From 98fabfae3e00f9876142ccde77313961494cb374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 18 Jan 2019 17:19:35 +0100 Subject: [PATCH 1/6] wip: typings --- packages/grafana-ui/src/types/datasource.ts | 6 +- packages/grafana-ui/src/types/plugin.ts | 21 +++-- .../app/features/.all.ts@neomake_22624_74.ts | 14 +++ .../prometheus/components/PromQueryField.tsx | 8 +- .../datasource/prometheus/datasource.ts | 94 ++++++++++--------- .../plugins/datasource/prometheus/types.ts | 6 ++ .../datasource/testdata/QueryEditor.tsx | 11 +-- .../plugins/datasource/testdata/datasource.ts | 9 +- .../app/plugins/datasource/testdata/module.ts | 8 +- .../app/plugins/datasource/testdata/types.ts | 11 +++ 10 files changed, 112 insertions(+), 76 deletions(-) create mode 100644 public/app/features/.all.ts@neomake_22624_74.ts create mode 100644 public/app/plugins/datasource/prometheus/types.ts create mode 100644 public/app/plugins/datasource/testdata/types.ts diff --git a/packages/grafana-ui/src/types/datasource.ts b/packages/grafana-ui/src/types/datasource.ts index f47e2473a85..cb6115486b1 100644 --- a/packages/grafana-ui/src/types/datasource.ts +++ b/packages/grafana-ui/src/types/datasource.ts @@ -8,14 +8,14 @@ export interface DataQueryResponse { export interface DataQuery { refId: string; - [key: string]: any; + hide?: boolean; } -export interface DataQueryOptions { +export interface DataQueryOptions { timezone: string; range: TimeRange; rangeRaw: RawTimeRange; - targets: DataQuery[]; + targets: TQuery[]; panelId: number; dashboardId: number; cacheTimeout?: string; diff --git a/packages/grafana-ui/src/types/plugin.ts b/packages/grafana-ui/src/types/plugin.ts index 30a958420de..8ded328b2da 100644 --- a/packages/grafana-ui/src/types/plugin.ts +++ b/packages/grafana-ui/src/types/plugin.ts @@ -2,10 +2,11 @@ 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; +export interface DataSourceApi { + // set externally by grafana + name?: string; + meta?: PluginMeta; + pluginExports?: PluginExports; /** * min interval range @@ -15,7 +16,7 @@ export interface DataSourceApi { /** * Imports queries from a different datasource */ - importQueries?(queries: DataQuery[], originMeta: PluginMeta): Promise; + importQueries?(queries: TQuery[], originMeta: PluginMeta): Promise; /** * Initializes a datasource after instantiation @@ -25,7 +26,7 @@ export interface DataSourceApi { /** * Main metrics / data query action */ - query(options: DataQueryOptions): Promise; + query(options: DataQueryOptions): Promise; /** * Test & verify datasource settings & connection details @@ -35,12 +36,12 @@ export interface DataSourceApi { /** * Get hints for query improvements */ - getQueryHints(query: DataQuery, results: any[], ...rest: any): QueryHint[]; + getQueryHints?(query: TQuery, results: any[], ...rest: any): QueryHint[]; } -export interface QueryEditorProps { - datasource: DataSourceApi; - query: DataQuery; +export interface QueryEditorProps { + datasource: DSType; + query: TQuery; onExecuteQuery?: () => void; onQueryChange?: (value: DataQuery) => void; } diff --git a/public/app/features/.all.ts@neomake_22624_74.ts b/public/app/features/.all.ts@neomake_22624_74.ts new file mode 100644 index 00000000000..99de12bf215 --- /dev/null +++ b/public/app/features/.all.ts@neomake_22624_74.ts @@ -0,0 +1,14 @@ +import './annotations/all'; +import './templating/all'; +import './plugins/all'; +import './dashboard/all'; +import './playlist/all'; +import './panel/all'; +import './org/all'; +import './admin'; +import './alerting/NotificationsEditCtrl'; +import './alerting/NotificationsListCtrl'; +import './manage-dashboards'; +import './teams/CreateTeamCtrl'; +import './profile/all'; +import './datasources/settings/dsHttpSettings'; diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx index 391d39836ca..6fd450394a3 100644 --- a/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx @@ -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 '@grafana/ui/src/types'; +import { PromQuery } from '../types'; const HISTOGRAM_GROUP = '__histograms__'; const METRIC_MARK = 'metric'; @@ -88,13 +88,13 @@ interface CascaderOption { interface PromQueryFieldProps { datasource: any; error?: string | JSX.Element; - initialQuery: DataQuery; + initialQuery: PromQuery; hint?: any; history?: any[]; metricsByPrefix?: CascaderOption[]; onClickHintFix?: (action: any) => void; onPressEnter?: () => void; - onQueryChange?: (value: DataQuery, override?: boolean) => void; + onQueryChange?: (value: PromQuery, override?: boolean) => void; } interface PromQueryFieldState { @@ -166,7 +166,7 @@ class PromQueryField extends React.PureComponent - group.rules.filter(rule => rule.type === 'recording').reduce( - (acc, rule) => ({ - ...acc, - [rule.name]: rule.query, - }), - mapping - ), - {} - ); -} - -export function prometheusRegularEscape(value) { - if (typeof value === 'string') { - return value.replace(/'/g, "\\\\'"); - } - return value; -} - -export function prometheusSpecialRegexEscape(value) { - if (typeof value === 'string') { - return prometheusRegularEscape(value.replace(/\\/g, '\\\\\\\\').replace(/[$^*{}\[\]+?.()]/g, '\\\\$&')); - } - return value; -} - -export class PrometheusDatasource { +export class PrometheusDatasource implements DataSourceApi { type: string; editorSrc: string; name: string; @@ -149,7 +116,7 @@ export class PrometheusDatasource { return this.templateSrv.variableExists(target.expr); } - query(options) { + query(options: DataQueryOptions) { const start = this.getPrometheusTime(options.range.from, false); const end = this.getPrometheusTime(options.range.to, true); @@ -423,7 +390,7 @@ export class PrometheusDatasource { }); } - getExploreState(queries: DataQuery[]): Partial { + getExploreState(queries: PromQuery[]): Partial { let state: Partial = { datasource: this.name }; if (queries && queries.length > 0) { const expandedQueries = queries.map(query => ({ @@ -438,7 +405,7 @@ export class PrometheusDatasource { return state; } - getQueryHints(query: DataQuery, result: any[]) { + getQueryHints(query: PromQuery, result: any[]) { return getQueryHints(query.expr || '', result, this); } @@ -457,7 +424,7 @@ export class PrometheusDatasource { }); } - modifyQuery(query: DataQuery, action: any): DataQuery { + modifyQuery(query: PromQuery, action: any): PromQuery { let expression = query.expr || ''; switch (action.type) { case 'ADD_FILTER': { @@ -507,3 +474,40 @@ export class PrometheusDatasource { return this.resultTransformer.getOriginalMetricName(labelData); } } + +export function alignRange(start, end, step) { + const alignedEnd = Math.ceil(end / step) * step; + const alignedStart = Math.floor(start / step) * step; + return { + end: alignedEnd, + start: alignedStart, + }; +} + +export function extractRuleMappingFromGroups(groups: any[]) { + return groups.reduce( + (mapping, group) => + group.rules.filter(rule => rule.type === 'recording').reduce( + (acc, rule) => ({ + ...acc, + [rule.name]: rule.query, + }), + mapping + ), + {} + ); +} + +export function prometheusRegularEscape(value) { + if (typeof value === 'string') { + return value.replace(/'/g, "\\\\'"); + } + return value; +} + +export function prometheusSpecialRegexEscape(value) { + if (typeof value === 'string') { + return prometheusRegularEscape(value.replace(/\\/g, '\\\\\\\\').replace(/[$^*{}\[\]+?.()]/g, '\\\\$&')); + } + return value; +} diff --git a/public/app/plugins/datasource/prometheus/types.ts b/public/app/plugins/datasource/prometheus/types.ts new file mode 100644 index 00000000000..5bdc687d774 --- /dev/null +++ b/public/app/plugins/datasource/prometheus/types.ts @@ -0,0 +1,6 @@ +import { DataQuery } from '@grafana/ui/src/types'; + +export interface PromQuery extends DataQuery { + expr: string; +} + diff --git a/public/app/plugins/datasource/testdata/QueryEditor.tsx b/public/app/plugins/datasource/testdata/QueryEditor.tsx index 25a811da42d..ef49505d2c6 100644 --- a/public/app/plugins/datasource/testdata/QueryEditor.tsx +++ b/public/app/plugins/datasource/testdata/QueryEditor.tsx @@ -10,18 +10,17 @@ import { FormLabel, Select, SelectOptionItem } from '@grafana/ui'; // Types import { QueryEditorProps } from '@grafana/ui/src/types'; - -interface Scenario { - id: string; - name: string; -} +import { TestDataDatasource } from './datasource'; +import { TestDataQuery, Scenario } from './types'; interface State { scenarioList: Scenario[]; current: Scenario | null; } -export class QueryEditor extends PureComponent { +type Props = QueryEditorProps; + +export class QueryEditor extends PureComponent { backendSrv: BackendSrv = getBackendSrv(); state: State = { diff --git a/public/app/plugins/datasource/testdata/datasource.ts b/public/app/plugins/datasource/testdata/datasource.ts index 989209792fb..c329389ee8c 100644 --- a/public/app/plugins/datasource/testdata/datasource.ts +++ b/public/app/plugins/datasource/testdata/datasource.ts @@ -1,15 +1,17 @@ import _ from 'lodash'; import TableModel from 'app/core/table_model'; +import { DataSourceApi, DataQueryOptions } from '@grafana/ui'; +import { TestDataQuery } from './types'; -class TestDataDatasource { - id: any; +export class TestDataDatasource implements DataSourceApi { + id: number; /** @ngInject */ constructor(instanceSettings, private backendSrv, private $q) { this.id = instanceSettings.id; } - query(options) { + query(options: DataQueryOptions) { const queries = _.filter(options.targets, item => { return item.hide !== true; }).map(item => { @@ -93,4 +95,3 @@ class TestDataDatasource { } } -export { TestDataDatasource }; diff --git a/public/app/plugins/datasource/testdata/module.ts b/public/app/plugins/datasource/testdata/module.ts index d3b376e3307..efd6c207407 100644 --- a/public/app/plugins/datasource/testdata/module.ts +++ b/public/app/plugins/datasource/testdata/module.ts @@ -1,6 +1,6 @@ import { TestDataDatasource } from './datasource'; -import { TestDataQueryCtrl } from './query_ctrl'; -// import { QueryEditor } from './QueryEditor'; +// import { TestDataQueryCtrl } from './query_ctrl'; +import { QueryEditor } from './QueryEditor'; class TestDataAnnotationsQueryCtrl { annotation: any; @@ -11,8 +11,8 @@ class TestDataAnnotationsQueryCtrl { } export { - // QueryEditor, + QueryEditor, TestDataDatasource as Datasource, - TestDataQueryCtrl as QueryCtrl, + // TestDataQueryCtrl as QueryCtrl, TestDataAnnotationsQueryCtrl as AnnotationsQueryCtrl, }; diff --git a/public/app/plugins/datasource/testdata/types.ts b/public/app/plugins/datasource/testdata/types.ts new file mode 100644 index 00000000000..e233c3ef7a0 --- /dev/null +++ b/public/app/plugins/datasource/testdata/types.ts @@ -0,0 +1,11 @@ +import { DataQuery } from '@grafana/ui/src/types'; + +export interface TestDataQuery extends DataQuery { + scenarioId: string; +} + +export interface Scenario { + id: string; + name: string; +} + From a69f79caed27b19b7f0652928823e51b4262f407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 18 Jan 2019 17:43:58 +0100 Subject: [PATCH 2/6] wip: more typings --- public/app/features/dashboard/panel_model.ts | 2 -- public/app/plugins/datasource/loki/datasource.ts | 15 ++++++++++----- public/app/plugins/datasource/loki/types.ts | 6 ++++++ 3 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 public/app/plugins/datasource/loki/types.ts diff --git a/public/app/features/dashboard/panel_model.ts b/public/app/features/dashboard/panel_model.ts index b54cabc9012..b7e8a68c722 100644 --- a/public/app/features/dashboard/panel_model.ts +++ b/public/app/features/dashboard/panel_model.ts @@ -243,8 +243,6 @@ export class PanelModel { addQuery(query?: Partial) { query = query || { refId: 'A' }; query.refId = this.getNextQueryLetter(); - query.isNew = true; - this.targets.push(query); } diff --git a/public/app/plugins/datasource/loki/datasource.ts b/public/app/plugins/datasource/loki/datasource.ts index 893ce649613..6c5bda8bcf2 100644 --- a/public/app/plugins/datasource/loki/datasource.ts +++ b/public/app/plugins/datasource/loki/datasource.ts @@ -1,13 +1,18 @@ +// Libraries import _ from 'lodash'; +// Services & Utils import * as dateMath from 'app/core/utils/datemath'; -import { LogsStream, LogsModel, makeSeriesForLogs } from 'app/core/logs_model'; -import { PluginMeta, DataQuery } from '@grafana/ui/src/types'; import { addLabelToSelector } from 'app/plugins/datasource/prometheus/add_label_to_query'; - import LanguageProvider from './language_provider'; import { mergeStreamsToLogs } from './result_transformer'; import { formatQuery, parseQuery } from './query_utils'; +import { makeSeriesForLogs } from 'app/core/logs_model'; + +// Types +import { LogsStream, LogsModel } from 'app/core/logs_model'; +import { PluginMeta, DataQueryOptions, DataSourceApi } from '@grafana/ui/src/types'; +import { LokiQuery } from './types'; export const DEFAULT_MAX_LINES = 1000; @@ -27,7 +32,7 @@ function serializeParams(data: any) { .join('&'); } -export default class LokiDatasource { +export default class LokiDatasource implements DataSourceApi { languageProvider: LanguageProvider; maxLines: number; @@ -68,7 +73,7 @@ export default class LokiDatasource { }; } - query(options): Promise<{ data: LogsStream[] }> { + query(options: DataQueryOptions): Promise<{ data: LogsStream[] }> { const queryTargets = options.targets .filter(target => target.expr) .map(target => this.prepareQueryTarget(target, options)); diff --git a/public/app/plugins/datasource/loki/types.ts b/public/app/plugins/datasource/loki/types.ts new file mode 100644 index 00000000000..7325239bb3a --- /dev/null +++ b/public/app/plugins/datasource/loki/types.ts @@ -0,0 +1,6 @@ +import { DataQuery } from '@grafana/ui/src/types'; + +export interface LokiQuery extends DataQuery { + expr: string; +} + From 1d2902715f33f06fc75a06f2c324a79d6b8e281f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 18 Jan 2019 18:14:27 +0100 Subject: [PATCH 3/6] wip: progress on adding query types --- .../plugins/datasource/loki/datasource.test.ts | 14 +++++++++++--- public/app/plugins/datasource/loki/datasource.ts | 10 +++++----- .../plugins/datasource/loki/language_provider.ts | 16 +++++++++++----- public/app/types/explore.ts | 4 ++-- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/public/app/plugins/datasource/loki/datasource.test.ts b/public/app/plugins/datasource/loki/datasource.test.ts index b7f67ffc0e7..8b84f1073fb 100644 --- a/public/app/plugins/datasource/loki/datasource.test.ts +++ b/public/app/plugins/datasource/loki/datasource.test.ts @@ -1,3 +1,4 @@ +import moment from 'moment'; import LokiDatasource from './datasource'; describe('LokiDatasource', () => { @@ -13,12 +14,19 @@ describe('LokiDatasource', () => { replace: a => a, }; - const range = { from: 'now-6h', to: 'now' }; + const range = { + from: moment(), + to: moment(), + raw: { + from: 'now-6h', + to: 'now' + } + }; test('should use default max lines when no limit given', () => { const ds = new LokiDatasource(instanceSettings, backendSrvMock, templateSrvMock); backendSrvMock.datasourceRequest = jest.fn(); - ds.query({ range, targets: [{ expr: 'foo' }] }); + ds.query({ range, targets: [{ expr: 'foo', refId: 'B' }] }); expect(backendSrvMock.datasourceRequest.mock.calls.length).toBe(1); expect(backendSrvMock.datasourceRequest.mock.calls[0][0].url).toContain('limit=1000'); }); @@ -28,7 +36,7 @@ describe('LokiDatasource', () => { const customSettings = { ...instanceSettings, jsonData: customData }; const ds = new LokiDatasource(customSettings, backendSrvMock, templateSrvMock); backendSrvMock.datasourceRequest = jest.fn(); - ds.query({ range, targets: [{ expr: 'foo' }] }); + ds.query({ range, targets: [{ expr: 'foo', refId: 'A' }] }); expect(backendSrvMock.datasourceRequest.mock.calls.length).toBe(1); expect(backendSrvMock.datasourceRequest.mock.calls[0][0].url).toContain('limit=20'); }); diff --git a/public/app/plugins/datasource/loki/datasource.ts b/public/app/plugins/datasource/loki/datasource.ts index 6c5bda8bcf2..95d7a2a830e 100644 --- a/public/app/plugins/datasource/loki/datasource.ts +++ b/public/app/plugins/datasource/loki/datasource.ts @@ -11,7 +11,7 @@ import { makeSeriesForLogs } from 'app/core/logs_model'; // Types import { LogsStream, LogsModel } from 'app/core/logs_model'; -import { PluginMeta, DataQueryOptions, DataSourceApi } from '@grafana/ui/src/types'; +import { PluginMeta, DataQueryOptions } from '@grafana/ui/src/types'; import { LokiQuery } from './types'; export const DEFAULT_MAX_LINES = 1000; @@ -32,7 +32,7 @@ function serializeParams(data: any) { .join('&'); } -export default class LokiDatasource implements DataSourceApi { +export default class LokiDatasource { languageProvider: LanguageProvider; maxLines: number; @@ -101,7 +101,7 @@ export default class LokiDatasource implements DataSourceApi { }); } - async importQueries(queries: DataQuery[], originMeta: PluginMeta): Promise { + async importQueries(queries: LokiQuery[], originMeta: PluginMeta): Promise { return this.languageProvider.importQueries(queries, originMeta.id); } @@ -114,7 +114,7 @@ export default class LokiDatasource implements DataSourceApi { }); } - modifyQuery(query: DataQuery, action: any): DataQuery { + modifyQuery(query: LokiQuery, action: any): LokiQuery { const parsed = parseQuery(query.expr || ''); let selector = parsed.query; switch (action.type) { @@ -129,7 +129,7 @@ export default class LokiDatasource implements DataSourceApi { return { ...query, expr: expression }; } - getHighlighterExpression(query: DataQuery): string { + getHighlighterExpression(query: LokiQuery): string { return parseQuery(query.expr).regexp; } diff --git a/public/app/plugins/datasource/loki/language_provider.ts b/public/app/plugins/datasource/loki/language_provider.ts index 3532e81ccd9..115a0a5f11f 100644 --- a/public/app/plugins/datasource/loki/language_provider.ts +++ b/public/app/plugins/datasource/loki/language_provider.ts @@ -1,6 +1,12 @@ +// Libraries import _ from 'lodash'; import moment from 'moment'; +// Services & Utils +import { parseSelector, labelRegexp, selectorRegexp } from 'app/plugins/datasource/prometheus/language_utils'; +import syntax from './syntax'; + +// Types import { CompletionItem, CompletionItemGroup, @@ -9,9 +15,7 @@ import { TypeaheadOutput, HistoryItem, } from 'app/types/explore'; -import { parseSelector, labelRegexp, selectorRegexp } from 'app/plugins/datasource/prometheus/language_utils'; -import syntax from './syntax'; -import { DataQuery } from '@grafana/ui/src/types'; +import { LokiQuery } from './types'; const DEFAULT_KEYS = ['job', 'namespace']; const EMPTY_SELECTOR = '{}'; @@ -20,7 +24,9 @@ const HISTORY_COUNT_CUTOFF = 1000 * 60 * 60 * 24; // 24h const wrapLabel = (label: string) => ({ label }); -export function addHistoryMetadata(item: CompletionItem, history: HistoryItem[]): CompletionItem { +type LokiHistoryItem = HistoryItem; + +export function addHistoryMetadata(item: CompletionItem, history: LokiHistoryItem[]): CompletionItem { const cutoffTs = Date.now() - HISTORY_COUNT_CUTOFF; const historyForItem = history.filter(h => h.ts > cutoffTs && (h.query.expr as string) === item.label); const count = historyForItem.length; @@ -155,7 +161,7 @@ export default class LokiLanguageProvider extends LanguageProvider { return { context, refresher, suggestions }; } - async importQueries(queries: DataQuery[], datasourceType: string): Promise { + async importQueries(queries: LokiQuery[], datasourceType: string): Promise { if (datasourceType === 'prometheus') { return Promise.all( queries.map(async query => { diff --git a/public/app/types/explore.ts b/public/app/types/explore.ts index e5ae676ba25..c69e93ff88e 100644 --- a/public/app/types/explore.ts +++ b/public/app/types/explore.ts @@ -243,9 +243,9 @@ export interface ExploreUrlState { range: RawTimeRange; } -export interface HistoryItem { +export interface HistoryItem { ts: number; - query: DataQuery; + query: TQuery; } export abstract class LanguageProvider { From 5d17ad110399fb71aa50880948e8f9aa3c590dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 18 Jan 2019 18:59:32 +0100 Subject: [PATCH 4/6] more typings work around data query and data source --- packages/grafana-ui/src/types/datasource.ts | 18 +++++++++++++ public/app/core/utils/explore.ts | 8 ++++-- .../loki/components/LokiQueryField.tsx | 15 +++++++---- .../datasource/loki/datasource.test.ts | 22 ++++++++-------- public/test/helpers/getQueryOptions.ts | 25 +++++++++++++++++++ 5 files changed, 69 insertions(+), 19 deletions(-) create mode 100644 public/test/helpers/getQueryOptions.ts diff --git a/packages/grafana-ui/src/types/datasource.ts b/packages/grafana-ui/src/types/datasource.ts index cb6115486b1..ffcbbb5fe64 100644 --- a/packages/grafana-ui/src/types/datasource.ts +++ b/packages/grafana-ui/src/types/datasource.ts @@ -7,8 +7,26 @@ export interface DataQueryResponse { } export interface DataQuery { + /** + * A - Z + */ refId: string; + + /** + * true if query is disabled (ie not executed / sent to TSDB) + */ hide?: boolean; + + /** + * Unique, guid like, string used in explore mode + */ + key?: string; + + /** + * For mixed data sources the selected datasource is on the query level. + * For non mixed scenarios this is undefined. + */ + datasource?: string | null; } export interface DataQueryOptions { diff --git a/public/app/core/utils/explore.ts b/public/app/core/utils/explore.ts index 2d1c0d2ad71..45b70672bc6 100644 --- a/public/app/core/utils/explore.ts +++ b/public/app/core/utils/explore.ts @@ -203,7 +203,7 @@ export function ensureQueries(queries?: DataQuery[]): DataQuery[] { /** * A target is non-empty when it has keys (with non-empty values) other than refId and key. */ -export function hasNonEmptyQuery(queries: DataQuery[]): boolean { +export function hasNonEmptyQuery(queries: TQuery[]): boolean { return ( queries && queries.some( @@ -280,7 +280,11 @@ export function makeTimeSeriesList(dataList) { /** * Update the query history. Side-effect: store history in local storage */ -export function updateHistory(history: HistoryItem[], datasourceId: string, queries: DataQuery[]): HistoryItem[] { +export function updateHistory( + history: Array>, + datasourceId: string, + queries: T[] +): Array> { const ts = Date.now(); queries.forEach(query => { history = [{ query, ts }, ...history]; diff --git a/public/app/plugins/datasource/loki/components/LokiQueryField.tsx b/public/app/plugins/datasource/loki/components/LokiQueryField.tsx index 98c8a5f6da9..febb322acca 100644 --- a/public/app/plugins/datasource/loki/components/LokiQueryField.tsx +++ b/public/app/plugins/datasource/loki/components/LokiQueryField.tsx @@ -1,16 +1,21 @@ +// Libraries import React from 'react'; 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'; +// Components +import QueryField, { TypeaheadInput, QueryFieldState } from 'app/features/explore/QueryField'; +// Utils & Services // dom also includes Element polyfills import { getNextCharacter, getPreviousCousin } from 'app/features/explore/utils/dom'; 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'; + +// Types +import { LokiQuery } from '../types'; +import { TypeaheadOutput } from 'app/types/explore'; const PRISM_SYNTAX = 'promql'; @@ -63,10 +68,10 @@ interface LokiQueryFieldProps { error?: string | JSX.Element; hint?: any; history?: any[]; - initialQuery?: DataQuery; + initialQuery?: LokiQuery; onClickHintFix?: (action: any) => void; onPressEnter?: () => void; - onQueryChange?: (value: DataQuery, override?: boolean) => void; + onQueryChange?: (value: LokiQuery, override?: boolean) => void; } interface LokiQueryFieldState { diff --git a/public/app/plugins/datasource/loki/datasource.test.ts b/public/app/plugins/datasource/loki/datasource.test.ts index 8b84f1073fb..195ac194dad 100644 --- a/public/app/plugins/datasource/loki/datasource.test.ts +++ b/public/app/plugins/datasource/loki/datasource.test.ts @@ -1,5 +1,6 @@ -import moment from 'moment'; import LokiDatasource from './datasource'; +import { LokiQuery } from './types'; +import { getQueryOptions } from 'test/helpers/getQueryOptions'; describe('LokiDatasource', () => { const instanceSettings: any = { @@ -14,19 +15,13 @@ describe('LokiDatasource', () => { replace: a => a, }; - const range = { - from: moment(), - to: moment(), - raw: { - from: 'now-6h', - to: 'now' - } - }; - test('should use default max lines when no limit given', () => { const ds = new LokiDatasource(instanceSettings, backendSrvMock, templateSrvMock); backendSrvMock.datasourceRequest = jest.fn(); - ds.query({ range, targets: [{ expr: 'foo', refId: 'B' }] }); + const options = getQueryOptions({ targets: [{ expr: 'foo', refId: 'B' }] }); + + ds.query(options); + expect(backendSrvMock.datasourceRequest.mock.calls.length).toBe(1); expect(backendSrvMock.datasourceRequest.mock.calls[0][0].url).toContain('limit=1000'); }); @@ -36,7 +31,10 @@ describe('LokiDatasource', () => { const customSettings = { ...instanceSettings, jsonData: customData }; const ds = new LokiDatasource(customSettings, backendSrvMock, templateSrvMock); backendSrvMock.datasourceRequest = jest.fn(); - ds.query({ range, targets: [{ expr: 'foo', refId: 'A' }] }); + + const options = getQueryOptions({ targets: [{ expr: 'foo', refId: 'B' }] }); + ds.query(options); + expect(backendSrvMock.datasourceRequest.mock.calls.length).toBe(1); expect(backendSrvMock.datasourceRequest.mock.calls[0][0].url).toContain('limit=20'); }); diff --git a/public/test/helpers/getQueryOptions.ts b/public/test/helpers/getQueryOptions.ts new file mode 100644 index 00000000000..ac92c2afb55 --- /dev/null +++ b/public/test/helpers/getQueryOptions.ts @@ -0,0 +1,25 @@ +import { DataQueryOptions, DataQuery } from '@grafana/ui'; +import moment from 'moment'; + + +export function getQueryOptions(options: Partial>): DataQueryOptions { + const raw = {from: 'now', to: 'now-1h'}; + const range = { from: moment(), to: moment(), raw: raw}; + + const defaults: DataQueryOptions = { + range: range, + rangeRaw: raw, + targets: [], + scopedVars: {}, + timezone: 'browser', + panelId: 1, + dashboardId: 1, + interval: '60s', + intervalMs: 60000, + maxDataPoints: 500, + }; + + Object.assign(defaults, options); + + return defaults; +} From 5ab9a7c2b8809a9e73aeb1ed754000daacace79a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 18 Jan 2019 19:11:30 +0100 Subject: [PATCH 5/6] Further refinements of typings --- packages/grafana-ui/src/types/plugin.ts | 20 ++++++++++--------- .../datasource/testdata/QueryEditor.tsx | 5 +++-- .../plugins/datasource/testdata/datasource.ts | 6 +++++- .../app/plugins/datasource/testdata/module.ts | 8 ++++---- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/packages/grafana-ui/src/types/plugin.ts b/packages/grafana-ui/src/types/plugin.ts index 8ded328b2da..420a54e5840 100644 --- a/packages/grafana-ui/src/types/plugin.ts +++ b/packages/grafana-ui/src/types/plugin.ts @@ -3,11 +3,6 @@ import { PanelProps, PanelOptionsProps } from './panel'; import { DataQueryOptions, DataQuery, DataQueryResponse, QueryHint } from './datasource'; export interface DataSourceApi { - // set externally by grafana - name?: string; - meta?: PluginMeta; - pluginExports?: PluginExports; - /** * min interval range */ @@ -37,19 +32,26 @@ export interface DataSourceApi { * Get hints for query improvements */ getQueryHints?(query: TQuery, results: any[], ...rest: any): QueryHint[]; + + /** + * Set after constructor is called by Grafana + */ + name?: string; + meta?: PluginMeta; + pluginExports?: PluginExports; } -export interface QueryEditorProps { +export interface QueryEditorProps { datasource: DSType; query: TQuery; onExecuteQuery?: () => void; - onQueryChange?: (value: DataQuery) => void; + onQueryChange?: (value: TQuery) => void; } export interface PluginExports { - Datasource?: any; + Datasource?: DataSourceApi; QueryCtrl?: any; - QueryEditor?: ComponentClass; + QueryEditor?: ComponentClass>; ConfigCtrl?: any; AnnotationsQueryCtrl?: any; VariableQueryEditor?: any; diff --git a/public/app/plugins/datasource/testdata/QueryEditor.tsx b/public/app/plugins/datasource/testdata/QueryEditor.tsx index ef49505d2c6..20b86d571df 100644 --- a/public/app/plugins/datasource/testdata/QueryEditor.tsx +++ b/public/app/plugins/datasource/testdata/QueryEditor.tsx @@ -29,11 +29,12 @@ export class QueryEditor extends PureComponent { }; async componentDidMount() { - const { query } = this.props; + const { query, datasource } = this.props; query.scenarioId = query.scenarioId || 'random_walk'; - const scenarioList = await this.backendSrv.get('/api/tsdb/testdata/scenarios'); + // const scenarioList = await this.backendSrv.get('/api/tsdb/testdata/scenarios'); + const scenarioList = await datasource.getScenarios(); const current = _.find(scenarioList, { id: query.scenarioId }); this.setState({ scenarioList: scenarioList, current: current }); diff --git a/public/app/plugins/datasource/testdata/datasource.ts b/public/app/plugins/datasource/testdata/datasource.ts index c329389ee8c..6ba0da59457 100644 --- a/public/app/plugins/datasource/testdata/datasource.ts +++ b/public/app/plugins/datasource/testdata/datasource.ts @@ -1,7 +1,7 @@ import _ from 'lodash'; import TableModel from 'app/core/table_model'; import { DataSourceApi, DataQueryOptions } from '@grafana/ui'; -import { TestDataQuery } from './types'; +import { TestDataQuery, Scenario } from './types'; export class TestDataDatasource implements DataSourceApi { id: number; @@ -93,5 +93,9 @@ export class TestDataDatasource implements DataSourceApi { message: 'Data source is working', }); } + + getScenarios(): Promise { + return this.backendSrv.get('/api/tsdb/testdata/scenarios'); + } } diff --git a/public/app/plugins/datasource/testdata/module.ts b/public/app/plugins/datasource/testdata/module.ts index efd6c207407..d3b376e3307 100644 --- a/public/app/plugins/datasource/testdata/module.ts +++ b/public/app/plugins/datasource/testdata/module.ts @@ -1,6 +1,6 @@ import { TestDataDatasource } from './datasource'; -// import { TestDataQueryCtrl } from './query_ctrl'; -import { QueryEditor } from './QueryEditor'; +import { TestDataQueryCtrl } from './query_ctrl'; +// import { QueryEditor } from './QueryEditor'; class TestDataAnnotationsQueryCtrl { annotation: any; @@ -11,8 +11,8 @@ class TestDataAnnotationsQueryCtrl { } export { - QueryEditor, + // QueryEditor, TestDataDatasource as Datasource, - // TestDataQueryCtrl as QueryCtrl, + TestDataQueryCtrl as QueryCtrl, TestDataAnnotationsQueryCtrl as AnnotationsQueryCtrl, }; From 12468c6033811bae9a21ab1ba09a994a538fce40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 18 Jan 2019 19:14:22 +0100 Subject: [PATCH 6/6] Delete .all.ts@neomake_22624_74.ts --- public/app/features/.all.ts@neomake_22624_74.ts | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 public/app/features/.all.ts@neomake_22624_74.ts diff --git a/public/app/features/.all.ts@neomake_22624_74.ts b/public/app/features/.all.ts@neomake_22624_74.ts deleted file mode 100644 index 99de12bf215..00000000000 --- a/public/app/features/.all.ts@neomake_22624_74.ts +++ /dev/null @@ -1,14 +0,0 @@ -import './annotations/all'; -import './templating/all'; -import './plugins/all'; -import './dashboard/all'; -import './playlist/all'; -import './panel/all'; -import './org/all'; -import './admin'; -import './alerting/NotificationsEditCtrl'; -import './alerting/NotificationsListCtrl'; -import './manage-dashboards'; -import './teams/CreateTeamCtrl'; -import './profile/all'; -import './datasources/settings/dsHttpSettings';