diff --git a/packages/grafana-prometheus/src/components/PromExploreExtraField.test.tsx b/packages/grafana-prometheus/src/components/PromExploreExtraField.test.tsx index 881cd1c0e12..4c22e2f16f2 100644 --- a/packages/grafana-prometheus/src/components/PromExploreExtraField.test.tsx +++ b/packages/grafana-prometheus/src/components/PromExploreExtraField.test.tsx @@ -4,7 +4,11 @@ import React from 'react'; import { PrometheusDatasource } from '../datasource'; import { PromQuery } from '../types'; -import { PromExploreExtraField, PromExploreExtraFieldProps, testIds } from './PromExploreExtraField'; +import { + PromExploreExtraField, + PromExploreExtraFieldProps, + promExploreExtraFieldTestIds, +} from './PromExploreExtraField'; const setup = (propOverrides?: PromExploreExtraFieldProps) => { const query = { exemplar: false } as PromQuery; @@ -27,11 +31,11 @@ const setup = (propOverrides?: PromExploreExtraFieldProps) => { describe('PromExploreExtraField', () => { it('should render step field', () => { setup(); - expect(screen.getByTestId(testIds.stepField)).toBeInTheDocument(); + expect(screen.getByTestId(promExploreExtraFieldTestIds.stepField)).toBeInTheDocument(); }); it('should render query type field', () => { setup(); - expect(screen.getByTestId(testIds.queryTypeField)).toBeInTheDocument(); + expect(screen.getByTestId(promExploreExtraFieldTestIds.queryTypeField)).toBeInTheDocument(); }); }); diff --git a/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx b/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx index f4bc23d0e4d..c9ad0a79e36 100644 --- a/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx +++ b/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx @@ -49,10 +49,14 @@ export const PromExploreExtraField = memo(({ query, datasource, onChange, onRunQ const onQueryTypeChange = getQueryTypeChangeHandler(query, onChange); return ( -
+
{/*Query type field*/}
{/*Step field*/}
); } -export const testIds = { +export const alertingTestIds = { editor: 'prom-editor-cloud-alerting', }; diff --git a/packages/grafana-prometheus/src/components/index.ts b/packages/grafana-prometheus/src/components/index.ts new file mode 100644 index 00000000000..41ffed43e72 --- /dev/null +++ b/packages/grafana-prometheus/src/components/index.ts @@ -0,0 +1,10 @@ +export * from './AnnotationQueryEditor'; +export * from './PromCheatSheet'; +export * from './PrometheusMetricsBrowser'; +export * from './PromExemplarField'; +export * from './PromExploreExtraField'; +export * from './PromQueryEditorByApp'; +export * from './PromQueryEditorForAlerting'; +export * from './PromQueryField'; +export * from './types'; +export * from './VariableQueryEditor'; diff --git a/packages/grafana-prometheus/src/index.ts b/packages/grafana-prometheus/src/index.ts index 75a11149dcc..db67923961f 100644 --- a/packages/grafana-prometheus/src/index.ts +++ b/packages/grafana-prometheus/src/index.ts @@ -1 +1,16 @@ +export * from './components'; export * from './configuration'; +export * from './querybuilder'; + +export * from './add_label_to_query'; +export * from './dataquery.gen'; +export * from './datasource'; +export * from './language_provider'; +export * from './language_utils'; +export * from './metric_find_query'; +export * from './promql'; +export * from './query_hints'; +export * from './result_transformer'; +export * from './tracking'; +export * from './types'; +export * from './variables'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/LabelFilterItem.tsx b/packages/grafana-prometheus/src/querybuilder/components/LabelFilterItem.tsx index d0275cda117..85b2ccd0535 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/LabelFilterItem.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/LabelFilterItem.tsx @@ -9,7 +9,7 @@ import { AsyncSelect, Select } from '@grafana/ui'; import { truncateResult } from '../../language_utils'; import { QueryBuilderLabelFilter } from '../shared/types'; -export interface Props { +export interface LabelFilterItemProps { defaultOp: string; item: Partial; onChange: (value: QueryBuilderLabelFilter) => void; @@ -33,7 +33,7 @@ export function LabelFilterItem({ invalidValue, getLabelValuesAutofillSuggestions, debounceDuration, -}: Props) { +}: LabelFilterItemProps) { const [state, setState] = useState<{ labelNames?: SelectableValue[]; labelValues?: SelectableValue[]; diff --git a/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx index 83f500a7711..fcd1b06b72a 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx @@ -5,7 +5,7 @@ import React, { ComponentProps } from 'react'; import { selectOptionInTest } from '../../gcopypaste/test/helpers/selectOptionInTest'; import { getLabelSelects } from '../testUtils'; -import { LabelFilters, MISSING_LABEL_FILTER_ERROR_MESSAGE, Props } from './LabelFilters'; +import { LabelFilters, MISSING_LABEL_FILTER_ERROR_MESSAGE, LabelFiltersProps } from './LabelFilters'; describe('LabelFilters', () => { it('renders empty input without labels', async () => { @@ -131,7 +131,7 @@ describe('LabelFilters', () => { }); function setup(propOverrides?: Partial>) { - const defaultProps: Props = { + const defaultProps: LabelFiltersProps = { onChange: jest.fn(), getLabelValuesAutofillSuggestions: async (query: string, labelName?: string) => [ { label: 'bar', value: 'bar' }, diff --git a/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.tsx b/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.tsx index 59c98310f57..09f5fd1d822 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.tsx @@ -12,7 +12,7 @@ import { LabelFilterItem } from './LabelFilterItem'; export const MISSING_LABEL_FILTER_ERROR_MESSAGE = 'Select at least 1 label filter (label and value)'; -export interface Props { +export interface LabelFiltersProps { labelsFilters: QueryBuilderLabelFilter[]; onChange: (labelFilters: Array>) => void; onGetLabelNames: (forLabel: Partial) => Promise; @@ -33,7 +33,7 @@ export function LabelFilters({ getLabelValuesAutofillSuggestions, debounceDuration, variableEditor, -}: Props) { +}: LabelFiltersProps) { const defaultOp = '='; const [items, setItems] = useState>>([{ op: defaultOp }]); diff --git a/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.test.tsx index 479990c6867..a0561768837 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.test.tsx @@ -11,7 +11,7 @@ import { formatPrometheusLabelFilters, formatPrometheusLabelFiltersToString, MetricSelect, - Props, + MetricSelectProps, } from './MetricSelect'; const instanceSettings = { @@ -48,7 +48,7 @@ dataSourceMock.metricFindQuery = jest.fn((query: string) => { ); }); -const props: Props = { +const props: MetricSelectProps = { labelsFilters: [], datasource: dataSourceMock, query: { diff --git a/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.tsx b/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.tsx index ef16fe9bd4d..baa54b5bd64 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.tsx @@ -33,7 +33,7 @@ import { tracking } from './metrics-modal/state/helpers'; // We are matching words split with space const splitSeparator = ' '; -export interface Props { +export interface MetricSelectProps { metricLookupDisabled: boolean; query: PromVisualQuery; onChange: (query: PromVisualQuery) => void; @@ -55,7 +55,7 @@ export function MetricSelect({ metricLookupDisabled, onBlur, variableEditor, -}: Props) { +}: MetricSelectProps) { const styles = useStyles2(getStyles); const [state, setState] = useState<{ metrics?: Array>; diff --git a/packages/grafana-prometheus/src/querybuilder/components/NestedQuery.tsx b/packages/grafana-prometheus/src/querybuilder/components/NestedQuery.tsx index 039ba43b3f6..ecba5898454 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/NestedQuery.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/NestedQuery.tsx @@ -11,7 +11,7 @@ import { PromVisualQueryBinary } from '../types'; import { PromQueryBuilder } from './PromQueryBuilder'; -export interface Props { +export interface NestedQueryProps { nestedQuery: PromVisualQueryBinary; datasource: PrometheusDatasource; index: number; @@ -21,7 +21,7 @@ export interface Props { showExplain: boolean; } -export const NestedQuery = React.memo((props) => { +export const NestedQuery = React.memo((props) => { const { nestedQuery, index, datasource, onChange, onRemove, onRunQuery, showExplain } = props; const styles = useStyles2(getStyles); diff --git a/packages/grafana-prometheus/src/querybuilder/components/NestedQueryList.tsx b/packages/grafana-prometheus/src/querybuilder/components/NestedQueryList.tsx index 0dfb5ed75c4..fb9e60229fe 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/NestedQueryList.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/NestedQueryList.tsx @@ -7,7 +7,7 @@ import { PromVisualQuery, PromVisualQueryBinary } from '../types'; import { NestedQuery } from './NestedQuery'; -export interface Props { +export interface NestedQueryListProps { query: PromVisualQuery; datasource: PrometheusDatasource; onChange: (query: PromVisualQuery) => void; @@ -15,7 +15,7 @@ export interface Props { showExplain: boolean; } -export function NestedQueryList(props: Props) { +export function NestedQueryList(props: NestedQueryListProps) { const { query, datasource, onChange, onRunQuery, showExplain } = props; const nestedQueries = query.binaryQueries ?? []; diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx index 44b71460c72..1a34a75b985 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx @@ -27,7 +27,7 @@ import { PromQail } from './promQail/PromQail'; import { QueryAssistantButton } from './promQail/QueryAssistantButton'; import { isLLMPluginEnabled } from './promQail/state/helpers'; -export interface Props { +export interface PromQueryBuilderProps { query: PromVisualQuery; datasource: PrometheusDatasource; onChange: (update: PromVisualQuery) => void; @@ -40,7 +40,7 @@ export interface Props { // AI/ML + Prometheus const prometheusPromQAIL = config.featureToggles.prometheusPromQAIL; -export const PromQueryBuilder = React.memo((props) => { +export const PromQueryBuilder = React.memo((props) => { const { datasource, query, onChange, onRunQuery, data, showExplain } = props; const [highlightedOp, setHighlightedOp] = useState(); const [showDrawer, setShowDrawer] = useState(false); diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.tsx index 43968f3a128..46d3dc05625 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.tsx @@ -14,7 +14,7 @@ import { PromQueryBuilder } from './PromQueryBuilder'; import { QueryPreview } from './QueryPreview'; import { getSettings, MetricsModalSettings } from './metrics-modal/state/state'; -export interface Props { +export interface PromQueryBuilderContainerProps { query: PromQuery; datasource: PrometheusDatasource; onChange: (update: PromQuery) => void; @@ -33,7 +33,7 @@ const prometheusMetricEncyclopedia = config.featureToggles.prometheusMetricEncyc /** * This component is here just to contain the translation logic between string query and the visual query builder model. */ -export function PromQueryBuilderContainer(props: Props) { +export function PromQueryBuilderContainer(props: PromQueryBuilderContainerProps) { const { query, onChange, onRunQuery, datasource, data, showExplain } = props; const [state, dispatch] = useReducer(stateSlice.reducer, { expr: query.expr }); // Only rebuild visual query if expr changes from outside diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx index c15fbc03505..38389fbc6e4 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx @@ -12,11 +12,11 @@ import { PromVisualQuery } from '../types'; export const EXPLAIN_LABEL_FILTER_CONTENT = 'Fetch all series matching metric name and label filters.'; -export interface Props { +export interface PromQueryBuilderExplainedProps { query: string; } -export const PromQueryBuilderExplained = React.memo(({ query }) => { +export const PromQueryBuilderExplained = React.memo(({ query }) => { const visQuery = buildVisualQueryFromString(query || '').query; const lang = { grammar: promqlGrammar, name: 'promql' }; diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.tsx index 54d860ee139..5a6b8273799 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.tsx @@ -22,113 +22,115 @@ export interface UIOptions { resolution: boolean; } -export interface Props { +export interface PromQueryBuilderOptionsProps { query: PromQuery; app?: CoreApp; onChange: (update: PromQuery) => void; onRunQuery: () => void; } -export const PromQueryBuilderOptions = React.memo(({ query, app, onChange, onRunQuery }) => { - const onChangeFormat = (value: SelectableValue) => { - onChange({ ...query, format: value.value }); - onRunQuery(); - }; +export const PromQueryBuilderOptions = React.memo( + ({ query, app, onChange, onRunQuery }) => { + const onChangeFormat = (value: SelectableValue) => { + onChange({ ...query, format: value.value }); + onRunQuery(); + }; - const onChangeStep = (evt: React.FormEvent) => { - onChange({ ...query, interval: evt.currentTarget.value }); - onRunQuery(); - }; + const onChangeStep = (evt: React.FormEvent) => { + onChange({ ...query, interval: evt.currentTarget.value }); + onRunQuery(); + }; - const queryTypeOptions = getQueryTypeOptions( - app === CoreApp.Explore || app === CoreApp.Correlations || app === CoreApp.PanelEditor - ); + const queryTypeOptions = getQueryTypeOptions( + app === CoreApp.Explore || app === CoreApp.Correlations || app === CoreApp.PanelEditor + ); - const onQueryTypeChange = getQueryTypeChangeHandler(query, onChange); + const onQueryTypeChange = getQueryTypeChangeHandler(query, onChange); - const onExemplarChange = (event: SyntheticEvent) => { - const isEnabled = event.currentTarget.checked; - onChange({ ...query, exemplar: isEnabled }); - onRunQuery(); - }; + const onExemplarChange = (event: SyntheticEvent) => { + const isEnabled = event.currentTarget.checked; + onChange({ ...query, exemplar: isEnabled }); + onRunQuery(); + }; - const onIntervalFactorChange = (value: SelectableValue) => { - onChange({ ...query, intervalFactor: value.value }); - onRunQuery(); - }; + const onIntervalFactorChange = (value: SelectableValue) => { + onChange({ ...query, intervalFactor: value.value }); + onRunQuery(); + }; - const formatOption = FORMAT_OPTIONS.find((option) => option.value === query.format) || FORMAT_OPTIONS[0]; - const queryTypeValue = getQueryTypeValue(query); - const queryTypeLabel = queryTypeOptions.find((x) => x.value === queryTypeValue)!.label; + const formatOption = FORMAT_OPTIONS.find((option) => option.value === query.format) || FORMAT_OPTIONS[0]; + const queryTypeValue = getQueryTypeValue(query); + const queryTypeLabel = queryTypeOptions.find((x) => x.value === queryTypeValue)!.label; - return ( - -
- - onChange({ ...query, legendFormat })} - onRunQuery={onRunQuery} - /> - - An additional lower limit for the step parameter of the Prometheus query and for the{' '} - $__interval and $__rate_interval variables. - - } + return ( + +
+ - onChange({ ...query, legendFormat })} + onRunQuery={onRunQuery} /> - - - option.value === query.intervalFactor)} + data-testid={selectors.components.DataSource.Prometheus.queryEditor.format} + value={formatOption} + allowCustomValue + onChange={onChangeFormat} + options={FORMAT_OPTIONS} /> - )} - -
-
- ); -}); + + + + {shouldShowExemplarSwitch(query, app) && ( + + + + )} + {query.intervalFactor && query.intervalFactor > 1 && ( + + x.value === mode)} - /> - )} - - - ); -}); + return ( + + <> + {mode === LegendFormatMode.Custom && ( + + )} + {mode !== LegendFormatMode.Custom && ( + { @@ -225,7 +225,7 @@ export const MetricsModal = (props: MetricsModalProps) => { {state.hasMetadata && (
{ variant="secondary" size="md" onClick={() => dispatch(showAdditionalSettings())} - data-testid={testIds.showAdditionalSettings} + data-testid={metricsModaltestIds.showAdditionalSettings} className={styles.noBorder} > Additional Settings @@ -301,7 +301,7 @@ export const MetricsModal = (props: MetricsModalProps) => {

# Results per page 

{ ); }; -export const testIds = { +export const metricsModaltestIds = { metricModal: 'metric-modal', searchMetric: 'search-metric', searchWithMetadata: 'search-with-metadata', diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/index.ts b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/index.ts new file mode 100644 index 00000000000..3f073bdca3f --- /dev/null +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/index.ts @@ -0,0 +1 @@ +export * from './MetricsModal'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.test.tsx index 57f6efa2236..dec1d39a4c0 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.test.tsx @@ -10,7 +10,7 @@ import { EmptyLanguageProviderMock } from '../../../language_provider.mock'; import { PromOptions } from '../../../types'; import { PromVisualQuery } from '../../types'; -import { PromQail, testIds } from './PromQail'; +import { PromQail, queryAssistanttestIds } from './PromQail'; // don't care about interaction tracking in our unit tests jest.mock('@grafana/runtime', () => ({ @@ -56,7 +56,7 @@ describe('PromQail', () => { expect(screen.getByText('Do you know what you want to query?')).toBeInTheDocument(); }); - const aiPrompt = screen.getByTestId(testIds.clickForAi); + const aiPrompt = screen.getByTestId(queryAssistanttestIds.clickForAi); userEvent.click(aiPrompt); @@ -75,7 +75,7 @@ describe('PromQail', () => { expect(screen.getByText('Do you know what you want to query?')).toBeInTheDocument(); }); - const historicalPrompt = screen.getByTestId(testIds.clickForHistorical); + const historicalPrompt = screen.getByTestId(queryAssistanttestIds.clickForHistorical); userEvent.click(historicalPrompt); @@ -142,7 +142,7 @@ function setup(query: PromVisualQuery) { } function clickSecurityButton() { - const securityInfoButton = screen.getByTestId(testIds.securityInfoButton); + const securityInfoButton = screen.getByTestId(queryAssistanttestIds.securityInfoButton); userEvent.click(securityInfoButton); } diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.tsx b/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.tsx index 940abb80b5b..43d07d1a553 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.tsx @@ -125,7 +125,7 @@ export const PromQail = (props: PromQailProps) => { fill="solid" variant="primary" onClick={() => dispatch(showStartingMessage(false))} - data-testid={testIds.securityInfoButton} + data-testid={queryAssistanttestIds.securityInfoButton} > Continue @@ -181,7 +181,7 @@ export const PromQail = (props: PromQailProps) => { className={styles.leftButton} fill="solid" variant="secondary" - data-testid={testIds.clickForHistorical} + data-testid={queryAssistanttestIds.clickForHistorical} onClick={() => { const isLoading = true; const suggestionType = SuggestionType.Historical; @@ -198,7 +198,7 @@ export const PromQail = (props: PromQailProps) => {