mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Tempo: Copy trace query to TraceQL tab (#79935)
* Copy trace query to TraceQL tab * Remove datasourceType * Update button position * Update test * Remove extra check * Update text
This commit is contained in:
@@ -193,6 +193,8 @@ class TempoQueryFieldComponent extends React.PureComponent<Props, State> {
|
|||||||
query={query}
|
query={query}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
onBlur={this.props.onBlur}
|
onBlur={this.props.onBlur}
|
||||||
|
app={app}
|
||||||
|
onClearResults={this.onClearResults}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{query.queryType === 'serviceMap' && (
|
{query.queryType === 'serviceMap' && (
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ describe('TraceQLSearch', () => {
|
|||||||
const onChange = (q: TempoQuery) => {
|
const onChange = (q: TempoQuery) => {
|
||||||
query = q;
|
query = q;
|
||||||
};
|
};
|
||||||
|
const onClearResults = jest.fn();
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
@@ -83,7 +84,9 @@ describe('TraceQLSearch', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should update operator when new value is selected in operator input', async () => {
|
it('should update operator when new value is selected in operator input', async () => {
|
||||||
const { container } = render(<TraceQLSearch datasource={datasource} query={query} onChange={onChange} />);
|
const { container } = render(
|
||||||
|
<TraceQLSearch datasource={datasource} query={query} onChange={onChange} onClearResults={onClearResults} />
|
||||||
|
);
|
||||||
|
|
||||||
const minDurationOperator = container.querySelector(`input[aria-label="select min-duration operator"]`);
|
const minDurationOperator = container.querySelector(`input[aria-label="select min-duration operator"]`);
|
||||||
expect(minDurationOperator).not.toBeNull();
|
expect(minDurationOperator).not.toBeNull();
|
||||||
@@ -101,7 +104,9 @@ describe('TraceQLSearch', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should add new filter when new value is selected in the service name section', async () => {
|
it('should add new filter when new value is selected in the service name section', async () => {
|
||||||
const { container } = render(<TraceQLSearch datasource={datasource} query={query} onChange={onChange} />);
|
const { container } = render(
|
||||||
|
<TraceQLSearch datasource={datasource} query={query} onChange={onChange} onClearResults={onClearResults} />
|
||||||
|
);
|
||||||
const serviceNameValue = container.querySelector(`input[aria-label="select service-name value"]`);
|
const serviceNameValue = container.querySelector(`input[aria-label="select service-name value"]`);
|
||||||
expect(serviceNameValue).not.toBeNull();
|
expect(serviceNameValue).not.toBeNull();
|
||||||
expect(serviceNameValue).toBeInTheDocument();
|
expect(serviceNameValue).toBeInTheDocument();
|
||||||
@@ -136,7 +141,9 @@ describe('TraceQLSearch', () => {
|
|||||||
} as TempoDatasource;
|
} as TempoDatasource;
|
||||||
datasource.languageProvider = new TempoLanguageProvider(datasource);
|
datasource.languageProvider = new TempoLanguageProvider(datasource);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
const { container } = render(<TraceQLSearch datasource={datasource} query={query} onChange={onChange} />);
|
const { container } = render(
|
||||||
|
<TraceQLSearch datasource={datasource} query={query} onChange={onChange} onClearResults={onClearResults} />
|
||||||
|
);
|
||||||
const serviceNameValue = container.querySelector(`input[aria-label="select service-name value"]`);
|
const serviceNameValue = container.querySelector(`input[aria-label="select service-name value"]`);
|
||||||
expect(serviceNameValue).toBeNull();
|
expect(serviceNameValue).toBeNull();
|
||||||
expect(serviceNameValue).not.toBeInTheDocument();
|
expect(serviceNameValue).not.toBeInTheDocument();
|
||||||
@@ -145,7 +152,9 @@ describe('TraceQLSearch', () => {
|
|||||||
|
|
||||||
it('should not render group by when feature toggle is not enabled', async () => {
|
it('should not render group by when feature toggle is not enabled', async () => {
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
render(<TraceQLSearch datasource={datasource} query={query} onChange={onChange} />);
|
render(
|
||||||
|
<TraceQLSearch datasource={datasource} query={query} onChange={onChange} onClearResults={onClearResults} />
|
||||||
|
);
|
||||||
const groupBy = screen.queryByText('Aggregate by');
|
const groupBy = screen.queryByText('Aggregate by');
|
||||||
expect(groupBy).toBeNull();
|
expect(groupBy).toBeNull();
|
||||||
expect(groupBy).not.toBeInTheDocument();
|
expect(groupBy).not.toBeInTheDocument();
|
||||||
@@ -155,7 +164,9 @@ describe('TraceQLSearch', () => {
|
|||||||
it('should render group by when feature toggle enabled', async () => {
|
it('should render group by when feature toggle enabled', async () => {
|
||||||
config.featureToggles.metricsSummary = true;
|
config.featureToggles.metricsSummary = true;
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
render(<TraceQLSearch datasource={datasource} query={query} onChange={onChange} />);
|
render(
|
||||||
|
<TraceQLSearch datasource={datasource} query={query} onChange={onChange} onClearResults={onClearResults} />
|
||||||
|
);
|
||||||
const groupBy = screen.queryByText('Aggregate by');
|
const groupBy = screen.queryByText('Aggregate by');
|
||||||
expect(groupBy).not.toBeNull();
|
expect(groupBy).not.toBeNull();
|
||||||
expect(groupBy).toBeInTheDocument();
|
expect(groupBy).toBeInTheDocument();
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { CoreApp, GrafanaTheme2 } from '@grafana/data';
|
||||||
import { EditorRow } from '@grafana/experimental';
|
import { config, FetchError, getTemplateSrv, reportInteraction } from '@grafana/runtime';
|
||||||
import { config, FetchError, getTemplateSrv } from '@grafana/runtime';
|
import { Alert, Button, HorizontalGroup, Select, useStyles2 } from '@grafana/ui';
|
||||||
import { Alert, HorizontalGroup, Select, useStyles2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { createErrorNotification } from '../../../../core/copy/appNotification';
|
import { createErrorNotification } from '../../../../core/copy/appNotification';
|
||||||
import { notifyApp } from '../../../../core/reducers/appNotification';
|
import { notifyApp } from '../../../../core/reducers/appNotification';
|
||||||
@@ -28,11 +27,13 @@ interface Props {
|
|||||||
query: TempoQuery;
|
query: TempoQuery;
|
||||||
onChange: (value: TempoQuery) => void;
|
onChange: (value: TempoQuery) => void;
|
||||||
onBlur?: () => void;
|
onBlur?: () => void;
|
||||||
|
onClearResults: () => void;
|
||||||
|
app?: CoreApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hardCodedFilterIds = ['min-duration', 'max-duration', 'status'];
|
const hardCodedFilterIds = ['min-duration', 'max-duration', 'status'];
|
||||||
|
|
||||||
const TraceQLSearch = ({ datasource, query, onChange }: Props) => {
|
const TraceQLSearch = ({ datasource, query, onChange, onClearResults, app }: Props) => {
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
const [error, setError] = useState<Error | FetchError | null>(null);
|
const [error, setError] = useState<Error | FetchError | null>(null);
|
||||||
|
|
||||||
@@ -214,9 +215,30 @@ const TraceQLSearch = ({ datasource, query, onChange }: Props) => {
|
|||||||
<GroupByField datasource={datasource} onChange={onChange} query={query} isTagsLoading={isTagsLoading} />
|
<GroupByField datasource={datasource} onChange={onChange} query={query} isTagsLoading={isTagsLoading} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<EditorRow>
|
<div className={styles.rawQueryContainer}>
|
||||||
<RawQuery query={templateSrv.replace(traceQlQuery)} lang={{ grammar: traceqlGrammar, name: 'traceql' }} />
|
<RawQuery query={templateSrv.replace(traceQlQuery)} lang={{ grammar: traceqlGrammar, name: 'traceql' }} />
|
||||||
</EditorRow>
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => {
|
||||||
|
reportInteraction('grafana_traces_copy_to_traceql_clicked', {
|
||||||
|
app: app ?? '',
|
||||||
|
grafana_version: config.buildInfo.version,
|
||||||
|
location: 'search_tab',
|
||||||
|
});
|
||||||
|
|
||||||
|
onClearResults();
|
||||||
|
const traceQlQuery = generateQueryFromFilters(query.filters || []);
|
||||||
|
onChange({
|
||||||
|
...query,
|
||||||
|
query: traceQlQuery,
|
||||||
|
queryType: 'traceql',
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Edit in TraceQL
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
<TempoQueryBuilderOptions onChange={onChange} query={query} />
|
<TempoQueryBuilderOptions onChange={onChange} query={query} />
|
||||||
</div>
|
</div>
|
||||||
{error ? (
|
{error ? (
|
||||||
@@ -242,4 +264,11 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`,
|
`,
|
||||||
|
rawQueryContainer: css({
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: theme.colors.background.secondary,
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
padding: theme.spacing(1),
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -48,9 +48,9 @@ export function QueryEditor(props: Props) {
|
|||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
reportInteraction('grafana_traces_copy_to_traceql_clicked', {
|
reportInteraction('grafana_traces_copy_to_traceql_clicked', {
|
||||||
datasourceType: 'tempo',
|
|
||||||
app: props.app ?? '',
|
app: props.app ?? '',
|
||||||
grafana_version: config.buildInfo.version,
|
grafana_version: config.buildInfo.version,
|
||||||
|
location: 'traceql_tab',
|
||||||
});
|
});
|
||||||
|
|
||||||
props.onClearResults();
|
props.onClearResults();
|
||||||
|
|||||||
Reference in New Issue
Block a user