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
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 285 additions and 212 deletions

View File

@ -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();
});
});

View File

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

View File

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

View File

@ -15,11 +15,11 @@ export function PromQueryEditorForAlerting(props: PromQueryEditorProps) {
history={[]}
range={range}
data={data}
data-testid={testIds.editor}
data-testid={alertingTestIds.editor}
/>
);
}
export const testIds = {
export const alertingTestIds = {
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 './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 { QueryBuilderLabelFilter } from '../shared/types';
export interface Props {
export interface LabelFilterItemProps {
defaultOp: string;
item: Partial<QueryBuilderLabelFilter>;
onChange: (value: QueryBuilderLabelFilter) => void;
@ -33,7 +33,7 @@ export function LabelFilterItem({
invalidValue,
getLabelValuesAutofillSuggestions,
debounceDuration,
}: Props) {
}: LabelFilterItemProps) {
const [state, setState] = useState<{
labelNames?: SelectableValue[];
labelValues?: SelectableValue[];

View File

@ -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<ComponentProps<typeof LabelFilters>>) {
const defaultProps: Props = {
const defaultProps: LabelFiltersProps = {
onChange: jest.fn(),
getLabelValuesAutofillSuggestions: async (query: string, labelName?: string) => [
{ 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 interface Props {
export interface LabelFiltersProps {
labelsFilters: QueryBuilderLabelFilter[];
onChange: (labelFilters: Array<Partial<QueryBuilderLabelFilter>>) => void;
onGetLabelNames: (forLabel: Partial<QueryBuilderLabelFilter>) => Promise<SelectableValue[]>;
@ -33,7 +33,7 @@ export function LabelFilters({
getLabelValuesAutofillSuggestions,
debounceDuration,
variableEditor,
}: Props) {
}: LabelFiltersProps) {
const defaultOp = '=';
const [items, setItems] = useState<Array<Partial<QueryBuilderLabelFilter>>>([{ op: defaultOp }]);

View File

@ -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: {

View File

@ -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<SelectableValue<any>>;

View File

@ -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>((props) => {
export const NestedQuery = React.memo<NestedQueryProps>((props) => {
const { nestedQuery, index, datasource, onChange, onRemove, onRunQuery, showExplain } = props;
const styles = useStyles2(getStyles);

View File

@ -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 ?? [];

View File

@ -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>((props) => {
export const PromQueryBuilder = React.memo<PromQueryBuilderProps>((props) => {
const { datasource, query, onChange, onRunQuery, data, showExplain } = props;
const [highlightedOp, setHighlightedOp] = useState<QueryBuilderOperation | undefined>();
const [showDrawer, setShowDrawer] = useState<boolean>(false);

View File

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

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 interface Props {
export interface PromQueryBuilderExplainedProps {
query: string;
}
export const PromQueryBuilderExplained = React.memo<Props>(({ query }) => {
export const PromQueryBuilderExplained = React.memo<PromQueryBuilderExplainedProps>(({ query }) => {
const visQuery = buildVisualQueryFromString(query || '').query;
const lang = { grammar: promqlGrammar, name: 'promql' };

View File

@ -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<Props>(({ query, app, onChange, onRunQuery }) => {
const onChangeFormat = (value: SelectableValue<PromQueryFormat>) => {
onChange({ ...query, format: value.value });
onRunQuery();
};
export const PromQueryBuilderOptions = React.memo<PromQueryBuilderOptionsProps>(
({ query, app, onChange, onRunQuery }) => {
const onChangeFormat = (value: SelectableValue<PromQueryFormat>) => {
onChange({ ...query, format: value.value });
onRunQuery();
};
const onChangeStep = (evt: React.FormEvent<HTMLInputElement>) => {
onChange({ ...query, interval: evt.currentTarget.value });
onRunQuery();
};
const onChangeStep = (evt: React.FormEvent<HTMLInputElement>) => {
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<HTMLInputElement>) => {
const isEnabled = event.currentTarget.checked;
onChange({ ...query, exemplar: isEnabled });
onRunQuery();
};
const onExemplarChange = (event: SyntheticEvent<HTMLInputElement>) => {
const isEnabled = event.currentTarget.checked;
onChange({ ...query, exemplar: isEnabled });
onRunQuery();
};
const onIntervalFactorChange = (value: SelectableValue<number>) => {
onChange({ ...query, intervalFactor: value.value });
onRunQuery();
};
const onIntervalFactorChange = (value: SelectableValue<number>) => {
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 (
<EditorRow>
<div data-testid={selectors.components.DataSource.Prometheus.queryEditor.options}>
<QueryOptionGroup
title="Options"
collapsedInfo={getCollapsedInfo(query, formatOption.label!, queryTypeLabel, app)}
>
<PromQueryLegendEditor
legendFormat={query.legendFormat}
onChange={(legendFormat) => onChange({ ...query, legendFormat })}
onRunQuery={onRunQuery}
/>
<EditorField
label="Min step"
tooltip={
<>
An additional lower limit for the step parameter of the Prometheus query and for the{' '}
<code>$__interval</code> and <code>$__rate_interval</code> variables.
</>
}
return (
<EditorRow>
<div data-testid={selectors.components.DataSource.Prometheus.queryEditor.options}>
<QueryOptionGroup
title="Options"
collapsedInfo={getCollapsedInfo(query, formatOption.label!, queryTypeLabel, app)}
>
<AutoSizeInput
type="text"
aria-label="Set lower limit for the step parameter"
placeholder={'auto'}
minWidth={10}
onCommitChange={onChangeStep}
defaultValue={query.interval}
id={selectors.components.DataSource.Prometheus.queryEditor.step}
<PromQueryLegendEditor
legendFormat={query.legendFormat}
onChange={(legendFormat) => onChange({ ...query, legendFormat })}
onRunQuery={onRunQuery}
/>
</EditorField>
<EditorField label="Format">
<Select
data-testid={selectors.components.DataSource.Prometheus.queryEditor.format}
value={formatOption}
allowCustomValue
onChange={onChangeFormat}
options={FORMAT_OPTIONS}
/>
</EditorField>
<EditorField label="Type" data-testid={selectors.components.DataSource.Prometheus.queryEditor.type}>
<RadioButtonGroup options={queryTypeOptions} value={queryTypeValue} onChange={onQueryTypeChange} />
</EditorField>
{shouldShowExemplarSwitch(query, app) && (
<EditorField label="Exemplars">
<EditorSwitch
value={query.exemplar || false}
onChange={onExemplarChange}
id={selectors.components.DataSource.Prometheus.queryEditor.exemplars}
<EditorField
label="Min step"
tooltip={
<>
An additional lower limit for the step parameter of the Prometheus query and for the{' '}
<code>$__interval</code> and <code>$__rate_interval</code> variables.
</>
}
>
<AutoSizeInput
type="text"
aria-label="Set lower limit for the step parameter"
placeholder={'auto'}
minWidth={10}
onCommitChange={onChangeStep}
defaultValue={query.interval}
id={selectors.components.DataSource.Prometheus.queryEditor.step}
/>
</EditorField>
)}
{query.intervalFactor && query.intervalFactor > 1 && (
<EditorField label="Resolution">
<EditorField label="Format">
<Select
aria-label="Select resolution"
isSearchable={false}
options={INTERVAL_FACTOR_OPTIONS}
onChange={onIntervalFactorChange}
value={INTERVAL_FACTOR_OPTIONS.find((option) => option.value === query.intervalFactor)}
data-testid={selectors.components.DataSource.Prometheus.queryEditor.format}
value={formatOption}
allowCustomValue
onChange={onChangeFormat}
options={FORMAT_OPTIONS}
/>
</EditorField>
)}
</QueryOptionGroup>
</div>
</EditorRow>
);
});
<EditorField label="Type" data-testid={selectors.components.DataSource.Prometheus.queryEditor.type}>
<RadioButtonGroup options={queryTypeOptions} value={queryTypeValue} onChange={onQueryTypeChange} />
</EditorField>
{shouldShowExemplarSwitch(query, app) && (
<EditorField label="Exemplars">
<EditorSwitch
value={query.exemplar || false}
onChange={onExemplarChange}
id={selectors.components.DataSource.Prometheus.queryEditor.exemplars}
/>
</EditorField>
)}
{query.intervalFactor && query.intervalFactor > 1 && (
<EditorField label="Resolution">
<Select
aria-label="Select resolution"
isSearchable={false}
options={INTERVAL_FACTOR_OPTIONS}
onChange={onIntervalFactorChange}
value={INTERVAL_FACTOR_OPTIONS.find((option) => option.value === query.intervalFactor)}
/>
</EditorField>
)}
</QueryOptionGroup>
</div>
</EditorRow>
);
}
);
function shouldShowExemplarSwitch(query: PromQuery, app?: CoreApp) {
if (app === CoreApp.UnifiedAlerting || !query.range) {

View File

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

View File

@ -7,7 +7,7 @@ import { AutoSizeInput, Select } from '@grafana/ui';
import { LegendFormatMode } from '../../types';
export interface Props {
export interface PromQueryLegendEditorProps {
legendFormat: string | undefined;
onChange: (legendFormat: string) => void;
onRunQuery: () => void;
@ -26,73 +26,75 @@ const legendModeOptions = [
/**
* Tests for this component are on the parent level (PromQueryBuilderOptions).
*/
export const PromQueryLegendEditor = React.memo<Props>(({ legendFormat, onChange, onRunQuery }) => {
const mode = getLegendMode(legendFormat);
const inputRef = useRef<HTMLInputElement | null>(null);
export const PromQueryLegendEditor = React.memo<PromQueryLegendEditorProps>(
({ legendFormat, onChange, onRunQuery }) => {
const mode = getLegendMode(legendFormat);
const inputRef = useRef<HTMLInputElement | null>(null);
const onLegendFormatChanged = (evt: React.FormEvent<HTMLInputElement>) => {
let newFormat = evt.currentTarget.value;
if (newFormat.length === 0) {
newFormat = LegendFormatMode.Auto;
}
const onLegendFormatChanged = (evt: React.FormEvent<HTMLInputElement>) => {
let newFormat = evt.currentTarget.value;
if (newFormat.length === 0) {
newFormat = LegendFormatMode.Auto;
}
if (newFormat !== legendFormat) {
onChange(newFormat);
if (newFormat !== legendFormat) {
onChange(newFormat);
onRunQuery();
}
};
const onLegendModeChanged = (value: SelectableValue<LegendFormatMode>) => {
switch (value.value!) {
case LegendFormatMode.Auto:
onChange(LegendFormatMode.Auto);
break;
case LegendFormatMode.Custom:
onChange('{{label_name}}');
setTimeout(() => {
inputRef.current?.focus();
inputRef.current?.setSelectionRange(2, 12, 'forward');
}, 10);
break;
case LegendFormatMode.Verbose:
onChange('');
break;
}
onRunQuery();
}
};
};
const onLegendModeChanged = (value: SelectableValue<LegendFormatMode>) => {
switch (value.value!) {
case LegendFormatMode.Auto:
onChange(LegendFormatMode.Auto);
break;
case LegendFormatMode.Custom:
onChange('{{label_name}}');
setTimeout(() => {
inputRef.current?.focus();
inputRef.current?.setSelectionRange(2, 12, 'forward');
}, 10);
break;
case LegendFormatMode.Verbose:
onChange('');
break;
}
onRunQuery();
};
return (
<EditorField
label="Legend"
tooltip="Series name override or template. Ex. {{hostname}} will be replaced with label value for hostname."
data-testid={selectors.components.DataSource.Prometheus.queryEditor.legend}
>
<>
{mode === LegendFormatMode.Custom && (
<AutoSizeInput
id="legendFormat"
minWidth={22}
placeholder="auto"
defaultValue={legendFormat}
onCommitChange={onLegendFormatChanged}
ref={inputRef}
/>
)}
{mode !== LegendFormatMode.Custom && (
<Select
inputId="legend.mode"
isSearchable={false}
placeholder="Select legend mode"
options={legendModeOptions}
width={22}
onChange={onLegendModeChanged}
value={legendModeOptions.find((x) => x.value === mode)}
/>
)}
</>
</EditorField>
);
});
return (
<EditorField
label="Legend"
tooltip="Series name override or template. Ex. {{hostname}} will be replaced with label value for hostname."
data-testid={selectors.components.DataSource.Prometheus.queryEditor.legend}
>
<>
{mode === LegendFormatMode.Custom && (
<AutoSizeInput
id="legendFormat"
minWidth={22}
placeholder="auto"
defaultValue={legendFormat}
onCommitChange={onLegendFormatChanged}
ref={inputRef}
/>
)}
{mode !== LegendFormatMode.Custom && (
<Select
inputId="legend.mode"
isSearchable={false}
placeholder="Select legend mode"
options={legendModeOptions}
width={22}
onChange={onLegendModeChanged}
value={legendModeOptions.find((x) => x.value === mode)}
/>
)}
</>
</EditorField>
);
}
);
PromQueryLegendEditor.displayName = 'PromQueryLegendEditor';

View File

@ -5,11 +5,11 @@ import { EditorFieldGroup, EditorRow } from '@grafana/experimental';
import promqlGrammar from '../../promql';
import { RawQuery } from '../shared/RawQuery';
export interface Props {
export interface QueryPreviewProps {
query: string;
}
export function QueryPreview({ query }: Props) {
export function QueryPreview({ query }: QueryPreviewProps) {
if (!query) {
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 { Icon, Switch, Tooltip, useTheme2 } from '@grafana/ui';
import { testIds } from './MetricsModal';
import { metricsModaltestIds } from './MetricsModal';
import { placeholders } from './state/helpers';
import { MetricsModalState } from './state/state';
@ -27,7 +27,7 @@ export function AdditionalSettings(props: AdditionalSettingsProps) {
<>
<div className={styles.selectItem}>
<Switch
data-testid={testIds.searchWithMetadata}
data-testid={metricsModaltestIds.searchWithMetadata}
value={state.fullMetaSearch}
disabled={state.useBackend || !state.hasMetadata}
onChange={() => onChangeFullMetaSearch()}
@ -47,7 +47,11 @@ export function AdditionalSettings(props: AdditionalSettingsProps) {
<div className={styles.selectItemLabel}>Disable text wrap</div>
</div>
<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>
<Tooltip
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 { PromVisualQuery } from '../../types';
import { MetricsModal, testIds } from './MetricsModal';
import { MetricsModal, metricsModaltestIds } from './MetricsModal';
// don't care about interaction tracking in our unit tests
jest.mock('@grafana/runtime', () => ({
@ -117,7 +117,7 @@ describe('MetricsModal', () => {
it('shows results metrics per page chosen by the user', async () => {
setup(defaultQuery, listOfMetrics);
const resultsPerPageInput = screen.getByTestId(testIds.resultsPerPage);
const resultsPerPageInput = screen.getByTestId(metricsModaltestIds.resultsPerPage);
await userEvent.type(resultsPerPageInput, '12');
const metricInsideRange = screen.getByText('j');
expect(metricInsideRange).toBeInTheDocument();
@ -130,7 +130,7 @@ describe('MetricsModal', () => {
// doesn't break on loading
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
await userEvent.type(resultsPerPageInput, '11');
const metricInsideRange = screen.getByText('9');
@ -149,7 +149,7 @@ describe('MetricsModal', () => {
expect(metricAll).toBeInTheDocument();
expect(metricABucket).toBeInTheDocument();
});
const searchMetric = screen.getByTestId(testIds.searchMetric);
const searchMetric = screen.getByTestId(metricsModaltestIds.searchMetric);
expect(searchMetric).toBeInTheDocument();
await userEvent.type(searchMetric, 'a_buck');
@ -169,15 +169,15 @@ describe('MetricsModal', () => {
expect(metricABucket).toBeInTheDocument();
});
const showSettingsButton = screen.getByTestId(testIds.showAdditionalSettings);
const showSettingsButton = screen.getByTestId(metricsModaltestIds.showAdditionalSettings);
expect(showSettingsButton).toBeInTheDocument();
await userEvent.click(showSettingsButton);
const metadataSwitch = screen.getByTestId(testIds.searchWithMetadata);
const metadataSwitch = screen.getByTestId(metricsModaltestIds.searchWithMetadata);
expect(metadataSwitch).toBeInTheDocument();
await userEvent.click(metadataSwitch);
const searchMetric = screen.getByTestId(testIds.searchMetric);
const searchMetric = screen.getByTestId(metricsModaltestIds.searchMetric);
expect(searchMetric).toBeInTheDocument();
await userEvent.type(searchMetric, 'functions');

View File

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

View File

@ -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
</Button>
@ -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) => {
<Button
fill="solid"
variant="primary"
data-testid={testIds.clickForAi}
data-testid={queryAssistanttestIds.clickForAi}
onClick={() => {
reportInteraction('grafana_prometheus_promqail_know_what_you_want_to_query', {
promVisualQuery: query,
@ -293,7 +293,7 @@ export const PromQail = (props: PromQailProps) => {
<Button
fill="solid"
variant="primary"
data-testid={testIds.submitPrompt + idx}
data-testid={queryAssistanttestIds.submitPrompt + idx}
onClick={() => {
const newInteraction: Interaction = {
...interaction,
@ -557,7 +557,7 @@ export const getStyles = (theme: GrafanaTheme2) => {
};
};
export const testIds = {
export const queryAssistanttestIds = {
promQail: 'prom-qail',
securityInfoButton: 'security-info-button',
clickForHistorical: 'click-for-historical',

View File

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