working on react data / query exectution

pull/13578/head
Torkel Ödegaard 7 years ago
parent 2e1d45a875
commit cd4619dad1
  1. 6
      public/app/core/components/grafana_app.ts
  2. 70
      public/app/features/dashboard/dashgrid/DataPanel.tsx
  3. 70
      public/app/features/dashboard/dashgrid/PanelChrome.tsx
  4. 30
      public/app/features/dashboard/time_srv.ts
  5. 1
      public/app/features/panel/panel_directive.ts
  6. 10
      public/app/features/plugins/datasource_srv.ts
  7. 5
      public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.ts
  8. 7
      public/app/plugins/datasource/elasticsearch/bucket_agg.ts
  9. 7
      public/app/plugins/datasource/elasticsearch/metric_agg.ts
  10. 4
      public/app/plugins/datasource/graphite/add_graphite_func.ts
  11. 4
      public/app/plugins/datasource/graphite/func_editor.ts
  12. 6
      public/app/plugins/datasource/stackdriver/query_aggregation_ctrl.ts
  13. 6
      public/app/plugins/datasource/stackdriver/query_filter_ctrl.ts
  14. 1
      public/app/plugins/panel/graph/graph.ts
  15. 6
      public/app/plugins/panel/graph/legend.ts
  16. 4
      public/app/plugins/panel/graph/series_overrides_ctrl.ts
  17. 4
      public/app/plugins/panel/graph2/module.tsx
  18. 8
      public/app/plugins/panel/heatmap/color_legend.ts
  19. 4
      public/app/plugins/panel/text2/module.tsx
  20. 5
      public/app/types/index.ts
  21. 6
      public/app/types/panel.ts
  22. 19
      public/app/types/queries.ts

