Prometheus: Frontend library exports (#81909)

* fix components folders for exports

* export files in the components folder

* export metrics modal and fix exports

* export promquail and fix exports

* export querybuilder/components and fix exports

* export querybuilder

* main index file exports

* run prettier
This commit is contained in:
Brendan O'Handley
2024-02-06 08:27:09 -06:00
committed by GitHub
parent 32a7aa33b8
commit ec0eb8fd79
30 changed files with 285 additions and 212 deletions

View File

@ -4,7 +4,11 @@ import React from 'react';
import { PrometheusDatasource } from '../datasource'; import { PrometheusDatasource } from '../datasource';
import { PromQuery } from '../types'; import { PromQuery } from '../types';
import { PromExploreExtraField, PromExploreExtraFieldProps, testIds } from './PromExploreExtraField'; import {
PromExploreExtraField,
PromExploreExtraFieldProps,
promExploreExtraFieldTestIds,
} from './PromExploreExtraField';
const setup = (propOverrides?: PromExploreExtraFieldProps) => { const setup = (propOverrides?: PromExploreExtraFieldProps) => {
const query = { exemplar: false } as PromQuery; const query = { exemplar: false } as PromQuery;
@ -27,11 +31,11 @@ const setup = (propOverrides?: PromExploreExtraFieldProps) => {
describe('PromExploreExtraField', () => { describe('PromExploreExtraField', () => {
it('should render step field', () => { it('should render step field', () => {
setup(); setup();
expect(screen.getByTestId(testIds.stepField)).toBeInTheDocument(); expect(screen.getByTestId(promExploreExtraFieldTestIds.stepField)).toBeInTheDocument();
}); });
it('should render query type field', () => { it('should render query type field', () => {
setup(); setup();
expect(screen.getByTestId(testIds.queryTypeField)).toBeInTheDocument(); expect(screen.getByTestId(promExploreExtraFieldTestIds.queryTypeField)).toBeInTheDocument();
}); });
}); });

View File

@ -49,10 +49,14 @@ export const PromExploreExtraField = memo(({ query, datasource, onChange, onRunQ
const onQueryTypeChange = getQueryTypeChangeHandler(query, onChange); const onQueryTypeChange = getQueryTypeChangeHandler(query, onChange);
return ( return (
<div aria-label="Prometheus extra field" className="gf-form-inline" data-testid={testIds.extraFieldEditor}> <div
aria-label="Prometheus extra field"
className="gf-form-inline"
data-testid={promExploreExtraFieldTestIds.extraFieldEditor}
>
{/*Query type field*/} {/*Query type field*/}
<div <div
data-testid={testIds.queryTypeField} data-testid={promExploreExtraFieldTestIds.queryTypeField}
className={cx( className={cx(
'gf-form explore-input-margin', 'gf-form explore-input-margin',
css` css`
@ -71,7 +75,7 @@ export const PromExploreExtraField = memo(({ query, datasource, onChange, onRunQ
</div> </div>
{/*Step field*/} {/*Step field*/}
<div <div
data-testid={testIds.stepField} data-testid={promExploreExtraFieldTestIds.stepField}
className={cx( className={cx(
'gf-form', 'gf-form',
css` css`
@ -134,7 +138,7 @@ export function getQueryTypeChangeHandler(query: PromQuery, onChange: (update: P
}; };
} }
export const testIds = { export const promExploreExtraFieldTestIds = {
extraFieldEditor: 'prom-editor-extra-field', extraFieldEditor: 'prom-editor-extra-field',
stepField: 'prom-editor-extra-field-step', stepField: 'prom-editor-extra-field-step',
queryTypeField: 'prom-editor-extra-field-query-type', queryTypeField: 'prom-editor-extra-field-query-type',

View File

@ -7,7 +7,7 @@ import { CoreApp } from '@grafana/data';
import { PrometheusDatasource } from '../datasource'; import { PrometheusDatasource } from '../datasource';
import { PromQueryEditorByApp } from './PromQueryEditorByApp'; import { PromQueryEditorByApp } from './PromQueryEditorByApp';
import { testIds as alertingTestIds } from './PromQueryEditorForAlerting'; import { alertingTestIds } from './PromQueryEditorForAlerting';
import { Props } from './monaco-query-field/MonacoQueryFieldProps'; import { Props } from './monaco-query-field/MonacoQueryFieldProps';
// the monaco-based editor uses lazy-loading and that does not work // the monaco-based editor uses lazy-loading and that does not work

View File

@ -15,11 +15,11 @@ export function PromQueryEditorForAlerting(props: PromQueryEditorProps) {
history={[]} history={[]}
range={range} range={range}
data={data} data={data}
data-testid={testIds.editor} data-testid={alertingTestIds.editor}
/> />
); );
} }
export const testIds = { export const alertingTestIds = {
editor: 'prom-editor-cloud-alerting', editor: 'prom-editor-cloud-alerting',
}; };

View File

@ -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';

View File

@ -1 +1,16 @@
export * from './components';
export * from './configuration'; 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';

View File

@ -9,7 +9,7 @@ import { AsyncSelect, Select } from '@grafana/ui';
import { truncateResult } from '../../language_utils'; import { truncateResult } from '../../language_utils';
import { QueryBuilderLabelFilter } from '../shared/types'; import { QueryBuilderLabelFilter } from '../shared/types';
export interface Props { export interface LabelFilterItemProps {
defaultOp: string; defaultOp: string;
item: Partial<QueryBuilderLabelFilter>; item: Partial<QueryBuilderLabelFilter>;
onChange: (value: QueryBuilderLabelFilter) => void; onChange: (value: QueryBuilderLabelFilter) => void;
@ -33,7 +33,7 @@ export function LabelFilterItem({
invalidValue, invalidValue,
getLabelValuesAutofillSuggestions, getLabelValuesAutofillSuggestions,
debounceDuration, debounceDuration,
}: Props) { }: LabelFilterItemProps) {
const [state, setState] = useState<{ const [state, setState] = useState<{
labelNames?: SelectableValue[]; labelNames?: SelectableValue[];
labelValues?: SelectableValue[]; labelValues?: SelectableValue[];

View File

@ -5,7 +5,7 @@ import React, { ComponentProps } from 'react';
import { selectOptionInTest } from '../../gcopypaste/test/helpers/selectOptionInTest'; import { selectOptionInTest } from '../../gcopypaste/test/helpers/selectOptionInTest';
import { getLabelSelects } from '../testUtils'; 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', () => { describe('LabelFilters', () => {
it('renders empty input without labels', async () => { it('renders empty input without labels', async () => {
@ -131,7 +131,7 @@ describe('LabelFilters', () => {
}); });
function setup(propOverrides?: Partial<ComponentProps<typeof LabelFilters>>) { function setup(propOverrides?: Partial<ComponentProps<typeof LabelFilters>>) {
const defaultProps: Props = { const defaultProps: LabelFiltersProps = {
onChange: jest.fn(), onChange: jest.fn(),
getLabelValuesAutofillSuggestions: async (query: string, labelName?: string) => [ getLabelValuesAutofillSuggestions: async (query: string, labelName?: string) => [
{ label: 'bar', value: 'bar' }, { label: 'bar', value: 'bar' },

View File

@ -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 const MISSING_LABEL_FILTER_ERROR_MESSAGE = 'Select at least 1 label filter (label and value)';
export interface Props { export interface LabelFiltersProps {
labelsFilters: QueryBuilderLabelFilter[]; labelsFilters: QueryBuilderLabelFilter[];
onChange: (labelFilters: Array<Partial<QueryBuilderLabelFilter>>) => void; onChange: (labelFilters: Array<Partial<QueryBuilderLabelFilter>>) => void;
onGetLabelNames: (forLabel: Partial<QueryBuilderLabelFilter>) => Promise<SelectableValue[]>; onGetLabelNames: (forLabel: Partial<QueryBuilderLabelFilter>) => Promise<SelectableValue[]>;
@ -33,7 +33,7 @@ export function LabelFilters({
getLabelValuesAutofillSuggestions, getLabelValuesAutofillSuggestions,
debounceDuration, debounceDuration,
variableEditor, variableEditor,
}: Props) { }: LabelFiltersProps) {
const defaultOp = '='; const defaultOp = '=';
const [items, setItems] = useState<Array<Partial<QueryBuilderLabelFilter>>>([{ op: defaultOp }]); const [items, setItems] = useState<Array<Partial<QueryBuilderLabelFilter>>>([{ op: defaultOp }]);

View File

@ -11,7 +11,7 @@ import {
formatPrometheusLabelFilters, formatPrometheusLabelFilters,
formatPrometheusLabelFiltersToString, formatPrometheusLabelFiltersToString,
MetricSelect, MetricSelect,
Props, MetricSelectProps,
} from './MetricSelect'; } from './MetricSelect';
const instanceSettings = { const instanceSettings = {
@ -48,7 +48,7 @@ dataSourceMock.metricFindQuery = jest.fn((query: string) => {
); );
}); });
const props: Props = { const props: MetricSelectProps = {
labelsFilters: [], labelsFilters: [],
datasource: dataSourceMock, datasource: dataSourceMock,
query: { query: {

View File

@ -33,7 +33,7 @@ import { tracking } from './metrics-modal/state/helpers';
// We are matching words split with space // We are matching words split with space
const splitSeparator = ' '; const splitSeparator = ' ';
export interface Props { export interface MetricSelectProps {
metricLookupDisabled: boolean; metricLookupDisabled: boolean;
query: PromVisualQuery; query: PromVisualQuery;
onChange: (query: PromVisualQuery) => void; onChange: (query: PromVisualQuery) => void;
@ -55,7 +55,7 @@ export function MetricSelect({
metricLookupDisabled, metricLookupDisabled,
onBlur, onBlur,
variableEditor, variableEditor,
}: Props) { }: MetricSelectProps) {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const [state, setState] = useState<{ const [state, setState] = useState<{
metrics?: Array<SelectableValue<any>>; metrics?: Array<SelectableValue<any>>;

View File

@ -11,7 +11,7 @@ import { PromVisualQueryBinary } from '../types';
import { PromQueryBuilder } from './PromQueryBuilder'; import { PromQueryBuilder } from './PromQueryBuilder';
export interface Props { export interface NestedQueryProps {
nestedQuery: PromVisualQueryBinary; nestedQuery: PromVisualQueryBinary;
datasource: PrometheusDatasource; datasource: PrometheusDatasource;
index: number; index: number;
@ -21,7 +21,7 @@ export interface Props {
showExplain: boolean; showExplain: boolean;
} }
export const NestedQuery = React.memo<Props>((props) => { export const NestedQuery = React.memo<NestedQueryProps>((props) => {
const { nestedQuery, index, datasource, onChange, onRemove, onRunQuery, showExplain } = props; const { nestedQuery, index, datasource, onChange, onRemove, onRunQuery, showExplain } = props;
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);

View File

@ -7,7 +7,7 @@ import { PromVisualQuery, PromVisualQueryBinary } from '../types';
import { NestedQuery } from './NestedQuery'; import { NestedQuery } from './NestedQuery';
export interface Props { export interface NestedQueryListProps {
query: PromVisualQuery; query: PromVisualQuery;
datasource: PrometheusDatasource; datasource: PrometheusDatasource;
onChange: (query: PromVisualQuery) => void; onChange: (query: PromVisualQuery) => void;
@ -15,7 +15,7 @@ export interface Props {
showExplain: boolean; showExplain: boolean;
} }
export function NestedQueryList(props: Props) { export function NestedQueryList(props: NestedQueryListProps) {
const { query, datasource, onChange, onRunQuery, showExplain } = props; const { query, datasource, onChange, onRunQuery, showExplain } = props;
const nestedQueries = query.binaryQueries ?? []; const nestedQueries = query.binaryQueries ?? [];

View File

@ -27,7 +27,7 @@ import { PromQail } from './promQail/PromQail';
import { QueryAssistantButton } from './promQail/QueryAssistantButton'; import { QueryAssistantButton } from './promQail/QueryAssistantButton';
import { isLLMPluginEnabled } from './promQail/state/helpers'; import { isLLMPluginEnabled } from './promQail/state/helpers';
export interface Props { export interface PromQueryBuilderProps {
query: PromVisualQuery; query: PromVisualQuery;
datasource: PrometheusDatasource; datasource: PrometheusDatasource;
onChange: (update: PromVisualQuery) => void; onChange: (update: PromVisualQuery) => void;
@ -40,7 +40,7 @@ export interface Props {
// AI/ML + Prometheus // AI/ML + Prometheus
const prometheusPromQAIL = config.featureToggles.prometheusPromQAIL; const prometheusPromQAIL = config.featureToggles.prometheusPromQAIL;
export const PromQueryBuilder = React.memo<Props>((props) => { export const PromQueryBuilder = React.memo<PromQueryBuilderProps>((props) => {
const { datasource, query, onChange, onRunQuery, data, showExplain } = props; const { datasource, query, onChange, onRunQuery, data, showExplain } = props;
const [highlightedOp, setHighlightedOp] = useState<QueryBuilderOperation | undefined>(); const [highlightedOp, setHighlightedOp] = useState<QueryBuilderOperation | undefined>();
const [showDrawer, setShowDrawer] = useState<boolean>(false); const [showDrawer, setShowDrawer] = useState<boolean>(false);

View File

@ -14,7 +14,7 @@ import { PromQueryBuilder } from './PromQueryBuilder';
import { QueryPreview } from './QueryPreview'; import { QueryPreview } from './QueryPreview';
import { getSettings, MetricsModalSettings } from './metrics-modal/state/state'; import { getSettings, MetricsModalSettings } from './metrics-modal/state/state';
export interface Props { export interface PromQueryBuilderContainerProps {
query: PromQuery; query: PromQuery;
datasource: PrometheusDatasource; datasource: PrometheusDatasource;
onChange: (update: PromQuery) => void; 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. * 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 { query, onChange, onRunQuery, datasource, data, showExplain } = props;
const [state, dispatch] = useReducer(stateSlice.reducer, { expr: query.expr }); const [state, dispatch] = useReducer(stateSlice.reducer, { expr: query.expr });
// Only rebuild visual query if expr changes from outside // Only rebuild visual query if expr changes from outside

View File

@ -12,11 +12,11 @@ import { PromVisualQuery } from '../types';
export const EXPLAIN_LABEL_FILTER_CONTENT = 'Fetch all series matching metric name and label filters.'; export const EXPLAIN_LABEL_FILTER_CONTENT = 'Fetch all series matching metric name and label filters.';
export interface Props { export interface PromQueryBuilderExplainedProps {
query: string; query: string;
} }
export const PromQueryBuilderExplained = React.memo<Props>(({ query }) => { export const PromQueryBuilderExplained = React.memo<PromQueryBuilderExplainedProps>(({ query }) => {
const visQuery = buildVisualQueryFromString(query || '').query; const visQuery = buildVisualQueryFromString(query || '').query;
const lang = { grammar: promqlGrammar, name: 'promql' }; const lang = { grammar: promqlGrammar, name: 'promql' };

View File

@ -22,14 +22,15 @@ export interface UIOptions {
resolution: boolean; resolution: boolean;
} }
export interface Props { export interface PromQueryBuilderOptionsProps {
query: PromQuery; query: PromQuery;
app?: CoreApp; app?: CoreApp;
onChange: (update: PromQuery) => void; onChange: (update: PromQuery) => void;
onRunQuery: () => void; onRunQuery: () => void;
} }
export const PromQueryBuilderOptions = React.memo<Props>(({ query, app, onChange, onRunQuery }) => { export const PromQueryBuilderOptions = React.memo<PromQueryBuilderOptionsProps>(
({ query, app, onChange, onRunQuery }) => {
const onChangeFormat = (value: SelectableValue<PromQueryFormat>) => { const onChangeFormat = (value: SelectableValue<PromQueryFormat>) => {
onChange({ ...query, format: value.value }); onChange({ ...query, format: value.value });
onRunQuery(); onRunQuery();
@ -128,7 +129,8 @@ export const PromQueryBuilderOptions = React.memo<Props>(({ query, app, onChange
</div> </div>
</EditorRow> </EditorRow>
); );
}); }
);
function shouldShowExemplarSwitch(query: PromQuery, app?: CoreApp) { function shouldShowExemplarSwitch(query: PromQuery, app?: CoreApp) {
if (app === CoreApp.UnifiedAlerting || !query.range) { if (app === CoreApp.UnifiedAlerting || !query.range) {

View File

@ -10,11 +10,11 @@ import { PromQueryEditorProps } from '../../components/types';
import { PromQueryBuilderExplained } from './PromQueryBuilderExplained'; import { PromQueryBuilderExplained } from './PromQueryBuilderExplained';
type Props = PromQueryEditorProps & { type PromQueryCodeEditorProps = PromQueryEditorProps & {
showExplain: boolean; showExplain: boolean;
}; };
export function PromQueryCodeEditor(props: Props) { export function PromQueryCodeEditor(props: PromQueryCodeEditorProps) {
const { query, datasource, range, onRunQuery, onChange, data, app, showExplain } = props; const { query, datasource, range, onRunQuery, onChange, data, app, showExplain } = props;
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);

View File

@ -7,7 +7,7 @@ import { AutoSizeInput, Select } from '@grafana/ui';
import { LegendFormatMode } from '../../types'; import { LegendFormatMode } from '../../types';
export interface Props { export interface PromQueryLegendEditorProps {
legendFormat: string | undefined; legendFormat: string | undefined;
onChange: (legendFormat: string) => void; onChange: (legendFormat: string) => void;
onRunQuery: () => void; onRunQuery: () => void;
@ -26,7 +26,8 @@ const legendModeOptions = [
/** /**
* Tests for this component are on the parent level (PromQueryBuilderOptions). * Tests for this component are on the parent level (PromQueryBuilderOptions).
*/ */
export const PromQueryLegendEditor = React.memo<Props>(({ legendFormat, onChange, onRunQuery }) => { export const PromQueryLegendEditor = React.memo<PromQueryLegendEditorProps>(
({ legendFormat, onChange, onRunQuery }) => {
const mode = getLegendMode(legendFormat); const mode = getLegendMode(legendFormat);
const inputRef = useRef<HTMLInputElement | null>(null); const inputRef = useRef<HTMLInputElement | null>(null);
@ -92,7 +93,8 @@ export const PromQueryLegendEditor = React.memo<Props>(({ legendFormat, onChange
</> </>
</EditorField> </EditorField>
); );
}); }
);
PromQueryLegendEditor.displayName = 'PromQueryLegendEditor'; PromQueryLegendEditor.displayName = 'PromQueryLegendEditor';

View File

@ -5,11 +5,11 @@ import { EditorFieldGroup, EditorRow } from '@grafana/experimental';
import promqlGrammar from '../../promql'; import promqlGrammar from '../../promql';
import { RawQuery } from '../shared/RawQuery'; import { RawQuery } from '../shared/RawQuery';
export interface Props { export interface QueryPreviewProps {
query: string; query: string;
} }
export function QueryPreview({ query }: Props) { export function QueryPreview({ query }: QueryPreviewProps) {
if (!query) { if (!query) {
return null; return null;
} }

View File

@ -0,0 +1,17 @@
export * from './LabelFilterItem';
export * from './LabelFilters';
export * from './LabelParamEditor';
export * from './MetricSelect';
export * from './MetricsLabelsSection';
export * from './NestedQuery';
export * from './NestedQueryList';
export * from './PromQueryBuilder';
export * from './PromQueryBuilderContainer';
export * from './PromQueryBuilderExplained';
export * from './PromQueryBuilderOptions';
export * from './PromQueryCodeEditor';
export * from './PromQueryEditorSelector';
export * from './PromQueryLegendEditor';
export * from './QueryPreview';
export * from './metrics-modal';
export * from './promQail';

View File

@ -4,7 +4,7 @@ import React from 'react';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { Icon, Switch, Tooltip, useTheme2 } from '@grafana/ui'; import { Icon, Switch, Tooltip, useTheme2 } from '@grafana/ui';
import { testIds } from './MetricsModal'; import { metricsModaltestIds } from './MetricsModal';
import { placeholders } from './state/helpers'; import { placeholders } from './state/helpers';
import { MetricsModalState } from './state/state'; import { MetricsModalState } from './state/state';
@ -27,7 +27,7 @@ export function AdditionalSettings(props: AdditionalSettingsProps) {
<> <>
<div className={styles.selectItem}> <div className={styles.selectItem}>
<Switch <Switch
data-testid={testIds.searchWithMetadata} data-testid={metricsModaltestIds.searchWithMetadata}
value={state.fullMetaSearch} value={state.fullMetaSearch}
disabled={state.useBackend || !state.hasMetadata} disabled={state.useBackend || !state.hasMetadata}
onChange={() => onChangeFullMetaSearch()} onChange={() => onChangeFullMetaSearch()}
@ -47,7 +47,11 @@ export function AdditionalSettings(props: AdditionalSettingsProps) {
<div className={styles.selectItemLabel}>Disable text wrap</div> <div className={styles.selectItemLabel}>Disable text wrap</div>
</div> </div>
<div className={styles.selectItem}> <div className={styles.selectItem}>
<Switch data-testid={testIds.setUseBackend} value={state.useBackend} onChange={() => onChangeUseBackend()} /> <Switch
data-testid={metricsModaltestIds.setUseBackend}
value={state.useBackend}
onChange={() => onChangeUseBackend()}
/>
<div className={styles.selectItemLabel}>{placeholders.setUseBackend}&nbsp;</div> <div className={styles.selectItemLabel}>{placeholders.setUseBackend}&nbsp;</div>
<Tooltip <Tooltip
content={'Filter metric names by regex search, using an additional call on the Prometheus API.'} content={'Filter metric names by regex search, using an additional call on the Prometheus API.'}

View File

@ -10,7 +10,7 @@ import { EmptyLanguageProviderMock } from '../../../language_provider.mock';
import { PromOptions } from '../../../types'; import { PromOptions } from '../../../types';
import { PromVisualQuery } from '../../types'; import { PromVisualQuery } from '../../types';
import { MetricsModal, testIds } from './MetricsModal'; import { MetricsModal, metricsModaltestIds } from './MetricsModal';
// don't care about interaction tracking in our unit tests // don't care about interaction tracking in our unit tests
jest.mock('@grafana/runtime', () => ({ jest.mock('@grafana/runtime', () => ({
@ -117,7 +117,7 @@ describe('MetricsModal', () => {
it('shows results metrics per page chosen by the user', async () => { it('shows results metrics per page chosen by the user', async () => {
setup(defaultQuery, listOfMetrics); setup(defaultQuery, listOfMetrics);
const resultsPerPageInput = screen.getByTestId(testIds.resultsPerPage); const resultsPerPageInput = screen.getByTestId(metricsModaltestIds.resultsPerPage);
await userEvent.type(resultsPerPageInput, '12'); await userEvent.type(resultsPerPageInput, '12');
const metricInsideRange = screen.getByText('j'); const metricInsideRange = screen.getByText('j');
expect(metricInsideRange).toBeInTheDocument(); expect(metricInsideRange).toBeInTheDocument();
@ -130,7 +130,7 @@ describe('MetricsModal', () => {
// doesn't break on loading // doesn't break on loading
expect(screen.getByText('0')).toBeInTheDocument(); expect(screen.getByText('0')).toBeInTheDocument();
}); });
const resultsPerPageInput = screen.getByTestId(testIds.resultsPerPage); const resultsPerPageInput = screen.getByTestId(metricsModaltestIds.resultsPerPage);
// doesn't break on changing results per page // doesn't break on changing results per page
await userEvent.type(resultsPerPageInput, '11'); await userEvent.type(resultsPerPageInput, '11');
const metricInsideRange = screen.getByText('9'); const metricInsideRange = screen.getByText('9');
@ -149,7 +149,7 @@ describe('MetricsModal', () => {
expect(metricAll).toBeInTheDocument(); expect(metricAll).toBeInTheDocument();
expect(metricABucket).toBeInTheDocument(); expect(metricABucket).toBeInTheDocument();
}); });
const searchMetric = screen.getByTestId(testIds.searchMetric); const searchMetric = screen.getByTestId(metricsModaltestIds.searchMetric);
expect(searchMetric).toBeInTheDocument(); expect(searchMetric).toBeInTheDocument();
await userEvent.type(searchMetric, 'a_buck'); await userEvent.type(searchMetric, 'a_buck');
@ -169,15 +169,15 @@ describe('MetricsModal', () => {
expect(metricABucket).toBeInTheDocument(); expect(metricABucket).toBeInTheDocument();
}); });
const showSettingsButton = screen.getByTestId(testIds.showAdditionalSettings); const showSettingsButton = screen.getByTestId(metricsModaltestIds.showAdditionalSettings);
expect(showSettingsButton).toBeInTheDocument(); expect(showSettingsButton).toBeInTheDocument();
await userEvent.click(showSettingsButton); await userEvent.click(showSettingsButton);
const metadataSwitch = screen.getByTestId(testIds.searchWithMetadata); const metadataSwitch = screen.getByTestId(metricsModaltestIds.searchWithMetadata);
expect(metadataSwitch).toBeInTheDocument(); expect(metadataSwitch).toBeInTheDocument();
await userEvent.click(metadataSwitch); await userEvent.click(metadataSwitch);
const searchMetric = screen.getByTestId(testIds.searchMetric); const searchMetric = screen.getByTestId(metricsModaltestIds.searchMetric);
expect(searchMetric).toBeInTheDocument(); expect(searchMetric).toBeInTheDocument();
await userEvent.type(searchMetric, 'functions'); await userEvent.type(searchMetric, 'functions');

View File

@ -197,7 +197,7 @@ export const MetricsModal = (props: MetricsModalProps) => {
return ( return (
<Modal <Modal
data-testid={testIds.metricModal} data-testid={metricsModaltestIds.metricModal}
isOpen={isOpen} isOpen={isOpen}
title="Metrics explorer" title="Metrics explorer"
onDismiss={onClose} onDismiss={onClose}
@ -212,7 +212,7 @@ export const MetricsModal = (props: MetricsModalProps) => {
<div className={cx(styles.inputItem, styles.inputItemFirst)}> <div className={cx(styles.inputItem, styles.inputItemFirst)}>
<Input <Input
autoFocus={true} autoFocus={true}
data-testid={testIds.searchMetric} data-testid={metricsModaltestIds.searchMetric}
placeholder={placeholders.browse} placeholder={placeholders.browse}
value={state.fuzzySearchQuery} value={state.fuzzySearchQuery}
onInput={(e) => { onInput={(e) => {
@ -225,7 +225,7 @@ export const MetricsModal = (props: MetricsModalProps) => {
{state.hasMetadata && ( {state.hasMetadata && (
<div className={styles.inputItem}> <div className={styles.inputItem}>
<MultiSelect <MultiSelect
data-testid={testIds.selectType} data-testid={metricsModaltestIds.selectType}
inputId="my-select" inputId="my-select"
options={typeOptions} options={typeOptions}
value={state.selectedTypes} value={state.selectedTypes}
@ -249,7 +249,7 @@ export const MetricsModal = (props: MetricsModalProps) => {
variant="secondary" variant="secondary"
size="md" size="md"
onClick={() => dispatch(showAdditionalSettings())} onClick={() => dispatch(showAdditionalSettings())}
data-testid={testIds.showAdditionalSettings} data-testid={metricsModaltestIds.showAdditionalSettings}
className={styles.noBorder} className={styles.noBorder}
> >
Additional Settings Additional Settings
@ -301,7 +301,7 @@ export const MetricsModal = (props: MetricsModalProps) => {
<div className={styles.resultsPerPageWrapper}> <div className={styles.resultsPerPageWrapper}>
<p className={styles.resultsPerPageLabel}># Results per page&nbsp;</p> <p className={styles.resultsPerPageLabel}># Results per page&nbsp;</p>
<Input <Input
data-testid={testIds.resultsPerPage} data-testid={metricsModaltestIds.resultsPerPage}
value={calculateResultsPerPage(state.resultsPerPage, DEFAULT_RESULTS_PER_PAGE, MAXIMUM_RESULTS_PER_PAGE)} value={calculateResultsPerPage(state.resultsPerPage, DEFAULT_RESULTS_PER_PAGE, MAXIMUM_RESULTS_PER_PAGE)}
placeholder="results per page" placeholder="results per page"
width={10} width={10}
@ -323,7 +323,7 @@ export const MetricsModal = (props: MetricsModalProps) => {
); );
}; };
export const testIds = { export const metricsModaltestIds = {
metricModal: 'metric-modal', metricModal: 'metric-modal',
searchMetric: 'search-metric', searchMetric: 'search-metric',
searchWithMetadata: 'search-with-metadata', searchWithMetadata: 'search-with-metadata',

View File

@ -0,0 +1 @@
export * from './MetricsModal';

View File

@ -10,7 +10,7 @@ import { EmptyLanguageProviderMock } from '../../../language_provider.mock';
import { PromOptions } from '../../../types'; import { PromOptions } from '../../../types';
import { PromVisualQuery } 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 // don't care about interaction tracking in our unit tests
jest.mock('@grafana/runtime', () => ({ jest.mock('@grafana/runtime', () => ({
@ -56,7 +56,7 @@ describe('PromQail', () => {
expect(screen.getByText('Do you know what you want to query?')).toBeInTheDocument(); 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); userEvent.click(aiPrompt);
@ -75,7 +75,7 @@ describe('PromQail', () => {
expect(screen.getByText('Do you know what you want to query?')).toBeInTheDocument(); 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); userEvent.click(historicalPrompt);
@ -142,7 +142,7 @@ function setup(query: PromVisualQuery) {
} }
function clickSecurityButton() { function clickSecurityButton() {
const securityInfoButton = screen.getByTestId(testIds.securityInfoButton); const securityInfoButton = screen.getByTestId(queryAssistanttestIds.securityInfoButton);
userEvent.click(securityInfoButton); userEvent.click(securityInfoButton);
} }

View File

@ -125,7 +125,7 @@ export const PromQail = (props: PromQailProps) => {
fill="solid" fill="solid"
variant="primary" variant="primary"
onClick={() => dispatch(showStartingMessage(false))} onClick={() => dispatch(showStartingMessage(false))}
data-testid={testIds.securityInfoButton} data-testid={queryAssistanttestIds.securityInfoButton}
> >
Continue Continue
</Button> </Button>
@ -181,7 +181,7 @@ export const PromQail = (props: PromQailProps) => {
className={styles.leftButton} className={styles.leftButton}
fill="solid" fill="solid"
variant="secondary" variant="secondary"
data-testid={testIds.clickForHistorical} data-testid={queryAssistanttestIds.clickForHistorical}
onClick={() => { onClick={() => {
const isLoading = true; const isLoading = true;
const suggestionType = SuggestionType.Historical; const suggestionType = SuggestionType.Historical;
@ -198,7 +198,7 @@ export const PromQail = (props: PromQailProps) => {
<Button <Button
fill="solid" fill="solid"
variant="primary" variant="primary"
data-testid={testIds.clickForAi} data-testid={queryAssistanttestIds.clickForAi}
onClick={() => { onClick={() => {
reportInteraction('grafana_prometheus_promqail_know_what_you_want_to_query', { reportInteraction('grafana_prometheus_promqail_know_what_you_want_to_query', {
promVisualQuery: query, promVisualQuery: query,
@ -293,7 +293,7 @@ export const PromQail = (props: PromQailProps) => {
<Button <Button
fill="solid" fill="solid"
variant="primary" variant="primary"
data-testid={testIds.submitPrompt + idx} data-testid={queryAssistanttestIds.submitPrompt + idx}
onClick={() => { onClick={() => {
const newInteraction: Interaction = { const newInteraction: Interaction = {
...interaction, ...interaction,
@ -557,7 +557,7 @@ export const getStyles = (theme: GrafanaTheme2) => {
}; };
}; };
export const testIds = { export const queryAssistanttestIds = {
promQail: 'prom-qail', promQail: 'prom-qail',
securityInfoButton: 'security-info-button', securityInfoButton: 'security-info-button',
clickForHistorical: 'click-for-historical', clickForHistorical: 'click-for-historical',

View File

@ -5,7 +5,7 @@ import { Button, useTheme2 } from '@grafana/ui';
import { PromVisualQuery } from '../../types'; import { PromVisualQuery } from '../../types';
import { getStyles, testIds } from './PromQail'; import { getStyles, queryAssistanttestIds } from './PromQail';
import { QuerySuggestionItem } from './QuerySuggestionItem'; import { QuerySuggestionItem } from './QuerySuggestionItem';
import { QuerySuggestion, SuggestionType } from './types'; import { QuerySuggestion, SuggestionType } from './types';
@ -81,7 +81,7 @@ export function QuerySuggestionContainer(props: Props) {
updateHasNextInteraction(true); updateHasNextInteraction(true);
nextInteraction(); nextInteraction();
}} }}
data-testid={testIds.refinePrompt} data-testid={queryAssistanttestIds.refinePrompt}
fill="outline" fill="outline"
variant="secondary" variant="secondary"
size="md" size="md"

View File

@ -0,0 +1 @@
export * from './PromQail';

View File

@ -0,0 +1,13 @@
export * from './aggregations';
export * from './binaryScalarOperations';
export * from './operations';
export * from './operationUtils';
export * from './parsing';
export * from './parsingUtils';
export * from './PromQueryModeller';
export * from './QueryPattern';
export * from './QueryPatternsModal';
export * from './state';
export * from './testUtils';
export * from './types';
export * from './components';