mirror of
https://github.com/grafana/grafana.git
synced 2025-07-31 21:02:29 +08:00
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:

committed by
GitHub

parent
32a7aa33b8
commit
ec0eb8fd79
@ -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();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -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',
|
||||||
|
@ -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
|
||||||
|
@ -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',
|
||||||
};
|
};
|
||||||
|
10
packages/grafana-prometheus/src/components/index.ts
Normal file
10
packages/grafana-prometheus/src/components/index.ts
Normal 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';
|
@ -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';
|
||||||
|
@ -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[];
|
||||||
|
@ -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' },
|
||||||
|
@ -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 }]);
|
||||||
|
|
||||||
|
@ -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: {
|
||||||
|
@ -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>>;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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 ?? [];
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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' };
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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';
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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';
|
@ -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} </div>
|
<div className={styles.selectItemLabel}>{placeholders.setUseBackend} </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.'}
|
||||||
|
@ -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');
|
||||||
|
|
||||||
|
@ -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 </p>
|
<p className={styles.resultsPerPageLabel}># Results per page </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',
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
export * from './MetricsModal';
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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',
|
||||||
|
@ -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"
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
export * from './PromQail';
|
13
packages/grafana-prometheus/src/querybuilder/index.ts
Normal file
13
packages/grafana-prometheus/src/querybuilder/index.ts
Normal 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';
|
Reference in New Issue
Block a user