diff --git a/.betterer.results b/.betterer.results index a5ae922b47a..46ecf2ed512 100644 --- a/.betterer.results +++ b/.betterer.results @@ -4144,9 +4144,6 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "1"], [0, 0, 0, "Do not use any type assertions.", "2"] ], - "public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxCheatSheet.tsx:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"] - ], "public/app/plugins/datasource/influxdb/datasource.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"], diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxCheatSheet.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxCheatSheet.tsx index 7bf562c2cff..04b573159c6 100644 --- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxCheatSheet.tsx +++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxCheatSheet.tsx @@ -8,7 +8,7 @@ const CHEAT_SHEET_ITEMS = [ }, ]; -const InfluxCheatSheet = (props: any) => ( +export const InfluxCheatSheet = () => (

InfluxDB Cheat Sheet

{CHEAT_SHEET_ITEMS.map((item) => ( @@ -19,5 +19,3 @@ const InfluxCheatSheet = (props: any) => ( ))}
); - -export default InfluxCheatSheet; diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxStartPage.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxStartPage.tsx index f5ac86a24d2..10f35190d08 100644 --- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxStartPage.tsx +++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxStartPage.tsx @@ -1,11 +1,7 @@ -import React, { PureComponent } from 'react'; +import React from 'react'; -import { QueryEditorHelpProps } from '@grafana/data'; +import { InfluxCheatSheet } from './InfluxCheatSheet'; -import InfluxCheatSheet from './InfluxCheatSheet'; - -export default class InfluxStartPage extends PureComponent { - render() { - return ; - } +export function InfluxStartPage() { + return ; } diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/code/RawInfluxQLEditor.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/code/RawInfluxQLEditor.tsx index 887bec9ee93..0df57b7b26d 100644 --- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/code/RawInfluxQLEditor.tsx +++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/code/RawInfluxQLEditor.tsx @@ -4,7 +4,7 @@ import { HorizontalGroup, InlineFormLabel, Input, Select, TextArea } from '@graf import { InfluxQuery } from '../../../../../types'; import { DEFAULT_RESULT_FORMAT, RESULT_FORMATS } from '../../../constants'; -import { useShadowedState } from '../../hooks/useShadowedState'; +import { useShadowedState } from '../hooks/useShadowedState'; type Props = { query: InfluxQuery; diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/hooks/useRetentionPolicies.test.ts b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/hooks/useRetentionPolicies.test.ts new file mode 100644 index 00000000000..e4648e2f1e7 --- /dev/null +++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/hooks/useRetentionPolicies.test.ts @@ -0,0 +1,44 @@ +import { renderHook } from '@testing-library/react-hooks'; + +import config from 'app/core/config'; + +import { getMockDS, getMockDSInstanceSettings, mockBackendService } from '../../../../../specs/mocks'; + +import { useRetentionPolicies } from './useRetentionPolicies'; + +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), +})); + +describe('useRetentionPolicies', () => { + it('should return all policies when influxdbBackendMigration feature toggle enabled', async () => { + const instanceSettings = getMockDSInstanceSettings(); + const datasource = getMockDS(instanceSettings); + mockBackendService(response); + + config.featureToggles.influxdbBackendMigration = true; + const { result, waitForNextUpdate } = renderHook(() => useRetentionPolicies(datasource)); + await waitForNextUpdate(); + expect(result.current.retentionPolicies.length).toEqual(4); + expect(result.current.retentionPolicies[0]).toEqual('autogen'); + }); +}); + +const response = { + data: { + results: { + metadataQuery: { + status: 200, + frames: [ + { + schema: { + refId: 'metadataQuery', + fields: [{ name: 'value', type: 'string', typeInfo: { frame: 'string' } }], + }, + data: { values: [['autogen', 'bar', '5m_avg', '1m_avg']] }, + }, + ], + }, + }, + }, +}; diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/hooks/useRetentionPolicies.ts b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/hooks/useRetentionPolicies.ts new file mode 100644 index 00000000000..c25b795294c --- /dev/null +++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/hooks/useRetentionPolicies.ts @@ -0,0 +1,15 @@ +import { useEffect, useState } from 'react'; + +import InfluxDatasource from '../../../../../datasource'; +import { getAllPolicies } from '../../../../../influxql_metadata_query'; + +export const useRetentionPolicies = (datasource: InfluxDatasource) => { + const [retentionPolicies, setRetentionPolicies] = useState([]); + useEffect(() => { + getAllPolicies(datasource).then((data) => { + setRetentionPolicies(data); + }); + }, [datasource]); + + return { retentionPolicies }; +}; diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/hooks/useShadowedState.test.ts b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/hooks/useShadowedState.test.ts similarity index 100% rename from public/app/plugins/datasource/influxdb/components/editor/query/hooks/useShadowedState.test.ts rename to public/app/plugins/datasource/influxdb/components/editor/query/influxql/hooks/useShadowedState.test.ts diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/hooks/useShadowedState.ts b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/hooks/useShadowedState.ts similarity index 100% rename from public/app/plugins/datasource/influxdb/components/editor/query/hooks/useShadowedState.ts rename to public/app/plugins/datasource/influxdb/components/editor/query/influxql/hooks/useShadowedState.ts diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/utils/filterTags.ts b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/utils/filterTags.ts new file mode 100644 index 00000000000..904de835063 --- /dev/null +++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/utils/filterTags.ts @@ -0,0 +1,7 @@ +// it is possible to add fields into the `InfluxQueryTag` structures, and they do work, +// but in some cases, when we do metadata queries, we have to remove them from the queries. +import { InfluxQueryTag } from '../../../../../types'; + +export function filterTags(parts: InfluxQueryTag[], allTagKeys: Set): InfluxQueryTag[] { + return parts.filter((t) => t.key.endsWith('::tag') || allTagKeys.has(t.key + '::tag')); +} diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/utils/getTemplateVariableOptions.ts b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/utils/getTemplateVariableOptions.ts new file mode 100644 index 00000000000..51db862e4d9 --- /dev/null +++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/utils/getTemplateVariableOptions.ts @@ -0,0 +1,12 @@ +import { TypedVariableModel } from '@grafana/data/src'; +import { getTemplateSrv } from '@grafana/runtime/src'; + +export function getTemplateVariableOptions(wrapper: (v: TypedVariableModel) => string) { + return ( + getTemplateSrv() + .getVariables() + // we make them regex-params, i'm not 100% sure why. + // probably because this way multi-value variables work ok too. + .map(wrapper) + ); +} diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/utils/withTemplateVariableOptions.ts b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/utils/withTemplateVariableOptions.ts new file mode 100644 index 00000000000..89bd1372bcd --- /dev/null +++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/utils/withTemplateVariableOptions.ts @@ -0,0 +1,16 @@ +// helper function to make it easy to call this from the widget-render-code +import { TypedVariableModel } from '@grafana/data/src'; + +import { getTemplateVariableOptions } from './getTemplateVariableOptions'; + +export function withTemplateVariableOptions( + optionsPromise: Promise, + wrapper: (v: TypedVariableModel) => string, + filter?: string +): Promise { + let templateVariableOptions = getTemplateVariableOptions(wrapper); + if (filter) { + templateVariableOptions = templateVariableOptions.filter((tvo) => tvo.indexOf(filter) > -1); + } + return optionsPromise.then((options) => [...templateVariableOptions, ...options]); +} diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/utils/wrapper.ts b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/utils/wrapper.ts new file mode 100644 index 00000000000..769a9a435a4 --- /dev/null +++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/utils/wrapper.ts @@ -0,0 +1,9 @@ +import { TypedVariableModel } from '@grafana/data/src'; + +export function wrapRegex(v: TypedVariableModel): string { + return `/^$${v.name}$/`; +} + +export function wrapPure(v: TypedVariableModel): string { + return `$${v.name}`; +} diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/InputSection.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/InputSection.tsx index 6bf9e24e9b5..71b9fad90d3 100644 --- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/InputSection.tsx +++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/InputSection.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { Input } from '@grafana/ui'; -import { useShadowedState } from '../../hooks/useShadowedState'; +import { useShadowedState } from '../hooks/useShadowedState'; import { paddingRightClass } from './styles'; diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/Seg.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/Seg.tsx index 8a2077b0e66..28b679fd5e3 100644 --- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/Seg.tsx +++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/Seg.tsx @@ -6,7 +6,7 @@ import { useAsyncFn } from 'react-use'; import { SelectableValue } from '@grafana/data'; import { AsyncSelect, InlineLabel, Input, Select } from '@grafana/ui'; -import { useShadowedState } from '../../hooks/useShadowedState'; +import { useShadowedState } from '../hooks/useShadowedState'; // this file is a simpler version of `grafana-ui / SegmentAsync.tsx` // with some changes: diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.tsx index 0a00132e9e1..21951edc28a 100644 --- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.tsx +++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.tsx @@ -1,9 +1,7 @@ import { css } from '@emotion/css'; import React, { useId, useMemo } from 'react'; -import { useAsync } from 'react-use'; -import { GrafanaTheme2, TypedVariableModel } from '@grafana/data'; -import { getTemplateSrv } from '@grafana/runtime'; +import { GrafanaTheme2 } from '@grafana/data'; import { InlineLabel, SegmentSection, useStyles2 } from '@grafana/ui'; import InfluxDatasource from '../../../../../datasource'; @@ -25,7 +23,11 @@ import { } from '../../../../../queryUtils'; import { InfluxQuery, InfluxQueryTag } from '../../../../../types'; import { DEFAULT_RESULT_FORMAT } from '../../../constants'; +import { useRetentionPolicies } from '../hooks/useRetentionPolicies'; +import { filterTags } from '../utils/filterTags'; import { getNewGroupByPartOptions, getNewSelectPartOptions, makePartList } from '../utils/partListUtils'; +import { withTemplateVariableOptions } from '../utils/withTemplateVariableOptions'; +import { wrapPure, wrapRegex } from '../utils/wrapper'; import { FormatAsSection } from './FormatAsSection'; import { FromSection } from './FromSection'; @@ -41,43 +43,6 @@ type Props = { datasource: InfluxDatasource; }; -function wrapRegex(v: TypedVariableModel): string { - return `/^$${v.name}$/`; -} - -function wrapPure(v: TypedVariableModel): string { - return `$${v.name}`; -} - -function getTemplateVariableOptions(wrapper: (v: TypedVariableModel) => string) { - return ( - getTemplateSrv() - .getVariables() - // we make them regex-params, i'm not 100% sure why. - // probably because this way multi-value variables work ok too. - .map(wrapper) - ); -} - -// helper function to make it easy to call this from the widget-render-code -function withTemplateVariableOptions( - optionsPromise: Promise, - wrapper: (v: TypedVariableModel) => string, - filter?: string -): Promise { - let templateVariableOptions = getTemplateVariableOptions(wrapper); - if (filter) { - templateVariableOptions = templateVariableOptions.filter((tvo) => tvo.indexOf(filter) > -1); - } - return optionsPromise.then((options) => [...templateVariableOptions, ...options]); -} - -// it is possible to add fields into the `InfluxQueryTag` structures, and they do work, -// but in some cases, when we do metadata queries, we have to remove them from the queries. -function filterTags(parts: InfluxQueryTag[], allTagKeys: Set): InfluxQueryTag[] { - return parts.filter((t) => t.key.endsWith('::tag') || allTagKeys.has(t.key + '::tag')); -} - export const VisualInfluxQLEditor = (props: Props): JSX.Element => { const uniqueId = useId(); const formatAsId = `influxdb-qe-format-as-${uniqueId}`; @@ -87,9 +52,7 @@ export const VisualInfluxQLEditor = (props: Props): JSX.Element => { const query = normalizeQuery(props.query); const { datasource } = props; const { measurement, policy } = query; - - const policyData = useAsync(() => getAllPolicies(datasource), [datasource]); - const retentionPolicies = !!policyData.error ? [] : policyData.value ?? []; + const { retentionPolicies } = useRetentionPolicies(datasource); const allTagKeys = useMemo(async () => { const tagKeys = (await getTagKeysForMeasurementAndTags(datasource, [], measurement, policy)).map( diff --git a/public/app/plugins/datasource/influxdb/module.ts b/public/app/plugins/datasource/influxdb/module.ts index da229451278..c293c017d6f 100644 --- a/public/app/plugins/datasource/influxdb/module.ts +++ b/public/app/plugins/datasource/influxdb/module.ts @@ -2,7 +2,7 @@ import { DataSourcePlugin } from '@grafana/data'; import ConfigEditor from './components/editor/config/ConfigEditor'; import { QueryEditor } from './components/editor/query/QueryEditor'; -import InfluxStartPage from './components/editor/query/influxql/InfluxStartPage'; +import { InfluxStartPage } from './components/editor/query/influxql/InfluxStartPage'; import VariableQueryEditor from './components/editor/variable/VariableQueryEditor'; import InfluxDatasource from './datasource'; diff --git a/public/app/plugins/datasource/influxdb/specs/mocks.ts b/public/app/plugins/datasource/influxdb/specs/mocks.ts index 9402f08aa44..72c01d4453a 100644 --- a/public/app/plugins/datasource/influxdb/specs/mocks.ts +++ b/public/app/plugins/datasource/influxdb/specs/mocks.ts @@ -58,6 +58,6 @@ export function getMockDSInstanceSettings(): DataSourceInstanceSettings