Merge pull request #14936 from grafana/plugin-types-refactor

Plugin types refactor
This commit is contained in:
Torkel Ödegaard
2019-01-18 08:21:29 +01:00
committed by GitHub
50 changed files with 508 additions and 391 deletions

View File

@@ -0,0 +1,71 @@
import { TimeRange, RawTimeRange } from './time';
import { TimeSeries } from './series';
import { PluginMeta } from './plugin';
export interface DataQueryResponse {
data: TimeSeries[];
}
export interface DataQuery {
refId: string;
[key: string]: any;
}
export interface DataQueryOptions {
timezone: string;
range: TimeRange;
rangeRaw: RawTimeRange;
targets: DataQuery[];
panelId: number;
dashboardId: number;
cacheTimeout?: string;
interval: string;
intervalMs: number;
maxDataPoints: number;
scopedVars: object;
}
export interface QueryFix {
type: string;
label: string;
action?: QueryFixAction;
}
export interface QueryFixAction {
type: string;
query?: string;
preventSubmit?: boolean;
}
export interface QueryHint {
type: string;
label: string;
fix?: QueryFix;
}
export interface DataSourceSettings {
id: number;
orgId: number;
name: string;
typeLogoUrl: string;
type: string;
access: string;
url: string;
password: string;
user: string;
database: string;
basicAuth: boolean;
basicAuthPassword: string;
basicAuthUser: string;
isDefault: boolean;
jsonData: { authType: string; defaultRegion: string };
readOnly: boolean;
withCredentials: boolean;
}
export interface DataSourceSelectItem {
name: string;
value: string | null;
meta: PluginMeta;
sort: string;
}

View File

@@ -1,3 +1,5 @@
export * from './series';
export * from './time';
export * from './panel';
export * from './plugin';
export * from './datasource';

View File

@@ -0,0 +1,115 @@
import { ComponentClass } from 'react';
import { PanelProps, PanelOptionsProps } from './panel';
import { DataQueryOptions, DataQuery, DataQueryResponse, QueryHint } from './datasource';
export interface DataSourceApi {
name: string;
meta: PluginMeta;
pluginExports: PluginExports;
/**
* min interval range
*/
interval?: string;
/**
* Imports queries from a different datasource
*/
importQueries?(queries: DataQuery[], originMeta: PluginMeta): Promise<DataQuery[]>;
/**
* Initializes a datasource after instantiation
*/
init?: () => void;
/**
* Main metrics / data query action
*/
query(options: DataQueryOptions): Promise<DataQueryResponse>;
/**
* Test & verify datasource settings & connection details
*/
testDatasource(): Promise<any>;
/**
* Get hints for query improvements
*/
getQueryHints(query: DataQuery, results: any[], ...rest: any): QueryHint[];
}
export interface QueryEditorProps {
datasource: DataSourceApi;
query: DataQuery;
onExecuteQuery?: () => void;
onQueryChange?: (value: DataQuery) => void;
}
export interface PluginExports {
Datasource?: any;
QueryCtrl?: any;
QueryEditor?: ComponentClass<QueryEditorProps>;
ConfigCtrl?: any;
AnnotationsQueryCtrl?: any;
VariableQueryEditor?: any;
ExploreQueryField?: any;
ExploreStartPage?: any;
// Panel plugin
PanelCtrl?: any;
Panel?: ComponentClass<PanelProps>;
PanelOptions?: ComponentClass<PanelOptionsProps>;
PanelDefaults?: any;
}
export interface PluginMeta {
id: string;
name: string;
info: PluginMetaInfo;
includes: PluginInclude[];
// Datasource-specific
metrics?: boolean;
tables?: boolean;
logs?: boolean;
explore?: boolean;
annotations?: boolean;
mixed?: boolean;
hasQueryHelp?: boolean;
queryOptions?: PluginMetaQueryOptions;
}
interface PluginMetaQueryOptions {
cacheTimeout?: boolean;
maxDataPoints?: boolean;
minInterval?: boolean;
}
export interface PluginInclude {
type: string;
name: string;
path: string;
}
interface PluginMetaInfoLink {
name: string;
url: string;
}
export interface PluginMetaInfo {
author: {
name: string;
url?: string;
};
description: string;
links: PluginMetaInfoLink[];
logos: {
large: string;
small: string;
};
screenshots: any[];
updated: string;
version: string;
}

View File

