The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryOptions.tsx

137 lines
4.4 KiB

import { css } from '@emotion/css';
import React from 'react';
import { CoreApp, GrafanaTheme2, SelectableValue } from '@grafana/data';
import { useStyles2, RadioButtonGroup, MultiSelect, Input } from '@grafana/ui';
import { Query } from '../types';
import { EditorField } from './EditorField';
import { QueryOptionGroup } from './QueryOptionGroup';
import { Stack } from './Stack';
export interface Props {
query: Query;
onQueryChange: (query: Query) => void;
app?: CoreApp;
labels?: string[];
}
const typeOptions: Array<{ value: Query['queryType']; label: string; description: string }> = [
{ value: 'metrics', label: 'Metric', description: 'Return aggregated metrics' },
{ value: 'profile', label: 'Profile', description: 'Return profile' },
{ value: 'both', label: 'Both', description: 'Return both metric and profile data' },
];
function getTypeOptions(app?: CoreApp) {
if (app === CoreApp.Explore) {
return typeOptions;
}
return typeOptions.filter((option) => option.value !== 'both');
}
/**
* Base on QueryOptionGroup component from grafana/ui but that is not available yet.
*/
export function QueryOptions({ query, onQueryChange, app, labels }: Props) {
const styles = useStyles2(getStyles);
const typeOptions = getTypeOptions(app);
const groupByOptions = labels
? labels.map((l) => ({
label: l,
value: l,
}))
: [];
let collapsedInfo = [`Type: ${query.queryType}`];
if (query.groupBy?.length) {
collapsedInfo.push(`Group by: ${query.groupBy.join(', ')}`);
}
if (query.spanSelector?.length) {
collapsedInfo.push(`Span ID: ${query.spanSelector.join(', ')}`);
}
if (query.maxNodes) {
collapsedInfo.push(`Max nodes: ${query.maxNodes}`);
}
return (
<Stack gap={0} direction="column">
<QueryOptionGroup title="Options" collapsedInfo={collapsedInfo}>
<div className={styles.body}>
<EditorField label={'Query Type'}>
<RadioButtonGroup
options={typeOptions}
value={query.queryType}
onChange={(value) => onQueryChange({ ...query, queryType: value })}
/>
</EditorField>
<EditorField
label={'Group by'}
tooltip={
<>
Used to group the metric result by a specific label or set of labels. Does not apply to profile query.
</>
}
>
<MultiSelect
placeholder="Label"
value={query.groupBy}
allowCustomValue
options={groupByOptions}
onChange={(change) => {
const changes = change.map((c: SelectableValue<string>) => {
return c.value!;
});
onQueryChange({ ...query, groupBy: changes });
}}
/>
</EditorField>
<EditorField label={'Span ID'} tooltip={<>Sets the span ID from which to search for profiles.</>}>
<Input
value={query.spanSelector || ['']}
type="string"
placeholder="64f170a95f537095"
onChange={(event: React.SyntheticEvent<HTMLInputElement>) => {
onQueryChange({
...query,
spanSelector: event.currentTarget.value !== '' ? [event.currentTarget.value] : [],
});
}}
/>
</EditorField>
<EditorField label={'Max Nodes'} tooltip={<>Sets the maximum number of nodes to return in the flamegraph.</>}>
<Input
value={query.maxNodes || ''}
type="number"
placeholder="16384"
onChange={(event: React.SyntheticEvent<HTMLInputElement>) => {
let newValue = parseInt(event.currentTarget.value, 10);
newValue = isNaN(newValue) ? 0 : newValue;
onQueryChange({ ...query, maxNodes: newValue });
}}
/>
</EditorField>
</div>
</QueryOptionGroup>
</Stack>
);
}
const getStyles = (theme: GrafanaTheme2) => {
return {
switchLabel: css({
color: theme.colors.text.secondary,
cursor: 'pointer',
fontSize: theme.typography.bodySmall.fontSize,
'&:hover': {
color: theme.colors.text.primary,
},
}),
body: css({
display: 'flex',
paddingTop: theme.spacing(2),
gap: theme.spacing(2),
flexWrap: 'wrap',
}),
};
};