mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki Query Builder: ensure unique ids for labelled fields (#74398)
* Loki Query Builder: ensure unique ids for labelled fields * Rename refactored argument
This commit is contained in:
parent
c3cbe220bb
commit
9310bb632e
@ -63,7 +63,7 @@ const createProps = (
|
|||||||
onChange: jest.fn(),
|
onChange: jest.fn(),
|
||||||
onRunQuery: jest.fn(),
|
onRunQuery: jest.fn(),
|
||||||
index: 1,
|
index: 1,
|
||||||
operationIndex: 1,
|
operationId: '1',
|
||||||
query: {
|
query: {
|
||||||
labels: [{ op: '=', label: 'foo', value: 'bar' }],
|
labels: [{ op: '=', label: 'foo', value: 'bar' }],
|
||||||
operations: [
|
operations: [
|
||||||
|
@ -15,7 +15,7 @@ import { LokiVisualQuery } from '../types';
|
|||||||
export function UnwrapParamEditor({
|
export function UnwrapParamEditor({
|
||||||
onChange,
|
onChange,
|
||||||
index,
|
index,
|
||||||
operationIndex,
|
operationId,
|
||||||
value,
|
value,
|
||||||
query,
|
query,
|
||||||
datasource,
|
datasource,
|
||||||
@ -27,7 +27,7 @@ export function UnwrapParamEditor({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
inputId={getOperationParamId(operationIndex, index)}
|
inputId={getOperationParamId(operationId, index)}
|
||||||
onOpenMenu={async () => {
|
onOpenMenu={async () => {
|
||||||
// This check is always true, we do it to make typescript happy
|
// This check is always true, we do it to make typescript happy
|
||||||
if (datasource instanceof LokiDatasource) {
|
if (datasource instanceof LokiDatasource) {
|
||||||
|
@ -11,7 +11,7 @@ import { PromVisualQuery } from '../types';
|
|||||||
export function LabelParamEditor({
|
export function LabelParamEditor({
|
||||||
onChange,
|
onChange,
|
||||||
index,
|
index,
|
||||||
operationIndex,
|
operationId,
|
||||||
value,
|
value,
|
||||||
query,
|
query,
|
||||||
datasource,
|
datasource,
|
||||||
@ -23,7 +23,7 @@ export function LabelParamEditor({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
inputId={getOperationParamId(operationIndex, index)}
|
inputId={getOperationParamId(operationId, index)}
|
||||||
autoFocus={value === '' ? true : undefined}
|
autoFocus={value === '' ? true : undefined}
|
||||||
openMenuOnFocus
|
openMenuOnFocus
|
||||||
onOpenMenu={async () => {
|
onOpenMenu={async () => {
|
||||||
|
@ -30,7 +30,7 @@ describe('PromQueryBuilderContainer', () => {
|
|||||||
await userEvent.click(screen.getByTestId('operations.0.add-rest-param'));
|
await userEvent.click(screen.getByTestId('operations.0.add-rest-param'));
|
||||||
|
|
||||||
waitFor(() => {
|
waitFor(() => {
|
||||||
expect(container.querySelector(`${getOperationParamId(0, 0)}`)).toBeInTheDocument();
|
expect(container.querySelector(`${getOperationParamId('0', 0)}`)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useId, useState } from 'react';
|
||||||
import { Draggable } from 'react-beautiful-dnd';
|
import { Draggable } from 'react-beautiful-dnd';
|
||||||
|
|
||||||
import { DataSourceApi, GrafanaTheme2 } from '@grafana/data';
|
import { DataSourceApi, GrafanaTheme2 } from '@grafana/data';
|
||||||
@ -46,6 +46,7 @@ export function OperationEditor({
|
|||||||
}: Props) {
|
}: Props) {
|
||||||
const def = queryModeller.getOperationDef(operation.id);
|
const def = queryModeller.getOperationDef(operation.id);
|
||||||
const shouldFlash = useFlash(flash);
|
const shouldFlash = useFlash(flash);
|
||||||
|
const id = useId();
|
||||||
|
|
||||||
const isConflicting =
|
const isConflicting =
|
||||||
operation.id === LokiOperationId.LabelFilter && isConflictingFilter(operation, query.operations);
|
operation.id === LokiOperationId.LabelFilter && isConflictingFilter(operation, query.operations);
|
||||||
@ -86,7 +87,7 @@ export function OperationEditor({
|
|||||||
<div className={styles.paramRow} key={`${paramIndex}-1`}>
|
<div className={styles.paramRow} key={`${paramIndex}-1`}>
|
||||||
{!paramDef.hideName && (
|
{!paramDef.hideName && (
|
||||||
<div className={styles.paramName}>
|
<div className={styles.paramName}>
|
||||||
<label htmlFor={getOperationParamId(index, paramIndex)}>{paramDef.name}</label>
|
<label htmlFor={getOperationParamId(id, paramIndex)}>{paramDef.name}</label>
|
||||||
{paramDef.description && (
|
{paramDef.description && (
|
||||||
<Tooltip placement="top" content={paramDef.description} theme="info">
|
<Tooltip placement="top" content={paramDef.description} theme="info">
|
||||||
<Icon name="info-circle" size="sm" className={styles.infoIcon} />
|
<Icon name="info-circle" size="sm" className={styles.infoIcon} />
|
||||||
@ -101,7 +102,7 @@ export function OperationEditor({
|
|||||||
paramDef={paramDef}
|
paramDef={paramDef}
|
||||||
value={operation.params[paramIndex]}
|
value={operation.params[paramIndex]}
|
||||||
operation={operation}
|
operation={operation}
|
||||||
operationIndex={index}
|
operationId={id}
|
||||||
onChange={onParamValueChanged}
|
onChange={onParamValueChanged}
|
||||||
onRunQuery={onRunQuery}
|
onRunQuery={onRunQuery}
|
||||||
query={query}
|
query={query}
|
||||||
|
@ -33,7 +33,7 @@ export function getOperationParamEditor(
|
|||||||
function SimpleInputParamEditor(props: QueryBuilderOperationParamEditorProps) {
|
function SimpleInputParamEditor(props: QueryBuilderOperationParamEditorProps) {
|
||||||
return (
|
return (
|
||||||
<AutoSizeInput
|
<AutoSizeInput
|
||||||
id={getOperationParamId(props.operationIndex, props.index)}
|
id={getOperationParamId(props.operationId, props.index)}
|
||||||
defaultValue={props.value?.toString()}
|
defaultValue={props.value?.toString()}
|
||||||
minWidth={props.paramDef.minWidth}
|
minWidth={props.paramDef.minWidth}
|
||||||
placeholder={props.paramDef.placeholder}
|
placeholder={props.paramDef.placeholder}
|
||||||
@ -52,7 +52,7 @@ function SimpleInputParamEditor(props: QueryBuilderOperationParamEditorProps) {
|
|||||||
function BoolInputParamEditor(props: QueryBuilderOperationParamEditorProps) {
|
function BoolInputParamEditor(props: QueryBuilderOperationParamEditorProps) {
|
||||||
return (
|
return (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id={getOperationParamId(props.operationIndex, props.index)}
|
id={getOperationParamId(props.operationId, props.index)}
|
||||||
value={props.value as boolean}
|
value={props.value as boolean}
|
||||||
onChange={(evt) => props.onChange(props.index, evt.currentTarget.checked)}
|
onChange={(evt) => props.onChange(props.index, evt.currentTarget.checked)}
|
||||||
/>
|
/>
|
||||||
@ -63,7 +63,7 @@ function SelectInputParamEditor({
|
|||||||
paramDef,
|
paramDef,
|
||||||
value,
|
value,
|
||||||
index,
|
index,
|
||||||
operationIndex,
|
operationId,
|
||||||
onChange,
|
onChange,
|
||||||
}: QueryBuilderOperationParamEditorProps) {
|
}: QueryBuilderOperationParamEditorProps) {
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
@ -99,7 +99,7 @@ function SelectInputParamEditor({
|
|||||||
return (
|
return (
|
||||||
<Stack gap={0.5} direction="row" alignItems="center" wrap={false}>
|
<Stack gap={0.5} direction="row" alignItems="center" wrap={false}>
|
||||||
<Select
|
<Select
|
||||||
id={getOperationParamId(operationIndex, index)}
|
id={getOperationParamId(operationId, index)}
|
||||||
value={valueOption}
|
value={valueOption}
|
||||||
options={selectOptions}
|
options={selectOptions}
|
||||||
placeholder={paramDef.placeholder}
|
placeholder={paramDef.placeholder}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
createAggregationOperation,
|
createAggregationOperation,
|
||||||
createAggregationOperationWithParam,
|
createAggregationOperationWithParam,
|
||||||
|
getOperationParamId,
|
||||||
isConflictingSelector,
|
isConflictingSelector,
|
||||||
} from './operationUtils';
|
} from './operationUtils';
|
||||||
|
|
||||||
@ -197,3 +198,11 @@ describe('isConflictingSelector', () => {
|
|||||||
expect(isConflictingSelector(newLabel, labels)).toBe(false);
|
expect(isConflictingSelector(newLabel, labels)).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getOperationParamId', () => {
|
||||||
|
it('Generates correct id for operation param', () => {
|
||||||
|
const operationId = 'abc';
|
||||||
|
const paramId = 0;
|
||||||
|
expect(getOperationParamId(operationId, paramId)).toBe('operations.abc.param.0');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -120,8 +120,8 @@ export function getPromAndLokiOperationDisplayName(funcName: string) {
|
|||||||
return capitalize(funcName.replace(/_/g, ' '));
|
return capitalize(funcName.replace(/_/g, ' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getOperationParamId(operationIndex: number, paramIndex: number) {
|
export function getOperationParamId(operationId: string, paramIndex: number) {
|
||||||
return `operations.${operationIndex}.param.${paramIndex}`;
|
return `operations.${operationId}.param.${paramIndex}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRangeVectorParamDef(withRateInterval = false): QueryBuilderOperationParamDef {
|
export function getRangeVectorParamDef(withRateInterval = false): QueryBuilderOperationParamDef {
|
||||||
|
@ -89,7 +89,7 @@ export interface QueryBuilderOperationParamEditorProps {
|
|||||||
/** Parameter index */
|
/** Parameter index */
|
||||||
index: number;
|
index: number;
|
||||||
operation: QueryBuilderOperation;
|
operation: QueryBuilderOperation;
|
||||||
operationIndex: number;
|
operationId: string;
|
||||||
query: any;
|
query: any;
|
||||||
datasource: DataSourceApi;
|
datasource: DataSourceApi;
|
||||||
onChange: (index: number, value: QueryBuilderOperationParamValue) => void;
|
onChange: (index: number, value: QueryBuilderOperationParamValue) => void;
|
||||||
|
Loading…
Reference in New Issue
Block a user