mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
WIP: good progress on react query editor support
This commit is contained in:
parent
0260c779e8
commit
33feb26fb5
@ -3,18 +3,16 @@ import React, { PureComponent } from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
// Components
|
||||
import 'app/features/panel/metrics_tab';
|
||||
import { EditorTabBody, EditorToolbarView } from './EditorTabBody';
|
||||
import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
|
||||
import { QueryInspector } from './QueryInspector';
|
||||
import { QueryOptions } from './QueryOptions';
|
||||
import { AngularQueryComponentScope } from 'app/features/panel/metrics_tab';
|
||||
import { PanelOptionsGroup } from '@grafana/ui';
|
||||
import { QueryEditorRow } from './QueryEditorRow';
|
||||
|
||||
// Services
|
||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
import { BackendSrv, getBackendSrv } from 'app/core/services/backend_srv';
|
||||
import { AngularComponent, getAngularLoader } from 'app/core/services/AngularLoader';
|
||||
import config from 'app/core/config';
|
||||
|
||||
// Types
|
||||
@ -37,63 +35,22 @@ interface State {
|
||||
}
|
||||
|
||||
export class QueriesTab extends PureComponent<Props, State> {
|
||||
element: HTMLElement;
|
||||
component: AngularComponent;
|
||||
datasources: DataSourceSelectItem[] = getDatasourceSrv().getMetricSources();
|
||||
backendSrv: BackendSrv = getBackendSrv();
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isLoadingHelp: false,
|
||||
currentDS: this.findCurrentDataSource(),
|
||||
helpContent: null,
|
||||
isPickerOpen: false,
|
||||
isAddingMixed: false,
|
||||
};
|
||||
}
|
||||
state: State = {
|
||||
isLoadingHelp: false,
|
||||
currentDS: this.findCurrentDataSource(),
|
||||
helpContent: null,
|
||||
isPickerOpen: false,
|
||||
isAddingMixed: false,
|
||||
};
|
||||
|
||||
findCurrentDataSource(): DataSourceSelectItem {
|
||||
const { panel } = this.props;
|
||||
return this.datasources.find(datasource => datasource.value === panel.datasource) || this.datasources[0];
|
||||
}
|
||||
|
||||
getAngularQueryComponentScope(): AngularQueryComponentScope {
|
||||
const { panel, dashboard } = this.props;
|
||||
|
||||
return {
|
||||
panel: panel,
|
||||
dashboard: dashboard,
|
||||
refresh: () => panel.refresh(),
|
||||
render: () => panel.render,
|
||||
addQuery: this.onAddQuery,
|
||||
moveQuery: this.onMoveQuery,
|
||||
removeQuery: this.onRemoveQuery,
|
||||
events: panel.events,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (!this.element) {
|
||||
return;
|
||||
}
|
||||
|
||||
const loader = getAngularLoader();
|
||||
const template = '<metrics-tab />';
|
||||
const scopeProps = {
|
||||
ctrl: this.getAngularQueryComponentScope(),
|
||||
};
|
||||
|
||||
this.component = loader.load(this.element, scopeProps, template);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.component) {
|
||||
this.component.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
onChangeDataSource = datasource => {
|
||||
const { panel } = this.props;
|
||||
const { currentDS } = this.state;
|
||||
@ -147,7 +104,6 @@ export class QueriesTab extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
this.props.panel.addQuery();
|
||||
this.component.digest();
|
||||
this.forceUpdate();
|
||||
};
|
||||
|
||||
@ -190,7 +146,6 @@ export class QueriesTab extends PureComponent<Props, State> {
|
||||
|
||||
onAddMixedQuery = datasource => {
|
||||
this.onAddQuery({ datasource: datasource.name });
|
||||
this.component.digest();
|
||||
this.setState({ isAddingMixed: false });
|
||||
};
|
||||
|
||||
@ -218,7 +173,17 @@ export class QueriesTab extends PureComponent<Props, State> {
|
||||
<>
|
||||
<PanelOptionsGroup>
|
||||
<div className="query-editor-rows">
|
||||
<div ref={element => (this.element = element)} />
|
||||
{panel.targets.map((query, index) => (
|
||||
<QueryEditorRow
|
||||
datasourceName={query.datasource || panel.datasource}
|
||||
key={query.refId}
|
||||
panel={panel}
|
||||
query={query}
|
||||
onRemoveQuery={this.onRemoveQuery}
|
||||
onAddQuery={this.onAddQuery}
|
||||
onMoveQuery={this.onMoveQuery}
|
||||
/>
|
||||
))}
|
||||
|
||||
<div className="gf-form-query">
|
||||
<div className="gf-form gf-form-query-letter-cell">
|
||||
|
@ -2,29 +2,121 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
// Utils & Services
|
||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
import { AngularComponent, getAngularLoader } from 'app/core/services/AngularLoader';
|
||||
import { Emitter } from 'app/core/utils/emitter';
|
||||
|
||||
// Types
|
||||
import { PanelModel } from '../panel_model';
|
||||
import { DashboardModel } from '../dashboard_model';
|
||||
import { DataQuery, DataSourceApi } from 'app/types/series';
|
||||
|
||||
interface Props {
|
||||
panel: PanelModel;
|
||||
dashboard: DashboardModel;
|
||||
query: DataQuery;
|
||||
onAddQuery: (query?: DataQuery) => void;
|
||||
onRemoveQuery: (query: DataQuery) => void;
|
||||
onMoveQuery: (query: DataQuery, direction: number) => void;
|
||||
datasourceName: string | null;
|
||||
}
|
||||
|
||||
interface State {
|
||||
datasource: DataSourceApi | null;
|
||||
}
|
||||
|
||||
export class VisualizationTab extends PureComponent<Props, State> {
|
||||
element: HTMLElement;
|
||||
angularQueryEditor: AngularComponent;
|
||||
export class QueryEditorRow extends PureComponent<Props, State> {
|
||||
element: HTMLElement | null = null;
|
||||
angularQueryEditor: AngularComponent | null = null;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
state: State = {
|
||||
datasource: null,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.loadDatasource();
|
||||
}
|
||||
|
||||
getAngularQueryComponentScope(): AngularQueryComponentScope {
|
||||
const { panel, onAddQuery, onMoveQuery, onRemoveQuery, query } = this.props;
|
||||
const { datasource } = this.state;
|
||||
|
||||
return {
|
||||
datasource: datasource,
|
||||
target: query,
|
||||
panel: panel,
|
||||
refresh: () => panel.refresh(),
|
||||
render: () => panel.render,
|
||||
addQuery: onAddQuery,
|
||||
moveQuery: onMoveQuery,
|
||||
removeQuery: onRemoveQuery,
|
||||
events: panel.events,
|
||||
};
|
||||
}
|
||||
|
||||
async loadDatasource() {
|
||||
const { query, panel } = this.props;
|
||||
const dataSourceSrv = getDatasourceSrv();
|
||||
const datasource = await dataSourceSrv.get(query.datasource || panel.datasource);
|
||||
|
||||
this.setState({ datasource });
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const { datasource } = this.state;
|
||||
|
||||
// check if we need to load another datasource
|
||||
if (datasource && datasource.name !== this.props.datasourceName) {
|
||||
if (this.angularQueryEditor) {
|
||||
this.angularQueryEditor.destroy();
|
||||
this.angularQueryEditor = null;
|
||||
}
|
||||
this.loadDatasource();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.element || this.angularQueryEditor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const loader = getAngularLoader();
|
||||
const template = '<plugin-component type="query-ctrl" />';
|
||||
const scopeProps = { ctrl: this.getAngularQueryComponentScope() };
|
||||
|
||||
this.angularQueryEditor = loader.load(this.element, scopeProps, template);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.angularQueryEditor) {
|
||||
this.angularQueryEditor.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { datasource } = this.state;
|
||||
|
||||
if (!datasource) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (datasource.pluginExports.QueryCtrl) {
|
||||
return <div ref={element => (this.element = element)} />;
|
||||
} else if (datasource.pluginExports.QueryEditor) {
|
||||
const QueryEditor = datasource.pluginExports.QueryEditor;
|
||||
return <QueryEditor />;
|
||||
}
|
||||
|
||||
return <div>Data source plugin does not export any Query Editor component</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export interface AngularQueryComponentScope {
|
||||
target: DataQuery;
|
||||
panel: PanelModel;
|
||||
events: Emitter;
|
||||
refresh: () => void;
|
||||
render: () => void;
|
||||
removeQuery: (query: DataQuery) => void;
|
||||
addQuery: (query?: DataQuery) => void;
|
||||
moveQuery: (query: DataQuery, direction: number) => void;
|
||||
datasource: DataSourceApi;
|
||||
}
|
||||
|
||||
|
@ -1,31 +0,0 @@
|
||||
// Services & utils
|
||||
import coreModule from 'app/core/core_module';
|
||||
import { Emitter } from 'app/core/utils/emitter';
|
||||
|
||||
// Types
|
||||
import { DashboardModel } from '../dashboard/dashboard_model';
|
||||
import { PanelModel } from '../dashboard/panel_model';
|
||||
import { DataQuery } from 'app/types';
|
||||
|
||||
export interface AngularQueryComponentScope {
|
||||
panel: PanelModel;
|
||||
dashboard: DashboardModel;
|
||||
events: Emitter;
|
||||
refresh: () => void;
|
||||
render: () => void;
|
||||
removeQuery: (query: DataQuery) => void;
|
||||
addQuery: (query?: DataQuery) => void;
|
||||
moveQuery: (query: DataQuery, direction: number) => void;
|
||||
}
|
||||
|
||||
/** @ngInject */
|
||||
export function metricsTabDirective() {
|
||||
'use strict';
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: true,
|
||||
templateUrl: 'public/app/features/panel/partials/metrics_tab.html',
|
||||
};
|
||||
}
|
||||
|
||||
coreModule.directive('metricsTab', metricsTabDirective);
|
@ -1,24 +0,0 @@
|
||||
<div ng-repeat="target in ctrl.panel.targets" ng-class="{'gf-form-disabled': target.hide}">
|
||||
<rebuild-on-change property="ctrl.panel.datasource || target.datasource" show-null="true">
|
||||
<plugin-component type="query-ctrl">
|
||||
</plugin-component>
|
||||
</rebuild-on-change>
|
||||
</div>
|
||||
|
||||
<!-- <div class="gf-form-query"> -->
|
||||
<!-- <div class="gf-form gf-form-query-letter-cell"> -->
|
||||
<!-- <label class="gf-form-label"> -->
|
||||
<!-- <span class="gf-form-query-letter-cell-carret"> -->
|
||||
<!-- <i class="fa fa-caret-down"></i> -->
|
||||
<!-- </span> -->
|
||||
<!-- <span class="gf-form-query-letter-cell-letter">{{ctrl.nextRefId}}</span> -->
|
||||
<!-- </label> -->
|
||||
<!-- <button class="btn btn-secondary gf-form-btn" ng-click="ctrl.addQuery()" ng-hide="ctrl.datasourceInstance.meta.mixed"> -->
|
||||
<!-- Add Query -->
|
||||
<!-- </button> -->
|
||||
<!-- <div class="dropdown" ng-if="ctrl.datasourceInstance.meta.mixed"> -->
|
||||
<!-- <gf-form-dropdown model="ctrl.addQueryDropdown" get-options="ctrl.getOptions(false)" on-change="ctrl.addMixedQuery($option)"> -->
|
||||
<!-- </gf-form-dropdown> -->
|
||||
<!-- </div> -->
|
||||
<!-- </div> -->
|
||||
<!-- </div> -->
|
@ -105,23 +105,17 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $
|
||||
switch (attrs.type) {
|
||||
// QueryCtrl
|
||||
case 'query-ctrl': {
|
||||
const datasource = scope.target.datasource || scope.ctrl.panel.datasource;
|
||||
return datasourceSrv.get(datasource).then(ds => {
|
||||
scope.datasource = ds;
|
||||
|
||||
return importPluginModule(ds.meta.module).then(dsModule => {
|
||||
return {
|
||||
baseUrl: ds.meta.baseUrl,
|
||||
name: 'query-ctrl-' + ds.meta.id,
|
||||
bindings: { target: '=', panelCtrl: '=', datasource: '=' },
|
||||
attrs: {
|
||||
target: 'target',
|
||||
'panel-ctrl': 'ctrl',
|
||||
datasource: 'datasource',
|
||||
},
|
||||
Component: dsModule.QueryCtrl,
|
||||
};
|
||||
});
|
||||
const ds = scope.ctrl.datasource;
|
||||
return $q.when({
|
||||
baseUrl: ds.meta.baseUrl,
|
||||
name: 'query-ctrl-' + ds.meta.id,
|
||||
bindings: { target: '=', panelCtrl: '=', datasource: '=' },
|
||||
attrs: {
|
||||
target: 'ctrl.target',
|
||||
'panel-ctrl': 'ctrl',
|
||||
datasource: 'ctrl.datasource',
|
||||
},
|
||||
Component: ds.pluginExports.QueryCtrl,
|
||||
});
|
||||
}
|
||||
// Annotations
|
||||
|
@ -4,6 +4,7 @@ import { PanelProps, PanelOptionsProps } from '@grafana/ui';
|
||||
export interface PluginExports {
|
||||
Datasource?: any;
|
||||
QueryCtrl?: any;
|
||||
QueryEditor?: any;
|
||||
ConfigCtrl?: any;
|
||||
AnnotationsQueryCtrl?: any;
|
||||
VariableQueryEditor?: any;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { PluginMeta } from './plugins';
|
||||
import { PluginMeta, PluginExports } from './plugins';
|
||||
import { TimeSeries, TimeRange, RawTimeRange } from '@grafana/ui';
|
||||
|
||||
export interface DataQueryResponse {
|
||||
@ -25,6 +25,10 @@ export interface DataQueryOptions {
|
||||
}
|
||||
|
||||
export interface DataSourceApi {
|
||||
name: string;
|
||||
meta: PluginMeta;
|
||||
pluginExports: PluginExports;
|
||||
|
||||
/**
|
||||
* min interval range
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user