@@ -6,7 +6,7 @@ import _ from 'lodash';
import { Select } from '@grafana/ui';
// Types
import { DataSourceSelectItem } from 'app/types';
import { DataSourceSelectItem } from '@grafana/ui/src/types';
export interface Props {
onChange: (ds: DataSourceSelectItem) => void;

View File

@@ -1,14 +1,18 @@
// Libraries
import _ from 'lodash';
import { colors, RawTimeRange, IntervalValues } from '@grafana/ui';
// Services & Utils
import * as dateMath from 'app/core/utils/datemath';
import { renderUrl } from 'app/core/utils/url';
import kbn from 'app/core/utils/kbn';
import store from 'app/core/store';
import { parse as parseDate } from 'app/core/utils/datemath';
import TimeSeries from 'app/core/time_series2';
import { colors } from '@grafana/ui';
import TableModel, { mergeTablesIntoModel } from 'app/core/table_model';
// Types
import { RawTimeRange, IntervalValues, DataQuery } from '@grafana/ui/src/types';
import TimeSeries from 'app/core/time_series2';
import {
ExploreUrlState,
HistoryItem,
@@ -17,7 +21,6 @@ import {
QueryIntervals,
QueryOptions,
} from 'app/types/explore';
import { DataQuery } from 'app/types/series';
export const DEFAULT_RANGE = {
from: 'now-6h',

View File

@@ -12,8 +12,7 @@ import { getDatasourceSrv, DatasourceSrv } from 'app/features/plugins/datasource
import kbn from 'app/core/utils/kbn';
// Types
import { DataQueryOptions, DataQueryResponse } from 'app/types';
import { TimeRange, TimeSeries, LoadingState } from '@grafana/ui';
import { TimeRange, TimeSeries, LoadingState, DataQueryResponse, DataQueryOptions } from '@grafana/ui/src/types';
const DEFAULT_PLUGIN_ERROR = 'Error in plugin';

View File

@@ -18,7 +18,7 @@ import config from 'app/core/config';
// Types
import { PanelModel } from '../panel_model';
import { DashboardModel } from '../dashboard_model';
import { DataQuery, DataSourceSelectItem } from 'app/types';
import { DataQuery, DataSourceSelectItem } from '@grafana/ui/src/types';
import { PluginHelp } from 'app/core/components/PluginHelp/PluginHelp';
interface Props {

View File

@@ -10,7 +10,7 @@ import { Emitter } from 'app/core/utils/emitter';
// Types
import { PanelModel } from '../panel_model';
import { DataQuery, DataSourceApi } from 'app/types/series';
import { DataQuery, DataSourceApi } from '@grafana/ui';
interface Props {
panel: PanelModel;
@@ -103,7 +103,17 @@ export class QueryEditorRow extends PureComponent<Props, State> {
this.setState({ isCollapsed: !this.state.isCollapsed });
};
onQueryChange = (query: DataQuery) => {
Object.assign(this.props.query, query);
this.onExecuteQuery();
};
onExecuteQuery = () => {
this.props.panel.refresh();
};
renderPluginEditor() {
const { query } = this.props;
const { datasource } = this.state;
if (datasource.pluginExports.QueryCtrl) {
@@ -112,7 +122,14 @@ export class QueryEditorRow extends PureComponent<Props, State> {
if (datasource.pluginExports.QueryEditor) {
const QueryEditor = datasource.pluginExports.QueryEditor;
return <QueryEditor />;
return (
<QueryEditor
query={query}
datasource={datasource}
onQueryChange={this.onQueryChange}
onExecuteQuery={this.onExecuteQuery}
/>
);
}
return <div>Data source plugin does not export any Query Editor component</div>;

View File

@@ -14,7 +14,8 @@ import { FormLabel } from '@grafana/ui';
// Types
import { PanelModel } from '../panel_model';
import { ValidationEvents, DataSourceSelectItem } from 'app/types';
import { DataSourceSelectItem } from '@grafana/ui/src/types';
import { ValidationEvents } from 'app/types';
const timeRangeValidationEvents: ValidationEvents = {
[EventsWithValidation.onBlur]: [

View File

@@ -1,7 +1,10 @@
import { Emitter } from 'app/core/utils/emitter';
// Libraries
import _ from 'lodash';
// Types
import { Emitter } from 'app/core/utils/emitter';
import { PANEL_OPTIONS_KEY_PREFIX } from 'app/core/constants';
import { DataQuery } from 'app/types';
import { DataQuery } from '@grafana/ui/src/types';
export interface GridPos {
x: number;

View File

@@ -1,13 +1,14 @@
import React from 'react';
import { shallow } from 'enzyme';
import { DataSourceDashboards, Props } from './DataSourceDashboards';
import { DataSource, NavModel, PluginDashboard } from 'app/types';
import { DataSourceSettings } from '@grafana/ui/src/types';
import { NavModel, PluginDashboard } from 'app/types';
const setup = (propOverrides?: object) => {
const props: Props = {
navModel: {} as NavModel,
dashboards: [] as PluginDashboard[],
dataSource: {} as DataSource,
dataSource: {} as DataSourceSettings,
pageId: 1,
importDashboard: jest.fn(),
loadDataSource: jest.fn(),

View File

@@ -1,9 +1,13 @@
// Libraries
import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
// Components
import PageHeader from 'app/core/components/PageHeader/PageHeader';
import DashboardTable from './DashboardsTable';
import { DataSource, NavModel, PluginDashboard } from 'app/types';
// Actions & Selectors
import { getNavModel } from 'app/core/selectors/navModel';
import { getRouteParamsId } from 'app/core/selectors/location';
import { loadDataSource } from './state/actions';
@@ -11,10 +15,14 @@ import { loadPluginDashboards } from '../plugins/state/actions';
import { importDashboard, removeDashboard } from '../dashboard/state/actions';
import { getDataSource } from './state/selectors';
// Types
import { NavModel, PluginDashboard } from 'app/types';
import { DataSourceSettings } from '@grafana/ui/src/types';
export interface Props {
navModel: NavModel;
dashboards: PluginDashboard[];
dataSource: DataSource;
dataSource: DataSourceSettings;
pageId: number;
importDashboard: typeof importDashboard;
loadDataSource: typeof loadDataSource;

View File

@@ -1,11 +1,16 @@
// Libraries
import React, { PureComponent } from 'react';
import classNames from 'classnames';
// Components
import DataSourcesListItem from './DataSourcesListItem';
import { DataSource } from 'app/types';
// Types
import { DataSourceSettings } from '@grafana/ui/src/types';
import { LayoutMode, LayoutModes } from '../../core/components/LayoutSelector/LayoutSelector';
export interface Props {
dataSources: DataSource[];
dataSources: DataSourceSettings[];
layoutMode: LayoutMode;
}

View File

@@ -1,8 +1,8 @@
import React, { PureComponent } from 'react';
import { DataSource } from 'app/types';
import { DataSourceSettings } from '@grafana/ui/src/types';
export interface Props {
dataSource: DataSource;
dataSource: DataSourceSettings;
}
export class DataSourcesListItem extends PureComponent<Props> {

View File

@@ -1,13 +1,14 @@
import React from 'react';
import { shallow } from 'enzyme';
import { DataSourcesListPage, Props } from './DataSourcesListPage';
import { DataSource, NavModel } from 'app/types';
import { NavModel } from 'app/types';
import { DataSourceSettings } from '@grafana/ui/src/types';
import { LayoutModes } from '../../core/components/LayoutSelector/LayoutSelector';
import { getMockDataSources } from './__mocks__/dataSourcesMocks';
const setup = (propOverrides?: object) => {
const props: Props = {
dataSources: [] as DataSource[],
dataSources: [] as DataSourceSettings[],
layoutMode: LayoutModes.Grid,
loadDataSources: jest.fn(),
navModel: {

View File

@@ -1,12 +1,20 @@
// Libraries
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import { hot } from 'react-hot-loader';
// Components
import Page from 'app/core/components/Page/Page';
import OrgActionBar from 'app/core/components/OrgActionBar/OrgActionBar';
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
import DataSourcesList from './DataSourcesList';
import { DataSource, NavModel, StoreState } from 'app/types';
// Types
import { DataSourceSettings } from '@grafana/ui/src/types';
import { NavModel, StoreState } from 'app/types';
import { LayoutMode } from 'app/core/components/LayoutSelector/LayoutSelector';
// Actions
import { loadDataSources, setDataSourcesLayoutMode, setDataSourcesSearchQuery } from './state/actions';
import { getNavModel } from 'app/core/selectors/navModel';
@@ -19,7 +27,7 @@ import {
export interface Props {
navModel: NavModel;
dataSources: DataSource[];
dataSources: DataSourceSettings[];
dataSourcesCount: number;
layoutMode: LayoutMode;
searchQuery: string;

View File

@@ -1,6 +1,6 @@
import { DataSource } from 'app/types';
import { DataSourceSettings } from '@grafana/ui/src/types';
export const getMockDataSources = (amount: number): DataSource[] => {
export const getMockDataSources = (amount: number): DataSourceSettings[] => {
const dataSources = [];
for (let i = 0; i <= amount; i++) {
@@ -25,7 +25,7 @@ export const getMockDataSources = (amount: number): DataSource[] => {
return dataSources;
};
export const getMockDataSource = (): DataSource => {
export const getMockDataSource = (): DataSourceSettings => {
return {
access: '',
basicAuth: false,

View File

@@ -1,7 +1,8 @@
import React from 'react';
import { shallow } from 'enzyme';
import { DataSourceSettings, Props } from './DataSourceSettings';
import { DataSource, NavModel } from '../../../types';
import { DataSourceSettingsPage, Props } from './DataSourceSettingsPage';
import { NavModel } from 'app/types';
import { DataSourceSettings } from '@grafana/ui';
import { getMockDataSource } from '../__mocks__/dataSourcesMocks';
import { getMockPlugin } from '../../plugins/__mocks__/pluginMocks';
@@ -20,7 +21,7 @@ const setup = (propOverrides?: object) => {
Object.assign(props, propOverrides);
return shallow(<DataSourceSettings {...props} />);
return shallow(<DataSourceSettingsPage {...props} />);
};
describe('Render', () => {
@@ -32,7 +33,7 @@ describe('Render', () => {
it('should render loader', () => {
const wrapper = setup({
dataSource: {} as DataSource,
dataSource: {} as DataSourceSettings,
});
expect(wrapper).toMatchSnapshot();

View File

@@ -1,28 +1,34 @@
// Libraries
import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
// Components
import PageHeader from 'app/core/components/PageHeader/PageHeader';
import PageLoader from 'app/core/components/PageLoader/PageLoader';
import PluginSettings from './PluginSettings';
import BasicSettings from './BasicSettings';
import ButtonRow from './ButtonRow';
// Services & Utils
import appEvents from 'app/core/app_events';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
// Actions & selectors
import { getDataSource, getDataSourceMeta } from '../state/selectors';
import { deleteDataSource, loadDataSource, setDataSourceName, setIsDefault, updateDataSource } from '../state/actions';
import { getNavModel } from 'app/core/selectors/navModel';
import { getRouteParamsId } from 'app/core/selectors/location';
import { DataSource, NavModel, Plugin } from 'app/types/';
// Types
import { NavModel, Plugin } from 'app/types/';
import { DataSourceSettings } from '@grafana/ui/src/types/';
import { getDataSourceLoadingNav } from '../state/navModel';
export interface Props {
navModel: NavModel;
dataSource: DataSource;
dataSource: DataSourceSettings;
dataSourceMeta: Plugin;
pageId: number;
deleteDataSource: typeof deleteDataSource;
@@ -33,7 +39,7 @@ export interface Props {
}
interface State {
dataSource: DataSource;
dataSource: DataSourceSettings;
isTesting?: boolean;
testingMessage?: string;
testingStatus?: string;
@@ -44,12 +50,12 @@ enum DataSourceStates {
Beta = 'beta',
}
export class DataSourceSettings extends PureComponent<Props, State> {
export class DataSourceSettingsPage extends PureComponent<Props, State> {
constructor(props) {
super(props);
this.state = {
dataSource: {} as DataSource,
dataSource: {} as DataSourceSettings,
};
}
@@ -246,4 +252,4 @@ const mapDispatchToProps = {
setIsDefault,
};
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(DataSourceSettings));
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(DataSourceSettingsPage));

View File

@@ -1,20 +1,21 @@
import React, { PureComponent } from 'react';
import _ from 'lodash';
import { DataSource, Plugin } from 'app/types/';
import { Plugin } from 'app/types';
import { DataSourceSettings } from '@grafana/ui/src/types';
import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader';
export interface Props {
dataSource: DataSource;
dataSource: DataSourceSettings;
dataSourceMeta: Plugin;
onModelChange: (dataSource: DataSource) => void;
onModelChange: (dataSource: DataSourceSettings) => void;
}
export class PluginSettings extends PureComponent<Props> {
element: any;
component: AngularComponent;
scopeProps: {
ctrl: { datasourceMeta: Plugin; current: DataSource };
onModelChanged: (dataSource: DataSource) => void;
ctrl: { datasourceMeta: Plugin; current: DataSourceSettings };
onModelChanged: (dataSource: DataSourceSettings) => void;
};
constructor(props) {
@@ -51,7 +52,7 @@ export class PluginSettings extends PureComponent<Props> {
}
}
onModelChanged = (dataSource: DataSource) => {
onModelChanged = (dataSource: DataSourceSettings) => {
this.props.onModelChange(dataSource);
};

View File

@@ -6,7 +6,8 @@ import { LayoutMode } from 'app/core/components/LayoutSelector/LayoutSelector';
import { updateLocation, updateNavIndex, UpdateNavIndexAction } from 'app/core/actions';
import { UpdateLocationAction } from 'app/core/actions/location';
import { buildNavModel } from './navModel';
import { DataSource, Plugin, StoreState } from 'app/types';
import { DataSourceSettings } from '@grafana/ui/src/types';
import { Plugin, StoreState } from 'app/types';
export enum ActionTypes {
LoadDataSources = 'LOAD_DATA_SOURCES',
@@ -22,7 +23,7 @@ export enum ActionTypes {
interface LoadDataSourcesAction {
type: ActionTypes.LoadDataSources;
payload: DataSource[];
payload: DataSourceSettings[];
}
interface SetDataSourcesSearchQueryAction {
@@ -47,7 +48,7 @@ interface SetDataSourceTypeSearchQueryAction {
interface LoadDataSourceAction {
type: ActionTypes.LoadDataSource;
payload: DataSource;
payload: DataSourceSettings;
}
interface LoadDataSourceMetaAction {
@@ -65,12 +66,12 @@ interface SetIsDefaultAction {
payload: boolean;
}
const dataSourcesLoaded = (dataSources: DataSource[]): LoadDataSourcesAction => ({
const dataSourcesLoaded = (dataSources: DataSourceSettings[]): LoadDataSourcesAction => ({
type: ActionTypes.LoadDataSources,
payload: dataSources,
});
const dataSourceLoaded = (dataSource: DataSource): LoadDataSourceAction => ({
const dataSourceLoaded = (dataSource: DataSourceSettings): LoadDataSourceAction => ({
type: ActionTypes.LoadDataSource,
payload: dataSource,
});
@@ -171,7 +172,7 @@ export function loadDataSourceTypes(): ThunkResult<void> {
};
}
export function updateDataSource(dataSource: DataSource): ThunkResult<void> {
export function updateDataSource(dataSource: DataSourceSettings): ThunkResult<void> {
return async dispatch => {
await getBackendSrv().put(`/api/datasources/${dataSource.id}`, dataSource);
await updateFrontendSettings();

View File

@@ -1,7 +1,8 @@
import { DataSource, NavModel, NavModelItem, PluginMeta } from 'app/types';
import { NavModel, NavModelItem } from 'app/types';
import { PluginMeta, DataSourceSettings } from '@grafana/ui/src/types';
import config from 'app/core/config';
export function buildNavModel(dataSource: DataSource, pluginMeta: PluginMeta): NavModelItem {
export function buildNavModel(dataSource: DataSourceSettings, pluginMeta: PluginMeta): NavModelItem {
const navModel = {
img: pluginMeta.info.logos.large,
id: 'datasource-' + dataSource.id,

View File

@@ -1,10 +1,11 @@
import { DataSource, DataSourcesState, Plugin } from 'app/types';
import { DataSourcesState, Plugin } from 'app/types';
import { DataSourceSettings } from '@grafana/ui/src/types';
import { Action, ActionTypes } from './actions';
import { LayoutModes } from '../../../core/components/LayoutSelector/LayoutSelector';
import { LayoutModes } from 'app/core/components/LayoutSelector/LayoutSelector';
const initialState: DataSourcesState = {
dataSources: [] as DataSource[],
dataSource: {} as DataSource,
dataSources: [] as DataSourceSettings[],
dataSource: {} as DataSourceSettings,
layoutMode: LayoutModes.List,
searchQuery: '',
dataSourcesCount: 0,

View File

@@ -1,4 +1,4 @@
import { DataSource } from '../../../types';
import { DataSourceSettings } from '@grafana/ui/src/types';
export const getDataSources = state => {
const regex = new RegExp(state.searchQuery, 'i');
@@ -16,11 +16,11 @@ export const getDataSourceTypes = state => {
});
};
export const getDataSource = (state, dataSourceId): DataSource | null => {
export const getDataSource = (state, dataSourceId): DataSourceSettings | null => {
if (state.dataSource.id === parseInt(dataSourceId, 10)) {
return state.dataSource;
}
return {} as DataSource;
return {} as DataSourceSettings;
};
export const getDataSourceMeta = (state, type): Plugin => {

View File

@@ -1,19 +1,25 @@
// Libraries
import React from 'react';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
import _ from 'lodash';
import { AutoSizer } from 'react-virtualized';
import { RawTimeRange, TimeRange } from '@grafana/ui';
import { DataSourceSelectItem } from 'app/types/datasources';
import { ExploreItemState, ExploreUrlState, RangeScanner, ExploreId } from 'app/types/explore';
import { DataQuery } from 'app/types/series';
import { StoreState } from 'app/types';
// Services & Utils
import store from 'app/core/store';
import { LAST_USED_DATASOURCE_KEY, ensureQueries, DEFAULT_RANGE } from 'app/core/utils/explore';
import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
import { Emitter } from 'app/core/utils/emitter';
// Components
import { DataSourceSelectItem } from '@grafana/ui/src/types';
import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
import { Alert } from './Error';
import ErrorBoundary from './ErrorBoundary';
import GraphContainer from './GraphContainer';
import LogsContainer from './LogsContainer';
import QueryRows from './QueryRows';
import TableContainer from './TableContainer';
import TimePicker, { parseTime } from './TimePicker';
// Actions
import {
changeDatasource,
changeSize,
@@ -29,13 +35,12 @@ import {
splitOpen,
} from './state/actions';
import { Alert } from './Error';
import ErrorBoundary from './ErrorBoundary';
import GraphContainer from './GraphContainer';
import LogsContainer from './LogsContainer';
import QueryRows from './QueryRows';
import TableContainer from './TableContainer';
import TimePicker, { parseTime } from './TimePicker';
// Types
import { RawTimeRange, TimeRange, DataQuery } from '@grafana/ui';
import { ExploreItemState, ExploreUrlState, RangeScanner, ExploreId } from 'app/types/explore';
import { StoreState } from 'app/types';
import { LAST_USED_DATASOURCE_KEY, ensureQueries, DEFAULT_RANGE } from 'app/core/utils/explore';
import { Emitter } from 'app/core/utils/emitter';
interface ExploreProps {
StartPage?: any;

View File

@@ -1,10 +1,14 @@
// Libraries
import React, { PureComponent } from 'react';
// Services
import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader';
import { Emitter } from 'app/core/utils/emitter';
import { getIntervals } from 'app/core/utils/explore';
import { DataQuery } from 'app/types';
import { RawTimeRange } from '@grafana/ui';
import { getTimeSrv } from 'app/features/dashboard/time_srv';
// Types
import { Emitter } from 'app/core/utils/emitter';
import { RawTimeRange, DataQuery } from '@grafana/ui';
import 'app/features/plugins/plugin_loader';
interface QueryEditorProps {

View File

@@ -1,16 +1,14 @@
// Libraries
import React, { PureComponent } from 'react';
import _ from 'lodash';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
import { RawTimeRange } from '@grafana/ui';
import _ from 'lodash';
import { QueryTransaction, HistoryItem, QueryHint, ExploreItemState, ExploreId } from 'app/types/explore';
import { Emitter } from 'app/core/utils/emitter';
import { DataQuery, StoreState } from 'app/types';
// import DefaultQueryField from './QueryField';
// Components
import QueryEditor from './QueryEditor';
import QueryTransactionStatus from './QueryTransactionStatus';
// Actions
import {
addQueryRow,
changeQuery,
@@ -20,6 +18,12 @@ import {
runQueries,
} from './state/actions';
// Types
import { StoreState } from 'app/types';
import { RawTimeRange, DataQuery, QueryHint } from '@grafana/ui';
import { QueryTransaction, HistoryItem, ExploreItemState, ExploreId } from 'app/types/explore';
import { Emitter } from 'app/core/utils/emitter';
function getFirstHintFromTransactions(transactions: QueryTransaction[]): QueryHint {
const transaction = transactions.find(qt => qt.hints && qt.hints.length > 0);
if (transaction) {

View File

@@ -1,17 +1,21 @@
// Libraries
import React, { PureComponent } from 'react';
import { Emitter } from 'app/core/utils/emitter';
import { DataQuery } from 'app/types';
import { ExploreId } from 'app/types/explore';
// Components
import QueryRow from './QueryRow';
// Types
import { Emitter } from 'app/core/utils/emitter';
import { DataQuery } from '@grafana/ui/src/types';
import { ExploreId } from 'app/types/explore';
interface QueryRowsProps {
className?: string;
exploreEvents: Emitter;
exploreId: ExploreId;
initialQueries: DataQuery[];
}
export default class QueryRows extends PureComponent<QueryRowsProps> {
render() {
const { className = '', exploreEvents, exploreId, initialQueries } = this.props;

View File

@@ -1,6 +1,6 @@
import { RawTimeRange, TimeRange } from '@grafana/ui';
// Types
import { Emitter } from 'app/core/core';
import { RawTimeRange, TimeRange, DataQuery, DataSourceSelectItem } from '@grafana/ui/src/types';
import {
ExploreId,
ExploreItemState,
@@ -9,8 +9,6 @@ import {
ResultType,
QueryTransaction,
} from 'app/types/explore';
import { DataSourceSelectItem } from 'app/types/datasources';
import { DataQuery } from 'app/types';
export enum ActionTypes {
AddQueryRow = 'explore/ADD_QUERY_ROW',

View File

@@ -1,7 +1,9 @@
// Libraries
import _ from 'lodash';
import { ThunkAction } from 'redux-thunk';
import { RawTimeRange, TimeRange } from '@grafana/ui';
// Services & Utils
import store from 'app/core/store';
import {
LAST_USED_DATASOURCE_KEY,
clearQueryKeys,
@@ -14,10 +16,12 @@ import {
serializeStateToUrlParam,
} from 'app/core/utils/explore';
// Actions
import { updateLocation } from 'app/core/actions';
import store from 'app/core/store';
import { DataSourceSelectItem } from 'app/types/datasources';
import { DataQuery, StoreState } from 'app/types';
// Types
import { StoreState } from 'app/types';
import { DataQuery, DataSourceSelectItem, QueryHint } from '@grafana/ui/src/types';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import {
ExploreId,
@@ -26,11 +30,10 @@ import {
ResultType,
QueryOptions,
QueryTransaction,
QueryHint,
QueryHintGetter,
} from 'app/types/explore';
import { Emitter } from 'app/core/core';
import { Emitter } from 'app/core/core';
import { RawTimeRange, TimeRange } from '@grafana/ui';
import {
Action as ThunkableAction,
ActionTypes,
@@ -45,6 +48,7 @@ import {
ScanStopAction,
} from './actionTypes';
type ThunkResult<R> = ThunkAction<R, StoreState, undefined, ThunkableAction>;
/**
@@ -460,7 +464,7 @@ export function queryTransactionSuccess(
// Get query hints
let hints: QueryHint[];
if (datasourceInstance.getQueryHints as QueryHintGetter) {
if (datasourceInstance.getQueryHints) {
hints = datasourceInstance.getQueryHints(transaction.query, result);
}

View File

@@ -5,7 +5,7 @@ import {
ensureQueries,
} from 'app/core/utils/explore';
import { ExploreItemState, ExploreState, QueryTransaction } from 'app/types/explore';
import { DataQuery } from 'app/types/series';
import { DataQuery } from '@grafana/ui/src/types';
import { Action, ActionTypes } from './actionTypes';

View File

@@ -1,14 +1,16 @@
// Libraries
import _ from 'lodash';
import coreModule from 'app/core/core_module';
// Services & Utils
import config from 'app/core/config';
import { importPluginModule } from './plugin_loader';
import { DataSourceApi } from 'app/types/series';
import { DataSource, DataSourceSelectItem } from 'app/types';
// Types
import { DataSourceApi, DataSourceSelectItem } from '@grafana/ui/src/types';
export class DatasourceSrv {
datasources: { [name: string]: DataSource };
datasources: { [name: string]: DataSourceApi };
/** @ngInject */
constructor(private $q, private $injector, private $rootScope, private templateSrv) {
@@ -59,7 +61,7 @@ export class DatasourceSrv {
throw new Error('Plugin module is missing Datasource constructor');
}
const instance: DataSource = this.$injector.instantiate(plugin.Datasource, { instanceSettings: dsConfig });
const instance: DataSourceApi = this.$injector.instantiate(plugin.Datasource, { instanceSettings: dsConfig });
instance.meta = pluginDef;
instance.name = name;
instance.pluginExports = plugin;

View File

@@ -18,7 +18,7 @@ import config from 'app/core/config';
import TimeSeries from 'app/core/time_series2';
import TableModel from 'app/core/table_model';
import { coreModule, appEvents, contextSrv } from 'app/core/core';
import { PluginExports } from 'app/types/plugins';
import { PluginExports } from '@grafana/ui';
import * as datemath from 'app/core/utils/datemath';
import * as fileExport from 'app/core/utils/file_export';
import * as flatten from 'app/core/utils/flatten';

View File

@@ -1,8 +1,14 @@
// Libraries
import _ from 'lodash';
import { DataSource, PluginMeta, NavModel } from 'app/types';
// Utils & Services
import config from 'app/core/config';
export function buildNavModel(ds: DataSource, plugin: PluginMeta, currentPage: string): NavModel {
// Types
import { NavModel } from 'app/types';
import { PluginMeta, DataSourceSettings } from '@grafana/ui/src/types';
export function buildNavModel(ds: DataSourceSettings, plugin: PluginMeta, currentPage: string): NavModel {
let title = 'New';
const subTitle = `Type: ${plugin.name}`;

View File

@@ -3,6 +3,7 @@ import Cascader from 'rc-cascader';
import PluginPrism from 'slate-prism';
import Prism from 'prismjs';
import { DataQuery } from '@grafana/ui/src/types';
import { TypeaheadOutput } from 'app/types/explore';
// dom also includes Element polyfills
@@ -10,7 +11,6 @@ import { getNextCharacter, getPreviousCousin } from 'app/features/explore/utils/
import BracesPlugin from 'app/features/explore/slate-plugins/braces';
import RunnerPlugin from 'app/features/explore/slate-plugins/runner';
import QueryField, { TypeaheadInput, QueryFieldState } from 'app/features/explore/QueryField';
import { DataQuery } from 'app/types';
const PRISM_SYNTAX = 'promql';

View File

@@ -2,7 +2,7 @@ import _ from 'lodash';
import * as dateMath from 'app/core/utils/datemath';
import { LogsStream, LogsModel, makeSeriesForLogs } from 'app/core/logs_model';
import { PluginMeta, DataQuery } from 'app/types';
import { PluginMeta, DataQuery } from '@grafana/ui/src/types';
import { addLabelToSelector } from 'app/plugins/datasource/prometheus/add_label_to_query';
import LanguageProvider from './language_provider';

View File

@@ -11,7 +11,7 @@ import {
} from 'app/types/explore';
import { parseSelector, labelRegexp, selectorRegexp } from 'app/plugins/datasource/prometheus/language_utils';
import syntax from './syntax';
import { DataQuery } from 'app/types';
import { DataQuery } from '@grafana/ui/src/types';
const DEFAULT_KEYS = ['job', 'namespace'];
const EMPTY_SELECTOR = '{}';

View File

@@ -11,7 +11,7 @@ import { getNextCharacter, getPreviousCousin } from 'app/features/explore/utils/
import BracesPlugin from 'app/features/explore/slate-plugins/braces';
import RunnerPlugin from 'app/features/explore/slate-plugins/runner';
import QueryField, { TypeaheadInput, QueryFieldState } from 'app/features/explore/QueryField';
import { DataQuery } from 'app/types';
import { DataQuery } from '@grafana/ui/src/types';
const HISTOGRAM_GROUP = '__histograms__';
const METRIC_MARK = 'metric';

View File

@@ -11,7 +11,7 @@ import { BackendSrv } from 'app/core/services/backend_srv';
import addLabelToQuery from './add_label_to_query';
import { getQueryHints } from './query_hints';
import { expandRecordingRules } from './language_utils';
import { DataQuery } from 'app/types';
import { DataQuery } from '@grafana/ui/src/types';
import { ExploreUrlState } from 'app/types/explore';
export function alignRange(start, end, step) {

View File

@@ -1,6 +1,5 @@
import _ from 'lodash';
import { QueryHint } from 'app/types/explore';
import { QueryHint } from '@grafana/ui/src/types';
/**
* Number of time series results needed before starting to suggest sum aggregation hints

View File

@@ -0,0 +1,66 @@
// Libraries
import React, { PureComponent } from 'react';
import _ from 'lodash';
// Services & Utils
import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv';
// Components
import { FormLabel, Select, SelectOptionItem } from '@grafana/ui';
// Types
import { QueryEditorProps } from '@grafana/ui/src/types';
interface Scenario {
id: string;
name: string;
}
interface State {
scenarioList: Scenario[];
current: Scenario | null;
}
export class QueryEditor extends PureComponent<QueryEditorProps> {
backendSrv: BackendSrv = getBackendSrv();
state: State = {
scenarioList: [],
current: null,
};
async componentDidMount() {
const { query } = this.props;
query.scenarioId = query.scenarioId || 'random_walk';
const scenarioList = await this.backendSrv.get('/api/tsdb/testdata/scenarios');
const current = _.find(scenarioList, { id: query.scenarioId });
this.setState({ scenarioList: scenarioList, current: current });
}
onScenarioChange = (item: SelectOptionItem) => {
this.props.onQueryChange({
scenarioId: item.value,
...this.props.query
});
}
render() {
const { query } = this.props;
const options = this.state.scenarioList.map(item => ({ label: item.name, value: item.id }));
const current = options.find(item => item.value === query.scenarioId);
return (
<div className="gf-form-inline">
<div className="gf-form">
<FormLabel className="query-keyword" width={7}>
Scenario
</FormLabel>
<Select options={options} value={current} onChange={this.onScenarioChange} />
</div>
</div>
);
}
}

View File

@@ -1,5 +1,6 @@
import { TestDataDatasource } from './datasource';
import { TestDataQueryCtrl } from './query_ctrl';
// import { QueryEditor } from './QueryEditor';
class TestDataAnnotationsQueryCtrl {
annotation: any;
@@ -10,7 +11,7 @@ class TestDataAnnotationsQueryCtrl {
}
export {
TestDataDatasource,
// QueryEditor,
TestDataDatasource as Datasource,
TestDataQueryCtrl as QueryCtrl,
TestDataAnnotationsQueryCtrl as AnnotationsQueryCtrl,

View File

@@ -14,7 +14,7 @@ import DataSourcesListPage from 'app/features/datasources/DataSourcesListPage';
import NewDataSourcePage from '../features/datasources/NewDataSourcePage';
import UsersListPage from 'app/features/users/UsersListPage';
import DataSourceDashboards from 'app/features/datasources/DataSourceDashboards';
import DataSourceSettings from '../features/datasources/settings/DataSourceSettings';
import DataSourceSettingsPage from '../features/datasources/settings/DataSourceSettingsPage';
import OrgDetailsPage from '../features/org/OrgDetailsPage';
/** @ngInject */
@@ -78,7 +78,7 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
.when('/datasources/edit/:id/', {
template: '<react-container />',
resolve: {
component: () => DataSourceSettings,
component: () => DataSourceSettingsPage,
},
})
.when('/datasources/edit/:id/dashboards', {

View File

@@ -1,43 +1,15 @@
import { LayoutMode } from '../core/components/LayoutSelector/LayoutSelector';
import { Plugin, PluginExports, PluginMeta } from './plugins';
export interface DataSource {
id: number;
orgId: number;
name: string;
typeLogoUrl: string;
type: string;
access: string;
url: string;
password: string;
user: string;
database: string;
basicAuth: boolean;
basicAuthPassword: string;
basicAuthUser: string;
isDefault: boolean;
jsonData: { authType: string; defaultRegion: string };
readOnly: boolean;
withCredentials: boolean;
meta?: PluginMeta;
pluginExports?: PluginExports;
}
export interface DataSourceSelectItem {
name: string;
value: string | null;
meta: PluginMeta;
sort: string;
}
import { Plugin } from './plugins';
import { DataSourceSettings } from '@grafana/ui/src/types';
export interface DataSourcesState {
dataSources: DataSource[];
dataSources: DataSourceSettings[];
searchQuery: string;
dataSourceTypeSearchQuery: string;
layoutMode: LayoutMode;
dataSourcesCount: number;
dataSourceTypes: Plugin[];
dataSource: DataSource;
dataSource: DataSourceSettings;
dataSourceMeta: Plugin;
hasFetched: boolean;
}

View File

@@ -1,12 +1,9 @@
import { Value } from 'slate';
import { RawTimeRange, TimeRange } from '@grafana/ui';
import { RawTimeRange, TimeRange, DataQuery, DataSourceSelectItem, DataSourceApi, QueryHint } from '@grafana/ui';
import { Emitter } from 'app/core/core';
import { LogsModel } from 'app/core/logs_model';
import TableModel from 'app/core/table_model';
import { DataSourceSelectItem } from 'app/types/datasources';
import { DataQuery } from './series';
export interface CompletionItem {
/**
@@ -113,7 +110,7 @@ export interface ExploreItemState {
/**
* Datasource instance that has been selected. Datasource-specific logic can be run on this object.
*/
datasourceInstance: any;
datasourceInstance: DataSourceApi;
/**
* Error to be shown when datasource loading or testing failed.
*/
@@ -276,28 +273,6 @@ export interface TypeaheadOutput {
suggestions: CompletionItemGroup[];
}
export interface QueryFix {
type: string;
label: string;
action?: QueryFixAction;
}
export interface QueryFixAction {
type: string;
query?: string;
preventSubmit?: boolean;
}
export interface QueryHint {
type: string;
label: string;
fix?: QueryFix;
}
export interface QueryHintGetter {
(query: DataQuery, results: any[], ...rest: any): QueryHint[];
}
export interface QueryIntervals {
interval: string;
intervalMs: number;

View File

@@ -1,90 +1,19 @@
import { Team, TeamsState, TeamState, TeamGroup, TeamMember } from './teams';
import { AlertRuleDTO, AlertRule, AlertRulesState } from './alerting';
import { LocationState, LocationUpdate, UrlQueryMap, UrlQueryValue } from './location';
import { NavModel, NavModelItem, NavIndex } from './navModel';
import { FolderDTO, FolderState, FolderInfo } from './folders';
import { DashboardState } from './dashboard';
import { DashboardAcl, OrgRole, PermissionLevel } from './acl';
import { ApiKey, ApiKeysState, NewApiKey } from './apiKeys';
import { Invitee, OrgUser, User, UsersState, UserState } from './user';
import { DataSource, DataSourceSelectItem, DataSourcesState } from './datasources';
import { DataQuery, DataQueryResponse, DataQueryOptions } from './series';
import { PluginDashboard, PluginMeta, Plugin, PanelPlugin, PluginsState } from './plugins';
import { Organization, OrganizationState } from './organization';
import {
AppNotification,
AppNotificationSeverity,
AppNotificationsState,
AppNotificationTimeout,
} from './appNotifications';
import { DashboardSearchHit } from './search';
import { ValidationEvents, ValidationRule } from './form';
import { ExploreState } from './explore';
export {
Team,
TeamsState,
TeamState,
TeamGroup,
TeamMember,
AlertRuleDTO,
AlertRule,
AlertRulesState,
LocationState,
LocationUpdate,
NavModel,
NavModelItem,
NavIndex,
UrlQueryMap,
UrlQueryValue,
FolderDTO,
FolderState,
FolderInfo,
DashboardState,
DashboardAcl,
OrgRole,
PermissionLevel,
DataSource,
DataSourceSelectItem,
PluginMeta,
ApiKey,
ApiKeysState,
NewApiKey,
Plugin,
PluginsState,
DataSourcesState,
Invitee,
OrgUser,
User,
UsersState,
PanelPlugin,
DataQuery,
DataQueryResponse,
DataQueryOptions,
PluginDashboard,
Organization,
OrganizationState,
AppNotification,
AppNotificationsState,
AppNotificationSeverity,
AppNotificationTimeout,
DashboardSearchHit,
UserState,
ValidationEvents,
ValidationRule,
};
export * from './teams';
export * from './alerting';
export * from './location';
export * from './navModel';
export * from './folders';
export * from './dashboard';
export * from './acl';
export * from './apiKeys';
export * from './user';
export * from './datasources';
export * from './plugins';
export * from './organization';
export * from './appNotifications';
export * from './search';
export * from './form';
export * from './explore';
export * from './store';
export interface StoreState {
navIndex: NavIndex;
location: LocationState;
alertRules: AlertRulesState;
teams: TeamsState;
team: TeamState;
folder: FolderState;
dashboard: DashboardState;
dataSources: DataSourcesState;
explore: ExploreState;
users: UsersState;
organization: OrganizationState;
appNotifications: AppNotificationsState;
user: UserState;
}

View File

@@ -1,22 +1,4 @@
import { ComponentClass } from 'react';
import { PanelProps, PanelOptionsProps } from '@grafana/ui';
export interface PluginExports {
Datasource?: any;
QueryCtrl?: any;
QueryEditor?: any;
ConfigCtrl?: any;
AnnotationsQueryCtrl?: any;
VariableQueryEditor?: any;
ExploreQueryField?: any;
ExploreStartPage?: any;
// Panel plugin
PanelCtrl?;
Panel?: ComponentClass<PanelProps>;
PanelOptions?: ComponentClass<PanelOptionsProps>;
PanelDefaults?: any;
}
import { PluginExports, PluginMetaInfo } from '@grafana/ui/src/types';
export interface PanelPlugin {
id: string;
@@ -29,56 +11,6 @@ export interface PanelPlugin {
exports?: PluginExports;
}
interface PluginMetaQueryOptions {
cacheTimeout?: boolean;
maxDataPoints?: boolean;
minInterval?: boolean;
}
export interface PluginMeta {
id: string;
name: string;
info: PluginMetaInfo;
includes: PluginInclude[];
// Datasource-specific
metrics?: boolean;
tables?: boolean;
logs?: boolean;
explore?: boolean;
annotations?: boolean;
mixed?: boolean;
hasQueryHelp?: boolean;
queryOptions?: PluginMetaQueryOptions;
}
export interface PluginInclude {
type: string;
name: string;
path: string;
}
interface PluginMetaInfoLink {
name: string;
url: string;
}
export interface PluginMetaInfo {
author: {
name: string;
url?: string;
};
description: string;
links: PluginMetaInfoLink[];
logos: {
large: string;
small: string;
};
screenshots: any[];
updated: string;
version: string;
}
export interface Plugin {
defaultNavUrl: string;
enabled: boolean;

View File

@@ -1,56 +0,0 @@
import { PluginMeta, PluginExports } from './plugins';
import { TimeSeries, TimeRange, RawTimeRange } from '@grafana/ui';
export interface DataQueryResponse {
data: TimeSeries[];
}
export interface DataQuery {
refId: string;
[key: string]: any;
}
export interface DataQueryOptions {
timezone: string;
range: TimeRange;
rangeRaw: RawTimeRange;
targets: DataQuery[];
panelId: number;
dashboardId: number;
cacheTimeout?: string;
interval: string;
intervalMs: number;
maxDataPoints: number;
scopedVars: object;
}
export interface DataSourceApi {
name: string;
meta: PluginMeta;
pluginExports: PluginExports;
/**
* min interval range
*/
interval?: string;
/**
* Imports queries from a different datasource
*/
importQueries?(queries: DataQuery[], originMeta: PluginMeta): Promise<DataQuery[]>;
/**
* Initializes a datasource after instantiation
*/
init?: () => void;
/**
* Main metrics / data query action
*/
query(options: DataQueryOptions): Promise<DataQueryResponse>;
/**
* Test & verify datasource settings & connection details
*/
testDatasource(): Promise<any>;
}

27
public/app/types/store.ts Normal file
View File

@@ -0,0 +1,27 @@
import { NavIndex } from './navModel';
import { LocationState } from './location';
import { AlertRulesState } from './alerting';
import { TeamsState, TeamState } from './teams';
import { FolderState } from './folders';
import { DashboardState } from './dashboard';
import { DataSourcesState } from './datasources';
import { ExploreState } from './explore';
import { UsersState, UserState } from './user';
import { OrganizationState } from './organization';
import { AppNotificationsState } from './appNotifications';
export interface StoreState {
navIndex: NavIndex;
location: LocationState;
alertRules: AlertRulesState;
teams: TeamsState;
team: TeamState;
folder: FolderState;
dashboard: DashboardState;
dataSources: DataSourcesState;
explore: ExploreState;
users: UsersState;
organization: OrganizationState;
appNotifications: AppNotificationsState;
user: UserState;
}