import angular from 'angular'; import _ from 'lodash'; import config from 'app/core/config'; import appEvents from 'app/core/app_events'; import { DashboardModel } from '../state/DashboardModel'; // represents the transient view state // like fullscreen panel & edit export class DashboardViewStateSrv { state: any; panelScopes: any; $scope: any; dashboard: DashboardModel; fullscreenPanel: any; oldTimeRange: any; /** @ngInject */ constructor($scope, private $location, private $timeout) { const self = this; self.state = {}; self.panelScopes = []; self.$scope = $scope; self.dashboard = $scope.dashboard; $scope.onAppEvent('$routeUpdate', () => { // const urlState = self.getQueryStringState(); // if (self.needsSync(urlState)) { // self.update(urlState, true); // } }); $scope.onAppEvent('panel-change-view', (evt, payload) => { // self.update(payload); }); // this marks changes to location during this digest cycle as not to add history item // don't want url changes like adding orgId to add browser history // $location.replace(); // this.update(this.getQueryStringState()); } needsSync(urlState) { return _.isEqual(this.state, urlState) === false; } getQueryStringState() { const state = this.$location.search(); state.panelId = parseInt(state.panelId, 10) || null; state.fullscreen = state.fullscreen ? true : null; state.edit = state.edit === 'true' || state.edit === true || null; state.editview = state.editview || null; state.orgId = config.bootData.user.orgId; return state; } serializeToUrl() { const urlState = _.clone(this.state); urlState.fullscreen = this.state.fullscreen ? true : null; urlState.edit = this.state.edit ? true : null; return urlState; } update(state, fromRouteUpdated?) { // implement toggle logic if (state.toggle) { delete state.toggle; if (this.state.fullscreen && state.fullscreen) { if (this.state.edit === state.edit) { state.fullscreen = !state.fullscreen; } } } _.extend(this.state, state); if (!this.state.fullscreen) { this.state.fullscreen = null; this.state.edit = null; // clear panel id unless in solo mode if (!this.dashboard.meta.soloMode) { this.state.panelId = null; } } if ((this.state.fullscreen || this.dashboard.meta.soloMode) && this.state.panelId) { // Trying to render panel in fullscreen when it's in the collapsed row causes an issue. // So in this case expand collapsed row first. this.toggleCollapsedPanelRow(this.state.panelId); } // if no edit state cleanup tab parm if (!this.state.edit) { delete this.state.tab; } // do not update url params if we are here // from routeUpdated event if (fromRouteUpdated !== true) { this.$location.search(this.serializeToUrl()); } } toggleCollapsedPanelRow(panelId) { for (const panel of this.dashboard.panels) { if (panel.collapsed) { for (const rowPanel of panel.panels) { if (rowPanel.id === panelId) { this.dashboard.toggleRow(panel); return; } } } } } leaveFullscreen() { const panel = this.fullscreenPanel; this.dashboard.setViewMode(panel, false, false); delete this.fullscreenPanel; this.$timeout(() => { appEvents.emit('dash-scroll', { restore: true }); if (this.oldTimeRange !== this.dashboard.time) { this.dashboard.startRefresh(); } else { this.dashboard.render(); } }); } enterFullscreen(panel) { const isEditing = this.state.edit && this.dashboard.meta.canEdit; this.oldTimeRange = this.dashboard.time; this.fullscreenPanel = panel; // Firefox doesn't return scrollTop position properly if 'dash-scroll' is emitted after setViewMode() this.$scope.appEvent('dash-scroll', { animate: false, pos: 0 }); this.dashboard.setViewMode(panel, true, isEditing); } } /** @ngInject */ export function dashboardViewStateSrv($location, $timeout) { return { create: $scope => { return new DashboardViewStateSrv($scope, $location, $timeout); }, }; } angular.module('grafana.services').factory('dashboardViewStateSrv', dashboardViewStateSrv);