@ -8,7 +8,8 @@ import appEvents from 'app/core/app_events';
import Drop from 'tether-drop'; import Drop from 'tether-drop';
import colors from 'app/core/utils/colors'; import colors from 'app/core/utils/colors';
import { BackendSrv, setBackendSrv } from 'app/core/services/backend_srv'; 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 { AngularLoader, setAngularLoader } from 'app/core/services/AngularLoader';
import { configureStore } from 'app/store/configureStore'; import { configureStore } from 'app/store/configureStore';
@ -23,12 +24,15 @@ export class GrafanaCtrl {
contextSrv, contextSrv,
bridgeSrv, bridgeSrv,
backendSrv: BackendSrv, backendSrv: BackendSrv,
timeSrv: TimeSrv,
datasourceSrv: DatasourceSrv, datasourceSrv: DatasourceSrv,
angularLoader: AngularLoader angularLoader: AngularLoader
) { ) {
// make angular loader service available to react components // make angular loader service available to react components
setAngularLoader(angularLoader); setAngularLoader(angularLoader);
setBackendSrv(backendSrv); setBackendSrv(backendSrv);
setDatasourceSrv(datasourceSrv);
setTimeSrv(timeSrv);
configureStore(); configureStore();
$scope.init = () => { $scope.init = () => {

@ -1,5 +1,11 @@
// Library // 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 { interface RenderProps {
loading: LoadingState; loading: LoadingState;
@ -9,6 +15,11 @@ interface RenderProps {
export interface Props { export interface Props {
datasource: string | null; datasource: string | null;
queries: any[]; queries: any[];
panelId?: number;
dashboardId?: number;
isVisible?: boolean;
timeRange?: TimeRange;
refreshCounter: number;
children: (r: RenderProps) => JSX.Element; children: (r: RenderProps) => JSX.Element;
} }
@ -18,16 +29,13 @@ export interface State {
data: any; data: any;
} }
export enum LoadingState { export class DataPanel extends PureComponent<Props, State> {
NotStarted = 'NotStarted', static defaultProps = {
Loading = 'Loading', isVisible: true,
Done = 'Done', panelId: 1,
Error = 'Error', dashboardId: 1,
} };
export interface PanelProps extends RenderProps {}
export class DataPanel extends Component<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
@ -44,20 +52,50 @@ export class DataPanel extends Component<Props, State> {
} }
issueQueries = async () => { 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 }); this.setState({ loading: LoadingState.Loading });
await new Promise(resolve => { try {
setTimeout(() => { const dataSourceSrv = getDatasourceSrv();
this.setState({ loading: LoadingState.Done, data: [{ value: 10 }], isFirstLoad: false }); const ds = await dataSourceSrv.get(datasource);
}, 500);
}); 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() { render() {
const { data, loading, isFirstLoad } = this.state; const { data, loading, isFirstLoad } = this.state;
console.log('data panel render'); console.log('data panel render');
if (isFirstLoad && loading === LoadingState.Loading) { if (isFirstLoad && (loading === LoadingState.Loading || loading === LoadingState.NotStarted)) {
return ( return (
<div className="loading"> <div className="loading">
<p>Loading</p> <p>Loading</p>

@ -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 { PanelModel } from '../panel_model';
import { DashboardModel } from '../dashboard_model'; import { DashboardModel } from '../dashboard_model';
import { PanelHeader } from './PanelHeader'; import { TimeRange, PanelProps } from 'app/types';
import { DataPanel, PanelProps } from './DataPanel';
export interface Props { export interface Props {
panel: PanelModel; panel: PanelModel;
@ -10,30 +19,59 @@ export interface Props {
component: ComponentClass<PanelProps>; component: ComponentClass<PanelProps>;
} }
interface State {} export interface State {
refreshCounter: number;
export class PanelChrome extends React.Component<Props, State> { timeRange?: TimeRange;
panelComponent: DataPanel; }
export class PanelChrome extends PureComponent<Props, State> {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = {
refreshCounter: 0,
};
} }
render() { componentDidMount() {
const { datasource, targets } = this.props.panel; this.props.dashboard.panelInitialized(this.props.panel);
const PanelComponent = this.props.component; 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();
// if (!PanelComponent) { this.setState({
// PanelComponent = dataPanels[type] = DataPanelWrapper(this.props.component); refreshCounter: this.state.refreshCounter + 1,
// } timeRange: timeRange,
});
};
console.log('PanelChrome render', PanelComponent); get isVisible() {
return this.props.dashboard.otherPanelInFullscreen(this.props.panel);
}
render() {
const { panel, dashboard } = this.props;
const { datasource, targets } = panel;
const { refreshCounter } = this.state;
const PanelComponent = this.props.component;
return ( return (
<div className="panel-container"> <div className="panel-container">
<PanelHeader panel={this.props.panel} dashboard={this.props.dashboard} /> <PanelHeader panel={panel} dashboard={dashboard} />
<div className="panel-content"> <div className="panel-content">
<DataPanel datasource={datasource} queries={targets}> <DataPanel
datasource={datasource}
queries={targets}
isVisible={this.isVisible}
refreshCounter={refreshCounter}
>
{({ loading, data }) => { {({ loading, data }) => {
return <PanelComponent loading={loading} data={data} />; return <PanelComponent loading={loading} data={data} />;
}} }}

@ -1,9 +1,15 @@
// Libraries
import moment from 'moment'; import moment from 'moment';
import _ from 'lodash'; import _ from 'lodash';
import coreModule from 'app/core/core_module';
// Utils
import kbn from 'app/core/utils/kbn'; import kbn from 'app/core/utils/kbn';
import coreModule from 'app/core/core_module';
import * as dateMath from 'app/core/utils/datemath'; import * as dateMath from 'app/core/utils/datemath';
// Types
import { TimeRange } from 'app/types';
export class TimeSrv { export class TimeSrv {
time: any; time: any;
refreshTimer: any; refreshTimer: any;
@ -200,7 +206,7 @@ export class TimeSrv {
return range; return range;
} }
timeRange() { timeRange(): TimeRange {
// make copies if they are moment (do not want to return out internal moment, because they are mutable!) // make copies if they are moment (do not want to return out internal moment, because they are mutable!)
const raw = { const raw = {
from: moment.isMoment(this.time.from) ? moment(this.time.from) : this.time.from, 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 timespan = range.to.valueOf() - range.from.valueOf();
const center = range.to.valueOf() - timespan / 2; const center = range.to.valueOf() - timespan / 2;
let to = center + timespan * factor / 2; const to = center + timespan * factor / 2;
let from = center - timespan * factor / 2; const from = center - timespan * factor / 2;
if (to > Date.now() && range.to <= Date.now()) {
const offset = to - Date.now();
from = from - offset;
to = Date.now();
}
this.setTime({ from: moment.utc(from), to: moment.utc(to) }); 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); coreModule.service('timeSrv', TimeSrv);

@ -145,7 +145,6 @@ module.directive('grafanaPanel', ($rootScope, $document, $timeout) => {
ctrl.calculatePanelHeight(); ctrl.calculatePanelHeight();
ctrl.events.on('render', () => { ctrl.events.on('render', () => {
console.log('panel_directive: render', ctrl.panel.id);
if (transparentLastState !== ctrl.panel.transparent) { if (transparentLastState !== ctrl.panel.transparent) {
panelContainer.toggleClass('panel-transparent', ctrl.panel.transparent === true); panelContainer.toggleClass('panel-transparent', ctrl.panel.transparent === true);
transparentLastState = ctrl.panel.transparent; transparentLastState = ctrl.panel.transparent;

@ -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); coreModule.service('datasourceSrv', DatasourceSrv);
export default DatasourceSrv; export default DatasourceSrv;

@ -1,4 +1,5 @@
import angular from 'angular'; import angular from 'angular';
import coreModule from 'app/core/core_module';
import _ from 'lodash'; import _ from 'lodash';
export class CloudWatchQueryParameter { export class CloudWatchQueryParameter {
@ -239,5 +240,5 @@ export class CloudWatchQueryParameterCtrl {
} }
} }
angular.module('grafana.controllers').directive('cloudwatchQueryParameter', CloudWatchQueryParameter); coreModule.directive('cloudwatchQueryParameter', CloudWatchQueryParameter);
angular.module('grafana.controllers').controller('CloudWatchQueryParameterCtrl', CloudWatchQueryParameterCtrl); coreModule.controller('CloudWatchQueryParameterCtrl', CloudWatchQueryParameterCtrl);

@ -1,4 +1,4 @@
import angular from 'angular'; import coreModule from 'app/core/core_module';
import _ from 'lodash'; import _ from 'lodash';
import * as queryDef from './query_def'; import * as queryDef from './query_def';
@ -226,6 +226,5 @@ export class ElasticBucketAggCtrl {
} }
} }
const module = angular.module('grafana.directives'); coreModule.directive('elasticBucketAgg', elasticBucketAgg);
module.directive('elasticBucketAgg', elasticBucketAgg); coreModule.controller('ElasticBucketAggCtrl', ElasticBucketAggCtrl);
module.controller('ElasticBucketAggCtrl', ElasticBucketAggCtrl);

@ -1,4 +1,4 @@
import angular from 'angular'; import coreModule from 'app/core/core_module';
import _ from 'lodash'; import _ from 'lodash';
import * as queryDef from './query_def'; import * as queryDef from './query_def';
@ -203,6 +203,5 @@ export class ElasticMetricAggCtrl {
} }
} }
const module = angular.module('grafana.directives'); coreModule.directive('elasticMetricAgg', elasticMetricAgg);
module.directive('elasticMetricAgg', elasticMetricAgg); coreModule.controller('ElasticMetricAggCtrl', ElasticMetricAggCtrl);
module.controller('ElasticMetricAggCtrl', ElasticMetricAggCtrl);

@ -1,8 +1,8 @@
import angular from 'angular';
import _ from 'lodash'; import _ from 'lodash';
import $ from 'jquery'; import $ from 'jquery';
import rst2html from 'rst2html'; import rst2html from 'rst2html';
import Drop from 'tether-drop'; import Drop from 'tether-drop';
import coreModule from 'app/core/core_module';
/** @ngInject */ /** @ngInject */
export function graphiteAddFunc($compile) { 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) { function createFunctionDropDownMenu(funcDefs) {
const categories = {}; const categories = {};

@ -1,7 +1,7 @@
import angular from 'angular';
import _ from 'lodash'; import _ from 'lodash';
import $ from 'jquery'; import $ from 'jquery';
import rst2html from 'rst2html'; import rst2html from 'rst2html';
import coreModule from 'app/core/core_module';
/** @ngInject */ /** @ngInject */
export function graphiteFuncEditor($compile, templateSrv, popoverSrv) { 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);

@ -1,4 +1,4 @@
import angular from 'angular'; import coreModule from 'app/core/core_module';
import _ from 'lodash'; import _ from 'lodash';
import * as options from './constants'; import * as options from './constants';
import kbn from 'app/core/utils/kbn'; import kbn from 'app/core/utils/kbn';
@ -83,5 +83,5 @@ export class StackdriverAggregationCtrl {
} }
} }
angular.module('grafana.controllers').directive('stackdriverAggregation', StackdriverAggregation); coreModule.directive('stackdriverAggregation', StackdriverAggregation);
angular.module('grafana.controllers').controller('StackdriverAggregationCtrl', StackdriverAggregationCtrl); coreModule.controller('StackdriverAggregationCtrl', StackdriverAggregationCtrl);

@ -1,4 +1,4 @@
import angular from 'angular'; import coreModule from 'app/core/core_module';
import _ from 'lodash'; import _ from 'lodash';
import { FilterSegments, DefaultRemoveFilterValue } from './filter_segments'; import { FilterSegments, DefaultRemoveFilterValue } from './filter_segments';
import appEvents from 'app/core/app_events'; import appEvents from 'app/core/app_events';
@ -281,5 +281,5 @@ export class StackdriverFilterCtrl {
} }
} }
angular.module('grafana.controllers').directive('stackdriverFilter', StackdriverFilter); coreModule.directive('stackdriverFilter', StackdriverFilter);
angular.module('grafana.controllers').controller('StackdriverFilterCtrl', StackdriverFilterCtrl); coreModule.controller('StackdriverFilterCtrl', StackdriverFilterCtrl);

@ -80,7 +80,6 @@ class GraphElement {
this.annotations = this.ctrl.annotations || []; this.annotations = this.ctrl.annotations || [];
this.buildFlotPairs(this.data); this.buildFlotPairs(this.data);
const graphHeight = this.elem.height(); const graphHeight = this.elem.height();
console.log('graphHeight', graphHeight);
updateLegendValues(this.data, this.panel, graphHeight); updateLegendValues(this.data, this.panel, graphHeight);
this.ctrl.events.emit('render-legend'); this.ctrl.events.emit('render-legend');

@ -1,11 +1,9 @@
import angular from 'angular';
import _ from 'lodash'; import _ from 'lodash';
import $ from 'jquery'; import $ from 'jquery';
import baron from 'baron'; import baron from 'baron';
import coreModule from 'app/core/core_module';
const module = angular.module('grafana.directives'); coreModule.directive('graphLegend', (popoverSrv, $timeout) => {
module.directive('graphLegend', (popoverSrv, $timeout) => {
return { return {
link: (scope, elem) => { link: (scope, elem) => {
let firstRender = true; let firstRender = true;

@ -1,5 +1,5 @@
import _ from 'lodash'; import _ from 'lodash';
import angular from 'angular'; import coreModule from 'app/core/core_module';
/** @ngInject */ /** @ngInject */
export function SeriesOverridesCtrl($scope, $element, popoverSrv) { export function SeriesOverridesCtrl($scope, $element, popoverSrv) {
@ -156,4 +156,4 @@ export function SeriesOverridesCtrl($scope, $element, popoverSrv) {
$scope.updateCurrentOverrides(); $scope.updateCurrentOverrides();
} }
angular.module('grafana.controllers').controller('SeriesOverridesCtrl', SeriesOverridesCtrl); coreModule.controller('SeriesOverridesCtrl', SeriesOverridesCtrl);

@ -1,5 +1,5 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { PanelProps } from 'app/features/dashboard/dashgrid/DataPanel'; import { PanelProps } from 'app/types';
interface Options { interface Options {
showBars: boolean; showBars: boolean;
@ -22,6 +22,8 @@ export class Graph2 extends PureComponent<Props> {
value = data[0].value; value = data[0].value;
} }
console.log('graph2 render');
return <h2>Text Panel {value}</h2>; return <h2>Text Panel {value}</h2>;
} }
} }

@ -1,12 +1,10 @@
import angular from 'angular';
import _ from 'lodash'; import _ from 'lodash';
import $ from 'jquery'; import $ from 'jquery';
import * as d3 from 'd3'; import * as d3 from 'd3';
import { contextSrv } from 'app/core/core'; import { contextSrv } from 'app/core/core';
import { tickStep } from 'app/core/utils/ticks'; import { tickStep } from 'app/core/utils/ticks';
import { getColorScale, getOpacityScale } from './color_scale'; import { getColorScale, getOpacityScale } from './color_scale';
import coreModule from 'app/core/core_module';
const module = angular.module('grafana.directives');
const LEGEND_HEIGHT_PX = 6; const LEGEND_HEIGHT_PX = 6;
const LEGEND_WIDTH_PX = 100; const LEGEND_WIDTH_PX = 100;
@ -16,7 +14,7 @@ const LEGEND_VALUE_MARGIN = 0;
/** /**
* Color legend for heatmap editor. * Color legend for heatmap editor.
*/ */
module.directive('colorLegend', () => { coreModule.directive('colorLegend', () => {
return { return {
restrict: 'E', restrict: 'E',
template: '<div class="heatmap-color-legend"><svg width="16.5rem" height="24px"></svg></div>', template: '<div class="heatmap-color-legend"><svg width="16.5rem" height="24px"></svg></div>',
@ -52,7 +50,7 @@ module.directive('colorLegend', () => {
/** /**
* Heatmap legend with scale values. * Heatmap legend with scale values.
*/ */
module.directive('heatmapLegend', () => { coreModule.directive('heatmapLegend', () => {
return { return {
restrict: 'E', restrict: 'E',
template: `<div class="heatmap-color-legend"><svg width="${LEGEND_WIDTH_PX}px" height="${LEGEND_HEIGHT_PX}px"></svg></div>`, template: `<div class="heatmap-color-legend"><svg width="${LEGEND_WIDTH_PX}px" height="${LEGEND_HEIGHT_PX}px"></svg></div>`,

@ -1,5 +1,5 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { PanelProps } from 'app/features/dashboard/dashgrid/DataPanel'; import { PanelProps } from 'app/types';
export class Text2 extends PureComponent<PanelProps> { export class Text2 extends PureComponent<PanelProps> {
constructor(props) { constructor(props) {
@ -14,7 +14,7 @@ export class Text2 extends PureComponent<PanelProps> {
value = data[0].value; value = data[0].value;
} }
return <h2>Graph Panel! {value}</h2>; return <h2>Text Panel! {value}</h2>;
} }
} }

@ -9,6 +9,8 @@ import { ApiKey, ApiKeysState, NewApiKey } from './apiKeys';
import { Invitee, OrgUser, User, UsersState } from './user'; import { Invitee, OrgUser, User, UsersState } from './user';
import { DataSource, DataSourcesState } from './datasources'; import { DataSource, DataSourcesState } from './datasources';
import { PluginMeta, Plugin, PluginsState } from './plugins'; import { PluginMeta, Plugin, PluginsState } from './plugins';
import { TimeRange, LoadingState } from './queries';
import { PanelProps } from './panel';
export { export {
Team, Team,
@ -45,6 +47,9 @@ export {
OrgUser, OrgUser,
User, User,
UsersState, UsersState,
TimeRange,
LoadingState,
PanelProps,
}; };
export interface StoreState { export interface StoreState {

@ -0,0 +1,6 @@
import { LoadingState } from './queries';
export interface PanelProps {
data: any;
loading: LoadingState;
}

@ -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;
}
Loading…
Cancel
Save