diff --git a/ui/src/app/api/data-aggregator.js b/ui/src/app/api/data-aggregator.js index 31baff134e..76d3b1cccc 100644 --- a/ui/src/app/api/data-aggregator.js +++ b/ui/src/app/api/data-aggregator.js @@ -74,7 +74,7 @@ export default class DataAggregator { }, this.aggregationTimeout, false); } - onData(data, update, history) { + onData(data, update, history, apply) { if (!this.dataReceived || this.resetPending) { var updateIntervalScheduledTime = true; if (!this.dataReceived) { @@ -96,18 +96,18 @@ export default class DataAggregator { if (updateIntervalScheduledTime) { this.intervalScheduledTime = currentTime(); } - this.onInterval(history); + this.onInterval(history, apply); } else { updateAggregatedData(this.aggregationMap, this.aggregationType === this.types.aggregation.count.value, this.noAggregation, this.aggFunction, data.data, this.interval, this.startTs); if (history) { this.intervalScheduledTime = currentTime(); - this.onInterval(history); + this.onInterval(history, apply); } } } - onInterval(history) { + onInterval(history, apply) { var now = currentTime(); this.elapsed += now - this.intervalScheduledTime; this.intervalScheduledTime = now; @@ -127,7 +127,7 @@ export default class DataAggregator { this.data = toData(this.tsKeyNames, this.aggregationMap, this.startTs, this.endTs, this.$filter, this.limit); } if (this.onDataCb) { - this.onDataCb(this.data, this.startTs, this.endTs); + this.onDataCb(this.data, this.startTs, this.endTs, apply); } var self = this; diff --git a/ui/src/app/api/datasource.service.js b/ui/src/app/api/datasource.service.js index 7d2c1be893..5458ada50e 100644 --- a/ui/src/app/api/datasource.service.js +++ b/ui/src/app/api/datasource.service.js @@ -197,7 +197,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic var datasourceKey = key + '_' + i; listener.dataUpdated(datasourceData[datasourceKey], listener.datasourceIndex, - dataKey.index); + dataKey.index, false); } } } else { @@ -205,7 +205,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic dataKey = dataKeys[key]; listener.dataUpdated(datasourceData[key], listener.datasourceIndex, - dataKey.index); + dataKey.index, false); } } } @@ -264,7 +264,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic type: types.dataKeyType.timeseries, onData: function (data) { if (data.data) { - onData(data.data, types.dataKeyType.timeseries); + onData(data.data, types.dataKeyType.timeseries, null, null, true); } }, onReconnected: function() {} @@ -287,9 +287,9 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic if (datasourceSubscription.type === types.widgetType.timeseries.value) { updateRealtimeSubscriptionCommand(subscriptionCommand, subsTw); - dataAggregator = createRealtimeDataAggregator(subsTw, tsKeyNames); + dataAggregator = createRealtimeDataAggregator(subsTw, tsKeyNames, types.dataKeyType.timeseries); subscriber.onData = function(data) { - dataAggregator.onData(data); + dataAggregator.onData(data, false, false, true); } subscriber.onReconnected = function() { var newSubsTw = null; @@ -308,7 +308,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic subscriber.onReconnected = function() {} subscriber.onData = function(data) { if (data.data) { - onData(data.data, types.dataKeyType.timeseries); + onData(data.data, types.dataKeyType.timeseries, null, null, true); } } } @@ -331,7 +331,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic type: types.dataKeyType.attribute, onData: function (data) { if (data.data) { - onData(data.data, types.dataKeyType.attribute); + onData(data.data, types.dataKeyType.attribute, null, null, true); } }, onReconnected: function() {} @@ -351,33 +351,24 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic tsKeyNames.push(dataKey.name+'_'+dataKey.index); } } - dataAggregator = new DataAggregator( - function (data, startTs, endTs) { - onData(data, types.dataKeyType.function, startTs, endTs); - }, - tsKeyNames, - subsTw.startTs, - subsTw.aggregation.limit, - subsTw.aggregation.type, - subsTw.aggregation.timeWindow, - subsTw.aggregation.interval, - types, - $timeout, - $filter - ); + dataAggregator = createRealtimeDataAggregator(subsTw, tsKeyNames, types.dataKeyType.function); } if (history) { - onTick(); + onTick(false); } else { - timer = $timeout(onTick, 0, false); + timer = $timeout( + function() {onTick(true)}, + 0, + false + ); } } } - function createRealtimeDataAggregator(subsTw, tsKeyNames) { + function createRealtimeDataAggregator(subsTw, tsKeyNames, dataKeyType) { return new DataAggregator( - function(data, startTs, endTs) { - onData(data, types.dataKeyType.timeseries, startTs, endTs); + function(data, startTs, endTs, apply) { + onData(data, dataKeyType, startTs, endTs, apply); }, tsKeyNames, subsTw.startTs, @@ -443,7 +434,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic return data; } - function generateLatest(dataKey) { + function generateLatest(dataKey, apply) { var prevSeries; var datasourceKeyData = datasourceData[dataKey.key].data; if (datasourceKeyData.length > 0) { @@ -461,11 +452,11 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic var listener = listeners[i]; listener.dataUpdated(datasourceData[dataKey.key], listener.datasourceIndex, - dataKey.index); + dataKey.index, apply); } } - function onTick() { + function onTick(apply) { var key; if (datasourceSubscription.type === types.widgetType.timeseries.value) { var startTime; @@ -495,15 +486,15 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic generatedData.data[dataKey.name+'_'+dataKey.index] = data; } } - dataAggregator.onData(generatedData, true, history); + dataAggregator.onData(generatedData, true, history, apply); } else if (datasourceSubscription.type === types.widgetType.latest.value) { for (key in dataKeys) { - generateLatest(dataKeys[key]); + generateLatest(dataKeys[key], apply); } } if (!history) { - timer = $timeout(onTick, frequency / 2, false); + timer = $timeout(function() {onTick(true)}, frequency / 2, false); } } @@ -519,7 +510,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic } } - function onData(sourceData, type, startTs, endTs) { + function onData(sourceData, type, startTs, endTs, apply) { for (var keyName in sourceData) { var keyData = sourceData[keyName]; var key = keyName + '_' + type; @@ -572,7 +563,7 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic var listener = listeners[i2]; listener.dataUpdated(datasourceData[datasourceKey], listener.datasourceIndex, - dataKey.index); + dataKey.index, apply); } } } diff --git a/ui/src/app/api/time.service.js b/ui/src/app/api/time.service.js index a4bb571a59..14f4c637a9 100644 --- a/ui/src/app/api/time.service.js +++ b/ui/src/app/api/time.service.js @@ -206,9 +206,9 @@ function TimeService($translate, types) { function defaultTimewindow() { var currentTime = (new Date).getTime(); var timewindow = { - displayValue: "", - selectedTab: 0, - realtime: { + displayValue: "", + selectedTab: 0, + realtime: { interval: SECOND, timewindowMs: MINUTE // 1 min by default }, diff --git a/ui/src/app/components/dashboard.directive.js b/ui/src/app/components/dashboard.directive.js index 3889339a23..1141add7ec 100644 --- a/ui/src/app/components/dashboard.directive.js +++ b/ui/src/app/components/dashboard.directive.js @@ -52,6 +52,7 @@ function Dashboard() { bindToController: { widgets: '=', deviceAliasList: '=', + dashboardTimewindow: '=?', columns: '=', margins: '=', isEdit: '=', @@ -71,7 +72,8 @@ function Dashboard() { getStDiff: '&?', onInit: '&?', onInitFailed: '&?', - dashboardStyle: '=?' + dashboardStyle: '=?', + dashboardClass: '=?' }, controller: DashboardController, controllerAs: 'vm', @@ -80,7 +82,7 @@ function Dashboard() { } /*@ngInject*/ -function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $log, toast, types) { +function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, timeService, types) { var highlightedMode = false; var highlightedWidget = null; @@ -99,6 +101,10 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $ vm.isMobileDisabled = angular.isDefined(vm.isMobileDisabled) ? vm.isMobileDisabled : false; + if (!('dashboardTimewindow' in vm)) { + vm.dashboardTimewindow = timeService.defaultTimewindow(); + } + vm.dashboardLoading = true; vm.visibleRect = { top: 0, @@ -176,6 +182,21 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $ vm.widgetContextMenuItems = []; vm.widgetContextMenuEvent = null; + vm.dashboardTimewindowApi = { + onResetTimewindow: function() { + if (vm.originalDashboardTimewindow) { + vm.dashboardTimewindow = angular.copy(vm.originalDashboardTimewindow); + vm.originalDashboardTimewindow = null; + } + }, + onUpdateTimewindow: function(startTimeMs, endTimeMs) { + if (!vm.originalDashboardTimewindow) { + vm.originalDashboardTimewindow = angular.copy(vm.dashboardTimewindow); + } + vm.dashboardTimewindow = timeService.toHistoryTimewindow(vm.dashboardTimewindow, startTimeMs, endTimeMs); + } + }; + //$element[0].onmousemove=function(){ // widgetMouseMove(); // } @@ -656,7 +677,12 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $ } function hasTimewindow(widget) { - return widget.type === types.widgetType.timeseries.value; + if (widget.type === types.widgetType.timeseries.value) { + return angular.isDefined(widget.config.useDashboardTimewindow) ? + !widget.config.useDashboardTimewindow : false; + } else { + return false; + } } function adoptMaxRows() { @@ -673,6 +699,9 @@ function DashboardController($scope, $rootScope, $element, $timeout, $mdMedia, $ function dashboardLoaded() { $timeout(function () { + $scope.$watch('vm.dashboardTimewindow', function () { + $scope.$broadcast('dashboardTimewindowChanged', vm.dashboardTimewindow); + }, true); adoptMaxRows(); vm.dashboardLoading = false; $timeout(function () { diff --git a/ui/src/app/components/dashboard.scss b/ui/src/app/components/dashboard.scss index 4c4af47639..cf56c15c00 100644 --- a/ui/src/app/components/dashboard.scss +++ b/ui/src/app/components/dashboard.scss @@ -51,7 +51,7 @@ div.tb-widget { height: 32px; min-width: 32px; min-height: 32px; - md-icon { + md-icon, ng-md-icon { width: 20px; height: 20px; min-width: 20px; @@ -93,6 +93,7 @@ md-content.tb-dashboard-content { right: 0; bottom: 0; outline: none; + background: none; .gridster-item { @include transition(none); } diff --git a/ui/src/app/components/dashboard.tpl.html b/ui/src/app/components/dashboard.tpl.html index dc46e35472..114460d3c1 100644 --- a/ui/src/app/components/dashboard.tpl.html +++ b/ui/src/app/components/dashboard.tpl.html @@ -21,7 +21,7 @@ -
+
    @@ -30,6 +30,7 @@
    -
    +
    {{widget.config.title}} - +
    + class="md-icon-button"> {{ 'widget.edit' | translate }} - - edit - + {{ 'widget.export' | translate }} - - file_download - + {{ 'widget.remove' | translate }} - - close - +
    + locals="{ visibleRect: vm.visibleRect, + widget: widget, + deviceAliasList: vm.deviceAliasList, + isEdit: vm.isEdit, + stDiff: vm.stDiff, + dashboardTimewindow: vm.dashboardTimewindow, + dashboardTimewindowApi: vm.dashboardTimewindowApi }">
    diff --git a/ui/src/app/components/expand-fullscreen.directive.js b/ui/src/app/components/expand-fullscreen.directive.js index 16bd71392a..f74aa91795 100644 --- a/ui/src/app/components/expand-fullscreen.directive.js +++ b/ui/src/app/components/expand-fullscreen.directive.js @@ -101,11 +101,15 @@ function ExpandFullscreen($compile, $document) { if (attrs.expandButtonId) { expandButton = $('#' + attrs.expandButtonId, element)[0]; } + var buttonSize; + if (attrs.expandButtonSize) { + buttonSize = attrs.expandButtonSize; + } var html = '' + '{{(expanded ? \'fullscreen.exit\' : \'fullscreen.expand\') | translate}}' + '' + - '' + ''; diff --git a/ui/src/app/components/timewindow-button.tpl.html b/ui/src/app/components/timewindow-button.tpl.html index 11d838295b..cea776c978 100644 --- a/ui/src/app/components/timewindow-button.tpl.html +++ b/ui/src/app/components/timewindow-button.tpl.html @@ -15,7 +15,7 @@ limitations under the License. --> - - date_range + + {{model.displayValue}} \ No newline at end of file diff --git a/ui/src/app/components/timewindow.directive.js b/ui/src/app/components/timewindow.directive.js index 14fff62b47..580b21bae6 100644 --- a/ui/src/app/components/timewindow.directive.js +++ b/ui/src/app/components/timewindow.directive.js @@ -79,26 +79,38 @@ function Timewindow($compile, $templateCache, $filter, $mdPanel, $document, $mdM if (scope.asButton) { template = $templateCache.get(timewindowButtonTemplate); } else { + scope.direction = scope.direction || 'left'; template = $templateCache.get(timewindowTemplate); } element.html(template); scope.openEditMode = function (event) { + if (scope.disabled) { + return; + } var position; var isGtSm = $mdMedia('gt-sm'); if (isGtSm) { var panelHeight = 375; + var panelWidth = 417; var offset = element[0].getBoundingClientRect(); var bottomY = offset.bottom - $(window).scrollTop(); //eslint-disable-line + var leftX = offset.left - $(window).scrollLeft(); //eslint-disable-line var yPosition; + var xPosition; if (bottomY + panelHeight > $( window ).height()) { //eslint-disable-line yPosition = $mdPanel.yPosition.ABOVE; } else { yPosition = $mdPanel.yPosition.BELOW; } + if (leftX + panelWidth > $( window ).width()) { //eslint-disable-line + xPosition = $mdPanel.xPosition.ALIGN_END; + } else { + xPosition = $mdPanel.xPosition.ALIGN_START; + } position = $mdPanel.newPanelPosition() .relativeTo(element) - .addPanelPosition($mdPanel.xPosition.ALIGN_START, yPosition); + .addPanelPosition(xPosition, yPosition); } else { position = $mdPanel.newPanelPosition() .absolute() @@ -223,7 +235,8 @@ function Timewindow($compile, $templateCache, $filter, $mdPanel, $document, $mdM require: "^ngModel", scope: { asButton: '=asButton', - buttonColor: '=?' + direction: '=?', + disabled:'=ngDisabled' }, link: linker }; diff --git a/ui/src/app/components/timewindow.scss b/ui/src/app/components/timewindow.scss index 0c85d521e3..9ea7c345a2 100644 --- a/ui/src/app/components/timewindow.scss +++ b/ui/src/app/components/timewindow.scss @@ -57,3 +57,10 @@ } } } + +tb-timewindow { + span { + pointer-events: all; + cursor: pointer; + } +} diff --git a/ui/src/app/components/timewindow.tpl.html b/ui/src/app/components/timewindow.tpl.html index 0de81e2bad..2778975c1c 100644 --- a/ui/src/app/components/timewindow.tpl.html +++ b/ui/src/app/components/timewindow.tpl.html @@ -15,9 +15,23 @@ limitations under the License. --> -
    - {{model.displayValue}} - - date_range +
    + + + {{ 'timewindow.edit' | translate }} + + + + + + {{ 'timewindow.edit' | translate }} + + {{model.displayValue}} + + + + {{ 'timewindow.edit' | translate }} + +
    \ No newline at end of file diff --git a/ui/src/app/components/widget-config.directive.js b/ui/src/app/components/widget-config.directive.js index c2c5743611..639395a64a 100644 --- a/ui/src/app/components/widget-config.directive.js +++ b/ui/src/app/components/widget-config.directive.js @@ -98,6 +98,8 @@ function WidgetConfig($compile, $templateCache, $rootScope, $timeout, types, uti }, true); scope.mobileOrder = ngModelCtrl.$viewValue.mobileOrder; scope.mobileHeight = ngModelCtrl.$viewValue.mobileHeight; + scope.useDashboardTimewindow = angular.isDefined(ngModelCtrl.$viewValue.useDashboardTimewindow) ? + ngModelCtrl.$viewValue.useDashboardTimewindow : true; scope.timewindow = ngModelCtrl.$viewValue.timewindow; if (scope.widgetType !== types.widgetType.rpc.value && scope.widgetType !== types.widgetType.static.value) { if (scope.datasources) { @@ -174,7 +176,8 @@ function WidgetConfig($compile, $templateCache, $rootScope, $timeout, types, uti } }; - scope.$watch('title + showTitle + dropShadow + enableFullscreen + backgroundColor + color + padding + titleStyle + mobileOrder + mobileHeight + intervalSec', function () { + scope.$watch('title + showTitle + dropShadow + enableFullscreen + backgroundColor + color + ' + + 'padding + titleStyle + mobileOrder + mobileHeight + useDashboardTimewindow', function () { if (ngModelCtrl.$viewValue) { var value = ngModelCtrl.$viewValue; value.title = scope.title; @@ -191,7 +194,7 @@ function WidgetConfig($compile, $templateCache, $rootScope, $timeout, types, uti } value.mobileOrder = angular.isNumber(scope.mobileOrder) ? scope.mobileOrder : undefined; value.mobileHeight = scope.mobileHeight; - value.intervalSec = scope.intervalSec; + value.useDashboardTimewindow = scope.useDashboardTimewindow; ngModelCtrl.$setViewValue(value); scope.updateValidity(); } diff --git a/ui/src/app/components/widget-config.tpl.html b/ui/src/app/components/widget-config.tpl.html index 23c64fcc5f..88bfc2d5fb 100644 --- a/ui/src/app/components/widget-config.tpl.html +++ b/ui/src/app/components/widget-config.tpl.html @@ -88,10 +88,15 @@
    -
    - widget-config.timewindow - +
    + {{ 'widget-config.use-dashboard-timewindow' | translate }} + +
    + widget-config.timewindow + +
    diff --git a/ui/src/app/components/widget.controller.js b/ui/src/app/components/widget.controller.js index a2056e0b36..c0617bc12a 100644 --- a/ui/src/app/components/widget.controller.js +++ b/ui/src/app/components/widget.controller.js @@ -20,7 +20,8 @@ import 'javascript-detect-element-resize/detect-element-resize'; /*@ngInject*/ export default function WidgetController($scope, $timeout, $window, $element, $q, $log, $injector, tbRaf, types, utils, timeService, - datasourceService, deviceService, visibleRect, isEdit, stDiff, widget, deviceAliasList, widgetType) { + datasourceService, deviceService, visibleRect, isEdit, stDiff, dashboardTimewindow, + dashboardTimewindowApi, widget, deviceAliasList, widgetType) { var vm = this; @@ -136,6 +137,24 @@ export default function WidgetController($scope, $timeout, $window, $element, $q $scope.widgetErrorData = utils.processWidgetException(e); } + function notifyDataLoaded(apply) { + if ($scope.loadingData === true) { + $scope.loadingData = false; + if (apply) { + $scope.$digest(); + } + } + } + + function notifyDataLoading(apply) { + if ($scope.loadingData === false) { + $scope.loadingData = true; + if (apply) { + $scope.$digest(); + } + } + } + function onInit() { if (!widgetContext.inited) { widgetContext.inited = true; @@ -274,7 +293,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q } function initialize() { - if (widget.type !== types.widgetType.rpc.value) { + if (widget.type !== types.widgetType.rpc.value && widget.type !== types.widgetType.static.value) { for (var i in widget.config.datasources) { var datasource = angular.copy(widget.config.datasources[i]); for (var a in datasource.dataKeys) { @@ -287,7 +306,7 @@ export default function WidgetController($scope, $timeout, $window, $element, $q widgetContext.data.push(datasourceData); } } - } else { + } else if (widget.type === types.widgetType.rpc.value) { if (widget.config.targetDeviceAliasIds && widget.config.targetDeviceAliasIds.length > 0) { targetDeviceAliasId = widget.config.targetDeviceAliasIds[0]; if (deviceAliasList[targetDeviceAliasId]) { @@ -354,14 +373,26 @@ export default function WidgetController($scope, $timeout, $window, $element, $q }); if (widget.type === types.widgetType.timeseries.value) { - $scope.$watch(function () { - return widget.config.timewindow; - }, function (newTimewindow, prevTimewindow) { - if (!angular.equals(newTimewindow, prevTimewindow)) { - unsubscribe(); - subscribe(); - } - }); + widgetContext.useDashboardTimewindow = angular.isDefined(widget.config.useDashboardTimewindow) + ? widget.config.useDashboardTimewindow : true; + if (widgetContext.useDashboardTimewindow) { + $scope.$on('dashboardTimewindowChanged', function (event, newDashboardTimewindow) { + if (!angular.equals(dashboardTimewindow, newDashboardTimewindow)) { + dashboardTimewindow = newDashboardTimewindow; + unsubscribe(); + subscribe(); + } + }); + } else { + $scope.$watch(function () { + return widgetContext.useDashboardTimewindow ? dashboardTimewindow : widget.config.timewindow; + }, function (newTimewindow, prevTimewindow) { + if (!angular.equals(newTimewindow, prevTimewindow)) { + unsubscribe(); + subscribe(); + } + }); + } } subscribe(); } @@ -474,20 +505,29 @@ export default function WidgetController($scope, $timeout, $window, $element, $q }*/ function onResetTimewindow() { - if (originalTimewindow) { - widget.config.timewindow = angular.copy(originalTimewindow); - originalTimewindow = null; + if (widgetContext.useDashboardTimewindow) { + dashboardTimewindowApi.onResetTimewindow(); + } else { + if (originalTimewindow) { + widget.config.timewindow = angular.copy(originalTimewindow); + originalTimewindow = null; + } } } function onUpdateTimewindow(startTimeMs, endTimeMs) { - if (!originalTimewindow) { - originalTimewindow = angular.copy(widget.config.timewindow); + if (widgetContext.useDashboardTimewindow) { + dashboardTimewindowApi.onUpdateTimewindow(startTimeMs, endTimeMs); + } else { + if (!originalTimewindow) { + originalTimewindow = angular.copy(widget.config.timewindow); + } + widget.config.timewindow = timeService.toHistoryTimewindow(widget.config.timewindow, startTimeMs, endTimeMs); } - widget.config.timewindow = timeService.toHistoryTimewindow(widget.config.timewindow, startTimeMs, endTimeMs); } - function dataUpdated(sourceData, datasourceIndex, dataKeyIndex) { + function dataUpdated(sourceData, datasourceIndex, dataKeyIndex, apply) { + notifyDataLoaded(apply); var update = true; if (widget.type === types.widgetType.latest.value) { var prevData = widgetContext.data[datasourceIndex + dataKeyIndex].data; @@ -547,16 +587,28 @@ export default function WidgetController($scope, $timeout, $window, $element, $q if (_subscriptionTimewindow) { subscriptionTimewindow = _subscriptionTimewindow; } else { - subscriptionTimewindow = timeService.createSubscriptionTimewindow(widget.config.timewindow, widgetContext.timeWindow.stDiff); + subscriptionTimewindow = + timeService.createSubscriptionTimewindow( + widgetContext.useDashboardTimewindow ? dashboardTimewindow : widget.config.timewindow, + widgetContext.timeWindow.stDiff); } updateTimewindow(); return subscriptionTimewindow; } + function hasTimewindow() { + if (widgetContext.useDashboardTimewindow) { + return angular.isDefined(dashboardTimewindow); + } else { + return angular.isDefined(widget.config.timewindow); + } + } + function subscribe() { - if (widget.type !== types.widgetType.rpc.value) { + if (widget.type !== types.widgetType.rpc.value && widget.type !== types.widgetType.static.value) { + notifyDataLoading(); if (widget.type === types.widgetType.timeseries.value && - angular.isDefined(widget.config.timewindow)) { + hasTimewindow()) { updateRealtimeSubscription(); if (subscriptionTimewindow.fixedWindow) { onDataUpdated(); @@ -579,8 +631,8 @@ export default function WidgetController($scope, $timeout, $window, $element, $q subscriptionTimewindow: subscriptionTimewindow, datasource: datasource, deviceId: deviceId, - dataUpdated: function (data, datasourceIndex, dataKeyIndex) { - dataUpdated(data, datasourceIndex, dataKeyIndex); + dataUpdated: function (data, datasourceIndex, dataKeyIndex, apply) { + dataUpdated(data, datasourceIndex, dataKeyIndex, apply); }, updateRealtimeSubscription: function() { this.subscriptionTimewindow = updateRealtimeSubscription(); @@ -601,6 +653,8 @@ export default function WidgetController($scope, $timeout, $window, $element, $q datasourceListeners.push(listener); datasourceService.subscribeToDatasource(listener); } + } else { + notifyDataLoaded(); } } diff --git a/ui/src/app/components/widget.directive.js b/ui/src/app/components/widget.directive.js index cd1d16bcf6..6d3a33073d 100644 --- a/ui/src/app/components/widget.directive.js +++ b/ui/src/app/components/widget.directive.js @@ -66,6 +66,8 @@ function Widget($controller, $compile, widgetService) { function loadFromWidgetInfo(widgetInfo) { + scope.loadingData = true; + elem.addClass("tb-widget"); var widgetNamespace = "widget-type-" + (widget.isSystemType ? 'sys-' : '') @@ -73,9 +75,12 @@ function Widget($controller, $compile, widgetService) { + widget.typeAlias; elem.addClass(widgetNamespace); - elem.html('
    ' + + elem.html('
    ' + 'Widget Error: {{ widgetErrorData.name + ": " + widgetErrorData.message}}' + '
    ' + + '
    ' + + '' + + '
    ' + '
    ' + widgetInfo.templateHtml + '
    '); $compile(elem.contents())(scope); diff --git a/ui/src/app/components/widget.scss b/ui/src/app/components/widget.scss index bad71b91fc..ddeddcc83b 100644 --- a/ui/src/app/components/widget.scss +++ b/ui/src/app/components/widget.scss @@ -23,4 +23,8 @@ color: red; } } + .tb-widget-loading { + background: rgba(255,255,255,0.15); + z-index: 3; + } } diff --git a/ui/src/app/dashboard/dashboard-settings.controller.js b/ui/src/app/dashboard/dashboard-settings.controller.js index 91885d3889..aac6da3dd0 100644 --- a/ui/src/app/dashboard/dashboard-settings.controller.js +++ b/ui/src/app/dashboard/dashboard-settings.controller.js @@ -32,6 +32,7 @@ export default function DashboardSettingsController($scope, $mdDialog, gridSetti } vm.gridSettings.backgroundColor = vm.gridSettings.backgroundColor || 'rgba(0,0,0,0)'; + vm.gridSettings.titleColor = vm.gridSettings.titleColor || 'rgba(0,0,0,0.870588)'; vm.gridSettings.columns = vm.gridSettings.columns || 24; vm.gridSettings.margins = vm.gridSettings.margins || [10, 10]; vm.hMargin = vm.gridSettings.margins[0]; diff --git a/ui/src/app/dashboard/dashboard-settings.tpl.html b/ui/src/app/dashboard/dashboard-settings.tpl.html index 9a1f5d4cd1..38cb530f27 100644 --- a/ui/src/app/dashboard/dashboard-settings.tpl.html +++ b/ui/src/app/dashboard/dashboard-settings.tpl.html @@ -31,10 +31,22 @@
    -
    +
    {{ 'dashboard.display-title' | translate }} +
    diff --git a/ui/src/app/dashboard/dashboard.controller.js b/ui/src/app/dashboard/dashboard.controller.js index c2a9cf316a..167b5ae594 100644 --- a/ui/src/app/dashboard/dashboard.controller.js +++ b/ui/src/app/dashboard/dashboard.controller.js @@ -23,7 +23,7 @@ import addWidgetTemplate from './add-widget.tpl.html'; /*@ngInject*/ export default function DashboardController(types, widgetService, userService, - dashboardService, itembuffer, importExport, hotkeys, $window, $rootScope, + dashboardService, timeService, itembuffer, importExport, hotkeys, $window, $rootScope, $scope, $state, $stateParams, $mdDialog, $timeout, $document, $q, $translate, $filter) { var user = userService.getCurrentUser(); @@ -47,6 +47,25 @@ export default function DashboardController(types, widgetService, userService, vm.widgets = []; vm.dashboardInitComplete = false; + vm.isToolbarOpened = false; + + Object.defineProperty(vm, 'toolbarOpened', { + get: function() { return vm.isToolbarOpened || vm.isEdit; }, + set: function() { } + }); + + vm.openToolbar = function() { + $timeout(function() { + vm.isToolbarOpened = true; + }); + } + + vm.closeToolbar = function() { + $timeout(function() { + vm.isToolbarOpened = false; + }); + } + vm.addWidget = addWidget; vm.addWidgetFromType = addWidgetFromType; vm.dashboardInited = dashboardInited; @@ -154,6 +173,9 @@ export default function DashboardController(types, widgetService, userService, if (vm.widgetEditMode) { $timeout(function () { + vm.dashboardConfiguration = { + timewindow: timeService.defaultTimewindow() + }; vm.widgets = [{ isSystemType: true, bundleAlias: 'customWidgetBundle', @@ -186,9 +208,12 @@ export default function DashboardController(types, widgetService, userService, if (angular.isUndefined(vm.dashboard.configuration.deviceAliases)) { vm.dashboard.configuration.deviceAliases = {}; } - //$timeout(function () { - vm.widgets = vm.dashboard.configuration.widgets; - //}); + + if (angular.isUndefined(vm.dashboard.configuration.timewindow)) { + vm.dashboard.configuration.timewindow = timeService.defaultTimewindow(); + } + vm.dashboardConfiguration = vm.dashboard.configuration; + vm.widgets = vm.dashboard.configuration.widgets; deferred.resolve(); }, function fail(e) { deferred.reject(e); @@ -607,6 +632,7 @@ export default function DashboardController(types, widgetService, userService, if (revert) { vm.dashboard = vm.prevDashboard; vm.widgets = vm.dashboard.configuration.widgets; + vm.dashboardConfiguration = vm.dashboard.configuration; } } } diff --git a/ui/src/app/dashboard/dashboard.scss b/ui/src/app/dashboard/dashboard.scss index 64aa4ec090..2d3b2fa5c0 100644 --- a/ui/src/app/dashboard/dashboard.scss +++ b/ui/src/app/dashboard/dashboard.scss @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +@import "~compass-sass-mixins/lib/compass"; @import '../../scss/constants'; section.tb-dashboard-title { @@ -53,3 +55,81 @@ tb-details-sidenav.tb-widget-details-sidenav { } } } + +/*********************** + * dashboard toolbar + ***********************/ + +section.tb-dashboard-toolbar { + position: absolute; + top: 0px; + left: -100%; + z-index: 3; + pointer-events: none; + &.tb-dashboard-toolbar-opened { + right: 0px; + @include transition(right .3s cubic-bezier(.55,0,.55,.2)); + } + &.tb-dashboard-toolbar-closed { + right: 18px; + @include transition(right .3s cubic-bezier(.55,0,.55,.2) .2s); + } + md-fab-toolbar { + &.md-is-open { + md-fab-trigger { + .md-button { + &.md-fab { + opacity: 1; + @include transition(opacity .3s cubic-bezier(.55,0,.55,.2)); + } + } + } + } + md-fab-trigger { + .md-button { + &.md-fab { + line-height: 36px; + width: 36px; + height: 36px; + margin: 4px 0 0 4px; + opacity: 0.5; + @include transition(opacity .3s cubic-bezier(.55,0,.55,.2) .2s); + md-icon { + margin: 0; + line-height: 18px; + height: 18px; + width: 18px; + min-height: 18px; + min-width: 18px; + } + } + } + } + .md-fab-toolbar-wrapper { + height: 40px; + md-toolbar { + min-height: 36px; + height: 36px; + md-fab-actions { + .close-action { + margin-right: -18px; + } + tb-timewindow { + font-size: 16px; + } + } + } + } + } +} + +.tb-dashboard-container { + &.tb-dashboard-toolbar-opened { + margin-top: 40px; + @include transition(margin-top .3s cubic-bezier(.55,0,.55,.2)); + } + &.tb-dashboard-toolbar-closed { + margin-top: 0px; + @include transition(margin-top .3s cubic-bezier(.55,0,.55,.2) .2s); + } +} diff --git a/ui/src/app/dashboard/dashboard.tpl.html b/ui/src/app/dashboard/dashboard.tpl.html index 298d365bb8..bf0b3ac1e5 100644 --- a/ui/src/app/dashboard/dashboard.tpl.html +++ b/ui/src/app/dashboard/dashboard.tpl.html @@ -15,235 +15,263 @@ limitations under the License. --> - - -
    - - dashboard.no-widgets - - - add - {{ 'dashboard.add-widget' | translate }} - -
    -
    -

    {{ vm.dashboard.title }}

    - - - - - - {{ 'device.aliases' | translate }} - - - {{ 'dashboard.settings' | translate }} - -
    -
    - - -
    - - -
    -
    -
    - - -
    -
    - - -
    - {{ 'widgets-bundle.current' | translate }} - - -
    -
    -
    - - - - - - - - - - - - - - - - - - - widgets-bundle.empty - widget.select-widgets-bundle -
    -
    - -