Tempo: Option to not show variable options in "search" editor (#87126)

* allow disabling variable options in Tempo "search" editor

* also for GroupByField

* set addVariablesToOptions true by default
This commit is contained in:
Domas
2024-05-03 14:22:03 +03:00
committed by GitHub
parent 39a88bae44
commit 4b496a907d
8 changed files with 97 additions and 66 deletions
@@ -23,7 +23,10 @@ import { QueryEditor } from './traceql/QueryEditor';
import { TempoQuery } from './types';
import { migrateFromSearchToTraceQLSearch } from './utils';
interface Props extends QueryEditorProps<TempoDatasource, TempoQuery>, Themeable2 {}
interface Props extends QueryEditorProps<TempoDatasource, TempoQuery>, Themeable2 {
// should template variables be added to tag options. default true
addVariablesToOptions?: boolean;
}
interface State {
uploadModalOpen: boolean;
}
@@ -154,6 +157,7 @@ class TempoQueryFieldComponent extends React.PureComponent<Props, State> {
onBlur={this.props.onBlur}
app={app}
onClearResults={this.onClearResults}
addVariablesToOptions={this.props.addVariablesToOptions}
/>
)}
{query.queryType === 'serviceMap' && (
@@ -138,7 +138,13 @@ describe('GroupByField', () => {
it('should allow selecting template variables', async () => {
const { container } = render(
<GroupByField datasource={datasource} query={query} onChange={onChange} isTagsLoading={false} />
<GroupByField
datasource={datasource}
query={query}
onChange={onChange}
isTagsLoading={false}
addVariablesToOptions={true}
/>
);
const tagSelect = container.querySelector(`input[aria-label="Select tag for filter 1"]`);
@@ -19,10 +19,11 @@ interface Props {
onChange: (value: TempoQuery) => void;
query: Partial<TempoQuery> & TempoQuery;
isTagsLoading: boolean;
addVariablesToOptions?: boolean;
}
export const GroupByField = (props: Props) => {
const { datasource, onChange, query, isTagsLoading } = props;
const { datasource, onChange, query, isTagsLoading, addVariablesToOptions } = props;
const styles = useStyles2(getStyles);
const generateId = () => uuidv4().slice(0, 8);
@@ -75,62 +76,63 @@ export const GroupByField = (props: Props) => {
tooltip="Select one or more tags to see the metrics summary. Note: the metrics summary API only considers spans of kind = server."
>
<>
{query.groupBy?.map((f, i) => (
<div key={f.id}>
<HorizontalGroup spacing={'none'} width={'auto'}>
<Select
aria-label={`Select scope for filter ${i + 1}`}
onChange={(v) => {
updateFilter({ ...f, scope: v?.value, tag: '' });
}}
options={scopeOptions}
placeholder="Select scope"
value={f.scope}
/>
<Select
aria-label={`Select tag for filter ${i + 1}`}
isClearable
allowCustomValue
isLoading={isTagsLoading}
key={f.tag}
onChange={(v) => {
updateFilter({ ...f, tag: v?.value });
}}
options={withTemplateVariableOptions(
getTags(f)
?.concat(f.tag !== undefined && !getTags(f)?.includes(f.tag) ? [f.tag] : [])
.map((t) => ({
label: t,
value: t,
}))
)}
placeholder="Select tag"
value={f.tag || ''}
/>
{(f.tag || (query.groupBy?.length ?? 0) > 1) && (
<AccessoryButton
aria-label={`Remove tag for filter ${i + 1}`}
icon="times"
onClick={() => removeFilter(f)}
tooltip="Remove tag"
title={`Remove tag for filter ${i + 1}`}
variant="secondary"
{query.groupBy?.map((f, i) => {
const tags = getTags(f)
?.concat(f.tag !== undefined && !getTags(f)?.includes(f.tag) ? [f.tag] : [])
.map((t) => ({
label: t,
value: t,
}));
return (
<div key={f.id}>
<HorizontalGroup spacing={'none'} width={'auto'}>
<Select
aria-label={`Select scope for filter ${i + 1}`}
onChange={(v) => {
updateFilter({ ...f, scope: v?.value, tag: '' });
}}
options={scopeOptions}
placeholder="Select scope"
value={f.scope}
/>
)}
{f.tag && i === (query.groupBy?.length ?? 0) - 1 && (
<span className={styles.addTag}>
<Select
aria-label={`Select tag for filter ${i + 1}`}
isClearable
allowCustomValue
isLoading={isTagsLoading}
key={f.tag}
onChange={(v) => {
updateFilter({ ...f, tag: v?.value });
}}
options={addVariablesToOptions ? withTemplateVariableOptions(tags) : tags}
placeholder="Select tag"
value={f.tag || ''}
/>
{(f.tag || (query.groupBy?.length ?? 0) > 1) && (
<AccessoryButton
aria-label="Add tag"
icon="plus"
onClick={() => addFilter()}
tooltip="Add tag"
aria-label={`Remove tag for filter ${i + 1}`}
icon="times"
onClick={() => removeFilter(f)}
tooltip="Remove tag"
title={`Remove tag for filter ${i + 1}`}
variant="secondary"
/>
</span>
)}
</HorizontalGroup>
</div>
))}
)}
{f.tag && i === (query.groupBy?.length ?? 0) - 1 && (
<span className={styles.addTag}>
<AccessoryButton
aria-label="Add tag"
icon="plus"
onClick={() => addFilter()}
tooltip="Add tag"
variant="secondary"
/>
</span>
)}
</HorizontalGroup>
</div>
);
})}
</>
</InlineSearchField>
);
@@ -293,6 +293,7 @@ const renderSearchField = (
tags={tags || []}
hideTag={hideTag}
query={'{}'}
addVariablesToOptions={true}
/>
);
};
@@ -34,6 +34,7 @@ interface Props {
query: string;
isMulti?: boolean;
allowCustomValue?: boolean;
addVariablesToOptions?: boolean;
}
const SearchField = ({
filter,
@@ -46,6 +47,7 @@ const SearchField = ({
hideTag,
hideValue,
query,
addVariablesToOptions,
isMulti = true,
allowCustomValue = true,
}: Props) => {
@@ -126,6 +128,13 @@ const SearchField = ({
operatorList = numberOperators;
}
const tagOptions = (filter.tag !== undefined ? uniq([filter.tag, ...tags]) : tags).map((t) => ({
label: t,
value: t,
}));
const operatorOptions = operatorList.map(operatorSelectableValue);
return (
<>
<HorizontalGroup spacing={'none'} width={'auto'}>
@@ -133,7 +142,7 @@ const SearchField = ({
<Select
className={styles.dropdown}
inputId={`${filter.id}-scope`}
options={withTemplateVariableOptions(scopeOptions)}
options={addVariablesToOptions ? withTemplateVariableOptions(scopeOptions) : scopeOptions}
value={filter.scope}
onChange={(v) => {
updateFilter({ ...filter, scope: v?.value });
@@ -148,12 +157,7 @@ const SearchField = ({
inputId={`${filter.id}-tag`}
isLoading={isTagsLoading}
// Add the current tag to the list if it doesn't exist in the tags prop, otherwise the field will be empty even though the state has a value
options={withTemplateVariableOptions(
(filter.tag !== undefined ? uniq([filter.tag, ...tags]) : tags).map((t) => ({
label: t,
value: t,
}))
)}
options={addVariablesToOptions ? withTemplateVariableOptions(tagOptions) : tagOptions}
value={filter.tag}
onChange={(v) => {
updateFilter({ ...filter, tag: v?.value, value: [] });
@@ -167,7 +171,7 @@ const SearchField = ({
<Select
className={styles.dropdown}
inputId={`${filter.id}-operator`}
options={withTemplateVariableOptions(operatorList.map(operatorSelectableValue))}
options={addVariablesToOptions ? withTemplateVariableOptions(operatorOptions) : operatorOptions}
value={filter.operator}
onChange={(v) => {
updateFilter({ ...filter, operator: v?.value });
@@ -182,7 +186,7 @@ const SearchField = ({
className={styles.dropdown}
inputId={`${filter.id}-value`}
isLoading={isLoadingValues}
options={withTemplateVariableOptions(options)}
options={addVariablesToOptions ? withTemplateVariableOptions(options) : options}
value={filter.value}
onChange={(val) => {
if (Array.isArray(val)) {
@@ -126,6 +126,7 @@ describe('TagsInput', () => {
staticTags={[]}
isTagsLoading={false}
query={''}
addVariablesToOptions={true}
/>
);
};
@@ -40,6 +40,7 @@ interface Props {
hideValues?: boolean;
requireTagAndValue?: boolean;
query: string;
addVariablesToOptions?: boolean;
}
const TagsInput = ({
updateFilter,
@@ -52,6 +53,7 @@ const TagsInput = ({
hideValues,
requireTagAndValue,
query,
addVariablesToOptions,
}: Props) => {
const styles = useStyles2(getStyles);
const handleOnAdd = useCallback(
@@ -88,6 +90,7 @@ const TagsInput = ({
isTagsLoading={isTagsLoading}
hideValue={hideValues}
query={query}
addVariablesToOptions={addVariablesToOptions}
/>
{(validInput(f) || filters.length > 1) && (
<AccessoryButton
@@ -27,11 +27,12 @@ interface Props {
onBlur?: () => void;
onClearResults: () => void;
app?: CoreApp;
addVariablesToOptions?: boolean;
}
const hardCodedFilterIds = ['min-duration', 'max-duration', 'status'];
const TraceQLSearch = ({ datasource, query, onChange, onClearResults, app }: Props) => {
const TraceQLSearch = ({ datasource, query, onChange, onClearResults, app, addVariablesToOptions = true }: Props) => {
const styles = useStyles2(getStyles);
const [alertText, setAlertText] = useState<string>();
const [error, setError] = useState<Error | FetchError | null>(null);
@@ -130,6 +131,7 @@ const TraceQLSearch = ({ datasource, query, onChange, onClearResults, app }: Pro
hideScope={true}
hideTag={true}
query={traceQlQuery}
addVariablesToOptions={addVariablesToOptions}
/>
</InlineSearchField>
)
@@ -153,6 +155,7 @@ const TraceQLSearch = ({ datasource, query, onChange, onClearResults, app }: Pro
query={traceQlQuery}
isMulti={false}
allowCustomValue={false}
addVariablesToOptions={addVariablesToOptions}
/>
</InlineSearchField>
<InlineSearchField
@@ -212,10 +215,17 @@ const TraceQLSearch = ({ datasource, query, onChange, onClearResults, app }: Pro
isTagsLoading={isTagsLoading}
query={traceQlQuery}
requireTagAndValue={true}
addVariablesToOptions={addVariablesToOptions}
/>
</InlineSearchField>
{config.featureToggles.metricsSummary && (
<GroupByField datasource={datasource} onChange={onChange} query={query} isTagsLoading={isTagsLoading} />
<GroupByField
datasource={datasource}
onChange={onChange}
query={query}
isTagsLoading={isTagsLoading}
addVariablesToOptions={addVariablesToOptions}
/>
)}
</div>
<div className={styles.rawQueryContainer}>