diff --git a/public/app/core/components/grafana_app.ts b/public/app/core/components/grafana_app.ts index a244a5393d1..d6291c94a6f 100644 --- a/public/app/core/components/grafana_app.ts +++ b/public/app/core/components/grafana_app.ts @@ -8,7 +8,8 @@ import appEvents from 'app/core/app_events'; import Drop from 'tether-drop'; import colors from 'app/core/utils/colors'; import { BackendSrv, setBackendSrv } from 'app/core/services/backend_srv'; -import { DatasourceSrv } from 'app/features/plugins/datasource_srv'; +import { TimeSrv, setTimeSrv } from 'app/features/dashboard/time_srv'; +import { DatasourceSrv, setDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { AngularLoader, setAngularLoader } from 'app/core/services/AngularLoader'; import { configureStore } from 'app/store/configureStore'; @@ -23,12 +24,15 @@ export class GrafanaCtrl { contextSrv, bridgeSrv, backendSrv: BackendSrv, + timeSrv: TimeSrv, datasourceSrv: DatasourceSrv, angularLoader: AngularLoader ) { // make angular loader service available to react components setAngularLoader(angularLoader); setBackendSrv(backendSrv); + setDatasourceSrv(datasourceSrv); + setTimeSrv(timeSrv); configureStore(); $scope.init = () => { diff --git a/public/app/features/dashboard/dashgrid/DataPanel.tsx b/public/app/features/dashboard/dashgrid/DataPanel.tsx index d19d6b10e2e..6b8aa8c4a91 100644 --- a/public/app/features/dashboard/dashgrid/DataPanel.tsx +++ b/public/app/features/dashboard/dashgrid/DataPanel.tsx @@ -1,5 +1,11 @@ // Library -import React, { Component } from 'react'; +import React, { PureComponent } from 'react'; + +// Services +import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; + +// Types +import { TimeRange, LoadingState } from 'app/types'; interface RenderProps { loading: LoadingState; @@ -9,6 +15,11 @@ interface RenderProps { export interface Props { datasource: string | null; queries: any[]; + panelId?: number; + dashboardId?: number; + isVisible?: boolean; + timeRange?: TimeRange; + refreshCounter: number; children: (r: RenderProps) => JSX.Element; } @@ -18,16 +29,13 @@ export interface State { data: any; } -export enum LoadingState { - NotStarted = 'NotStarted', - Loading = 'Loading', - Done = 'Done', - Error = 'Error', -} +export class DataPanel extends PureComponent { + static defaultProps = { + isVisible: true, + panelId: 1, + dashboardId: 1, + }; -export interface PanelProps extends RenderProps {} - -export class DataPanel extends Component { constructor(props: Props) { super(props); @@ -44,20 +52,50 @@ export class DataPanel extends Component { } issueQueries = async () => { + const { isVisible, queries, datasource, panelId, dashboardId, timeRange } = this.props; + + if (!isVisible) { + return; + } + + if (!queries.length) { + this.setState({ data: [], loading: LoadingState.Done }); + return; + } + this.setState({ loading: LoadingState.Loading }); - await new Promise(resolve => { - setTimeout(() => { - this.setState({ loading: LoadingState.Done, data: [{ value: 10 }], isFirstLoad: false }); - }, 500); - }); + try { + const dataSourceSrv = getDatasourceSrv(); + const ds = await dataSourceSrv.get(datasource); + + const queryOptions = { + timezone: 'browser', + panelId: panelId, + dashboardId: dashboardId, + range: timeRange, + rangeRaw: timeRange.raw, + interval: '1s', + intervalMs: 1000, + targets: queries, + maxDataPoints: 500, + scopedVars: {}, + cacheTimeout: null, + }; + + const resp = await ds.query(queryOptions); + console.log(resp); + } catch (err) { + console.log('Loading error', err); + this.setState({ loading: LoadingState.Error }); + } }; render() { const { data, loading, isFirstLoad } = this.state; console.log('data panel render'); - if (isFirstLoad && loading === LoadingState.Loading) { + if (isFirstLoad && (loading === LoadingState.Loading || loading === LoadingState.NotStarted)) { return (

Loading

diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.tsx index a3e4b4eedc8..29797664cd9 100644 --- a/public/app/features/dashboard/dashgrid/PanelChrome.tsx +++ b/public/app/features/dashboard/dashgrid/PanelChrome.tsx @@ -1,8 +1,17 @@ -import React, { ComponentClass } from 'react'; +// Libraries +import React, { ComponentClass, PureComponent } from 'react'; + +// Services +import { getTimeSrv } from '../time_srv'; + +// Components +import { PanelHeader } from './PanelHeader'; +import { DataPanel } from './DataPanel'; + +// Types import { PanelModel } from '../panel_model'; import { DashboardModel } from '../dashboard_model'; -import { PanelHeader } from './PanelHeader'; -import { DataPanel, PanelProps } from './DataPanel'; +import { TimeRange, PanelProps } from 'app/types'; export interface Props { panel: PanelModel; @@ -10,30 +19,59 @@ export interface Props { component: ComponentClass; } -interface State {} - -export class PanelChrome extends React.Component { - panelComponent: DataPanel; +export interface State { + refreshCounter: number; + timeRange?: TimeRange; +} +export class PanelChrome extends PureComponent { constructor(props) { super(props); + + this.state = { + refreshCounter: 0, + }; + } + + componentDidMount() { + this.props.dashboard.panelInitialized(this.props.panel); + this.props.panel.events.on('refresh', this.onRefresh); + } + + componentWillUnmount() { + this.props.panel.events.off('refresh', this.onRefresh); + } + + onRefresh = () => { + const timeSrv = getTimeSrv(); + const timeRange = timeSrv.timeRange(); + + this.setState({ + refreshCounter: this.state.refreshCounter + 1, + timeRange: timeRange, + }); + }; + + get isVisible() { + return this.props.dashboard.otherPanelInFullscreen(this.props.panel); } render() { - const { datasource, targets } = this.props.panel; + const { panel, dashboard } = this.props; + const { datasource, targets } = panel; + const { refreshCounter } = this.state; const PanelComponent = this.props.component; - // if (!PanelComponent) { - // PanelComponent = dataPanels[type] = DataPanelWrapper(this.props.component); - // } - - console.log('PanelChrome render', PanelComponent); - return (
- +
- + {({ loading, data }) => { return ; }} diff --git a/public/app/features/dashboard/time_srv.ts b/public/app/features/dashboard/time_srv.ts index 89aa94ed336..06cadfa6530 100644 --- a/public/app/features/dashboard/time_srv.ts +++ b/public/app/features/dashboard/time_srv.ts @@ -1,9 +1,15 @@ +// Libraries import moment from 'moment'; import _ from 'lodash'; -import coreModule from 'app/core/core_module'; + +// Utils import kbn from 'app/core/utils/kbn'; +import coreModule from 'app/core/core_module'; import * as dateMath from 'app/core/utils/datemath'; +// Types +import { TimeRange } from 'app/types'; + export class TimeSrv { time: any; refreshTimer: any; @@ -200,7 +206,7 @@ export class TimeSrv { return range; } - timeRange() { + timeRange(): TimeRange { // make copies if they are moment (do not want to return out internal moment, because they are mutable!) const raw = { from: moment.isMoment(this.time.from) ? moment(this.time.from) : this.time.from, @@ -222,17 +228,21 @@ export class TimeSrv { const timespan = range.to.valueOf() - range.from.valueOf(); const center = range.to.valueOf() - timespan / 2; - let to = center + timespan * factor / 2; - let from = center - timespan * factor / 2; - - if (to > Date.now() && range.to <= Date.now()) { - const offset = to - Date.now(); - from = from - offset; - to = Date.now(); - } + const to = center + timespan * factor / 2; + const from = center - timespan * factor / 2; this.setTime({ from: moment.utc(from), to: moment.utc(to) }); } } +let singleton; + +export function setTimeSrv(srv: TimeSrv) { + singleton = srv; +} + +export function getTimeSrv(): TimeSrv { + return singleton; +} + coreModule.service('timeSrv', TimeSrv); diff --git a/public/app/features/panel/panel_directive.ts b/public/app/features/panel/panel_directive.ts index e4d70ff3cf9..d4554a2eed9 100644 --- a/public/app/features/panel/panel_directive.ts +++ b/public/app/features/panel/panel_directive.ts @@ -145,7 +145,6 @@ module.directive('grafanaPanel', ($rootScope, $document, $timeout) => { ctrl.calculatePanelHeight(); ctrl.events.on('render', () => { - console.log('panel_directive: render', ctrl.panel.id); if (transparentLastState !== ctrl.panel.transparent) { panelContainer.toggleClass('panel-transparent', ctrl.panel.transparent === true); transparentLastState = ctrl.panel.transparent; diff --git a/public/app/features/plugins/datasource_srv.ts b/public/app/features/plugins/datasource_srv.ts index 7ef82519668..22861eaeef8 100644 --- a/public/app/features/plugins/datasource_srv.ts +++ b/public/app/features/plugins/datasource_srv.ts @@ -162,5 +162,15 @@ export class DatasourceSrv { } } +let singleton: DatasourceSrv; + +export function setDatasourceSrv(srv: DatasourceSrv) { + singleton = srv; +} + +export function getDatasourceSrv(): DatasourceSrv { + return singleton; +} + coreModule.service('datasourceSrv', DatasourceSrv); export default DatasourceSrv; diff --git a/public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.ts b/public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.ts index 4f4b2961761..ba5a39688b3 100644 --- a/public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.ts +++ b/public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.ts @@ -1,4 +1,5 @@ import angular from 'angular'; +import coreModule from 'app/core/core_module'; import _ from 'lodash'; export class CloudWatchQueryParameter { @@ -239,5 +240,5 @@ export class CloudWatchQueryParameterCtrl { } } -angular.module('grafana.controllers').directive('cloudwatchQueryParameter', CloudWatchQueryParameter); -angular.module('grafana.controllers').controller('CloudWatchQueryParameterCtrl', CloudWatchQueryParameterCtrl); +coreModule.directive('cloudwatchQueryParameter', CloudWatchQueryParameter); +coreModule.controller('CloudWatchQueryParameterCtrl', CloudWatchQueryParameterCtrl); diff --git a/public/app/plugins/datasource/elasticsearch/bucket_agg.ts b/public/app/plugins/datasource/elasticsearch/bucket_agg.ts index 8963f2c3f4b..cacf86201fe 100644 --- a/public/app/plugins/datasource/elasticsearch/bucket_agg.ts +++ b/public/app/plugins/datasource/elasticsearch/bucket_agg.ts @@ -1,4 +1,4 @@ -import angular from 'angular'; +import coreModule from 'app/core/core_module'; import _ from 'lodash'; import * as queryDef from './query_def'; @@ -226,6 +226,5 @@ export class ElasticBucketAggCtrl { } } -const module = angular.module('grafana.directives'); -module.directive('elasticBucketAgg', elasticBucketAgg); -module.controller('ElasticBucketAggCtrl', ElasticBucketAggCtrl); +coreModule.directive('elasticBucketAgg', elasticBucketAgg); +coreModule.controller('ElasticBucketAggCtrl', ElasticBucketAggCtrl); diff --git a/public/app/plugins/datasource/elasticsearch/metric_agg.ts b/public/app/plugins/datasource/elasticsearch/metric_agg.ts index 623eed68914..1dd0d892360 100644 --- a/public/app/plugins/datasource/elasticsearch/metric_agg.ts +++ b/public/app/plugins/datasource/elasticsearch/metric_agg.ts @@ -1,4 +1,4 @@ -import angular from 'angular'; +import coreModule from 'app/core/core_module'; import _ from 'lodash'; import * as queryDef from './query_def'; @@ -203,6 +203,5 @@ export class ElasticMetricAggCtrl { } } -const module = angular.module('grafana.directives'); -module.directive('elasticMetricAgg', elasticMetricAgg); -module.controller('ElasticMetricAggCtrl', ElasticMetricAggCtrl); +coreModule.directive('elasticMetricAgg', elasticMetricAgg); +coreModule.controller('ElasticMetricAggCtrl', ElasticMetricAggCtrl); diff --git a/public/app/plugins/datasource/graphite/add_graphite_func.ts b/public/app/plugins/datasource/graphite/add_graphite_func.ts index a5c1dc49959..ea3dfe8ff5e 100644 --- a/public/app/plugins/datasource/graphite/add_graphite_func.ts +++ b/public/app/plugins/datasource/graphite/add_graphite_func.ts @@ -1,8 +1,8 @@ -import angular from 'angular'; import _ from 'lodash'; import $ from 'jquery'; import rst2html from 'rst2html'; import Drop from 'tether-drop'; +import coreModule from 'app/core/core_module'; /** @ngInject */ export function graphiteAddFunc($compile) { @@ -130,7 +130,7 @@ export function graphiteAddFunc($compile) { }; } -angular.module('grafana.directives').directive('graphiteAddFunc', graphiteAddFunc); +coreModule.directive('graphiteAddFunc', graphiteAddFunc); function createFunctionDropDownMenu(funcDefs) { const categories = {}; diff --git a/public/app/plugins/datasource/graphite/func_editor.ts b/public/app/plugins/datasource/graphite/func_editor.ts index 68cc6f1452e..9e19083a9c3 100644 --- a/public/app/plugins/datasource/graphite/func_editor.ts +++ b/public/app/plugins/datasource/graphite/func_editor.ts @@ -1,7 +1,7 @@ -import angular from 'angular'; import _ from 'lodash'; import $ from 'jquery'; import rst2html from 'rst2html'; +import coreModule from 'app/core/core_module'; /** @ngInject */ export function graphiteFuncEditor($compile, templateSrv, popoverSrv) { @@ -315,4 +315,4 @@ export function graphiteFuncEditor($compile, templateSrv, popoverSrv) { }; } -angular.module('grafana.directives').directive('graphiteFuncEditor', graphiteFuncEditor); +coreModule.directive('graphiteFuncEditor', graphiteFuncEditor); diff --git a/public/app/plugins/datasource/stackdriver/query_aggregation_ctrl.ts b/public/app/plugins/datasource/stackdriver/query_aggregation_ctrl.ts index 98a1258cb15..6cd6c805463 100644 --- a/public/app/plugins/datasource/stackdriver/query_aggregation_ctrl.ts +++ b/public/app/plugins/datasource/stackdriver/query_aggregation_ctrl.ts @@ -1,4 +1,4 @@ -import angular from 'angular'; +import coreModule from 'app/core/core_module'; import _ from 'lodash'; import * as options from './constants'; import kbn from 'app/core/utils/kbn'; @@ -83,5 +83,5 @@ export class StackdriverAggregationCtrl { } } -angular.module('grafana.controllers').directive('stackdriverAggregation', StackdriverAggregation); -angular.module('grafana.controllers').controller('StackdriverAggregationCtrl', StackdriverAggregationCtrl); +coreModule.directive('stackdriverAggregation', StackdriverAggregation); +coreModule.controller('StackdriverAggregationCtrl', StackdriverAggregationCtrl); diff --git a/public/app/plugins/datasource/stackdriver/query_filter_ctrl.ts b/public/app/plugins/datasource/stackdriver/query_filter_ctrl.ts index 786b2831e89..7af76720d23 100644 --- a/public/app/plugins/datasource/stackdriver/query_filter_ctrl.ts +++ b/public/app/plugins/datasource/stackdriver/query_filter_ctrl.ts @@ -1,4 +1,4 @@ -import angular from 'angular'; +import coreModule from 'app/core/core_module'; import _ from 'lodash'; import { FilterSegments, DefaultRemoveFilterValue } from './filter_segments'; import appEvents from 'app/core/app_events'; @@ -281,5 +281,5 @@ export class StackdriverFilterCtrl { } } -angular.module('grafana.controllers').directive('stackdriverFilter', StackdriverFilter); -angular.module('grafana.controllers').controller('StackdriverFilterCtrl', StackdriverFilterCtrl); +coreModule.directive('stackdriverFilter', StackdriverFilter); +coreModule.controller('StackdriverFilterCtrl', StackdriverFilterCtrl); diff --git a/public/app/plugins/panel/graph/graph.ts b/public/app/plugins/panel/graph/graph.ts index ec4b16fbc79..7a8e24539f7 100755 --- a/public/app/plugins/panel/graph/graph.ts +++ b/public/app/plugins/panel/graph/graph.ts @@ -80,7 +80,6 @@ class GraphElement { this.annotations = this.ctrl.annotations || []; this.buildFlotPairs(this.data); const graphHeight = this.elem.height(); - console.log('graphHeight', graphHeight); updateLegendValues(this.data, this.panel, graphHeight); this.ctrl.events.emit('render-legend'); diff --git a/public/app/plugins/panel/graph/legend.ts b/public/app/plugins/panel/graph/legend.ts index cf317389941..7b01c46c4d3 100644 --- a/public/app/plugins/panel/graph/legend.ts +++ b/public/app/plugins/panel/graph/legend.ts @@ -1,11 +1,9 @@ -import angular from 'angular'; import _ from 'lodash'; import $ from 'jquery'; import baron from 'baron'; +import coreModule from 'app/core/core_module'; -const module = angular.module('grafana.directives'); - -module.directive('graphLegend', (popoverSrv, $timeout) => { +coreModule.directive('graphLegend', (popoverSrv, $timeout) => { return { link: (scope, elem) => { let firstRender = true; diff --git a/public/app/plugins/panel/graph/series_overrides_ctrl.ts b/public/app/plugins/panel/graph/series_overrides_ctrl.ts index deb7bd8ba61..540d19fb47a 100644 --- a/public/app/plugins/panel/graph/series_overrides_ctrl.ts +++ b/public/app/plugins/panel/graph/series_overrides_ctrl.ts @@ -1,5 +1,5 @@ import _ from 'lodash'; -import angular from 'angular'; +import coreModule from 'app/core/core_module'; /** @ngInject */ export function SeriesOverridesCtrl($scope, $element, popoverSrv) { @@ -156,4 +156,4 @@ export function SeriesOverridesCtrl($scope, $element, popoverSrv) { $scope.updateCurrentOverrides(); } -angular.module('grafana.controllers').controller('SeriesOverridesCtrl', SeriesOverridesCtrl); +coreModule.controller('SeriesOverridesCtrl', SeriesOverridesCtrl); diff --git a/public/app/plugins/panel/graph2/module.tsx b/public/app/plugins/panel/graph2/module.tsx index 79bf1890bae..c5245137211 100644 --- a/public/app/plugins/panel/graph2/module.tsx +++ b/public/app/plugins/panel/graph2/module.tsx @@ -1,5 +1,5 @@ import React, { PureComponent } from 'react'; -import { PanelProps } from 'app/features/dashboard/dashgrid/DataPanel'; +import { PanelProps } from 'app/types'; interface Options { showBars: boolean; @@ -22,6 +22,8 @@ export class Graph2 extends PureComponent { value = data[0].value; } + console.log('graph2 render'); + return

Text Panel {value}

; } } diff --git a/public/app/plugins/panel/heatmap/color_legend.ts b/public/app/plugins/panel/heatmap/color_legend.ts index 628186569dd..0e011e59439 100644 --- a/public/app/plugins/panel/heatmap/color_legend.ts +++ b/public/app/plugins/panel/heatmap/color_legend.ts @@ -1,12 +1,10 @@ -import angular from 'angular'; import _ from 'lodash'; import $ from 'jquery'; import * as d3 from 'd3'; import { contextSrv } from 'app/core/core'; import { tickStep } from 'app/core/utils/ticks'; import { getColorScale, getOpacityScale } from './color_scale'; - -const module = angular.module('grafana.directives'); +import coreModule from 'app/core/core_module'; const LEGEND_HEIGHT_PX = 6; const LEGEND_WIDTH_PX = 100; @@ -16,7 +14,7 @@ const LEGEND_VALUE_MARGIN = 0; /** * Color legend for heatmap editor. */ -module.directive('colorLegend', () => { +coreModule.directive('colorLegend', () => { return { restrict: 'E', template: '
', @@ -52,7 +50,7 @@ module.directive('colorLegend', () => { /** * Heatmap legend with scale values. */ -module.directive('heatmapLegend', () => { +coreModule.directive('heatmapLegend', () => { return { restrict: 'E', template: `
`, diff --git a/public/app/plugins/panel/text2/module.tsx b/public/app/plugins/panel/text2/module.tsx index df00b85176a..9fcd89b612c 100644 --- a/public/app/plugins/panel/text2/module.tsx +++ b/public/app/plugins/panel/text2/module.tsx @@ -1,5 +1,5 @@ import React, { PureComponent } from 'react'; -import { PanelProps } from 'app/features/dashboard/dashgrid/DataPanel'; +import { PanelProps } from 'app/types'; export class Text2 extends PureComponent { constructor(props) { @@ -14,7 +14,7 @@ export class Text2 extends PureComponent { value = data[0].value; } - return

Graph Panel! {value}

; + return

Text Panel! {value}

; } } diff --git a/public/app/types/index.ts b/public/app/types/index.ts index 26f15d582ac..9a1045f8c7c 100644 --- a/public/app/types/index.ts +++ b/public/app/types/index.ts @@ -9,6 +9,8 @@ import { ApiKey, ApiKeysState, NewApiKey } from './apiKeys'; import { Invitee, OrgUser, User, UsersState } from './user'; import { DataSource, DataSourcesState } from './datasources'; import { PluginMeta, Plugin, PluginsState } from './plugins'; +import { TimeRange, LoadingState } from './queries'; +import { PanelProps } from './panel'; export { Team, @@ -45,6 +47,9 @@ export { OrgUser, User, UsersState, + TimeRange, + LoadingState, + PanelProps, }; export interface StoreState { diff --git a/public/app/types/panel.ts b/public/app/types/panel.ts new file mode 100644 index 00000000000..4cb93e5728d --- /dev/null +++ b/public/app/types/panel.ts @@ -0,0 +1,6 @@ +import { LoadingState } from './queries'; + +export interface PanelProps { + data: any; + loading: LoadingState; +} diff --git a/public/app/types/queries.ts b/public/app/types/queries.ts new file mode 100644 index 00000000000..5c350efbb08 --- /dev/null +++ b/public/app/types/queries.ts @@ -0,0 +1,19 @@ +import { Moment } from 'moment'; + +export enum LoadingState { + NotStarted = 'NotStarted', + Loading = 'Loading', + Done = 'Done', + Error = 'Error', +} + +export interface RawTimeRange { + from: Moment | string; + to: Moment | string; +} + +export interface TimeRange { + from: Moment; + to: Moment; + raw: RawTimeRange; +}