Add support to use custom values in dropdown (#2163)
## Summary
When we switched to use `Combobox` we were no longer able to add custom
values for our dropdowns, and this prevented users from using regexp
values for `group`, `host`, `proxy` etc. This PR adds
`createCustomValue` flag so that any custom value can be entered into
the dropdowns.
## Detailed summary
- Make use of `Combobox`'s `createCustomValues` so that wherever
necessary, users are able to enter regex values.
<img width="720" height="221" alt="Screenshot 2026-01-05 at 7 15 23 AM"
src="https://github.com/user-attachments/assets/841716eb-cd86-49d1-b13c-a0e37e8a37b9"
/>
## Why
For users to be able to use regexp, and any custom value in our
dropdowns.
## How to test
For all query types where dropdowns are used and user configurable (i.e.
group, host, proxy, application) start typing a value that does not
already exist in the dropdown. You should see an option to `Use custom
value`
Fixes
[comment](https://github.com/grafana/grafana-zabbix/pull/2141#issuecomment-3698818476),
thanks for the testing and call out @christos-diamantis
This commit is contained in:
committed by
GitHub
parent
0d64736e86
commit
9fda7768ff
5
.changeset/full-parrots-crash.md
Normal file
5
.changeset/full-parrots-crash.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'grafana-zabbix': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Support adding custom values in dropdowns for all query types
|
||||||
@@ -9,10 +9,11 @@ export interface Props {
|
|||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
options: Array<ComboboxOption<string>>;
|
options: Array<ComboboxOption<string>>;
|
||||||
width?: number;
|
width?: number;
|
||||||
|
createCustomValue?: boolean;
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MetricPicker = ({ value, placeholder, options, isLoading, width, onChange }: Props) => {
|
export const MetricPicker = ({ value, placeholder, options, isLoading, width, onChange, createCustomValue }: Props) => {
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const onMenuOptionSelect = (option: SelectableValue<string>) => {
|
const onMenuOptionSelect = (option: SelectableValue<string>) => {
|
||||||
@@ -23,6 +24,7 @@ export const MetricPicker = ({ value, placeholder, options, isLoading, width, on
|
|||||||
return (
|
return (
|
||||||
<div data-testid="role-picker" style={{ position: 'relative' }} ref={ref}>
|
<div data-testid="role-picker" style={{ position: 'relative' }} ref={ref}>
|
||||||
<Combobox<string>
|
<Combobox<string>
|
||||||
|
createCustomValue={createCustomValue ?? false}
|
||||||
width={width}
|
width={width}
|
||||||
value={value}
|
value={value}
|
||||||
options={options ?? []}
|
options={options ?? []}
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ export const HostTagQueryEditor = ({
|
|||||||
options={hostTagOptions ?? []}
|
options={hostTagOptions ?? []}
|
||||||
width={19}
|
width={19}
|
||||||
loading={hostTagOptionsLoading}
|
loading={hostTagOptionsLoading}
|
||||||
|
createCustomValue={true}
|
||||||
/>
|
/>
|
||||||
<Combobox
|
<Combobox
|
||||||
value={filter.operator}
|
value={filter.operator}
|
||||||
|
|||||||
@@ -239,6 +239,7 @@ export const MetricsQueryEditor = ({ query, datasource, onChange, onItemCountCha
|
|||||||
isLoading={groupsLoading}
|
isLoading={groupsLoading}
|
||||||
onChange={onFilterChange('group')}
|
onChange={onFilterChange('group')}
|
||||||
placeholder="Group name"
|
placeholder="Group name"
|
||||||
|
createCustomValue={true}
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
<InlineField label="Host tag" labelWidth={12}>
|
<InlineField label="Host tag" labelWidth={12}>
|
||||||
@@ -259,6 +260,7 @@ export const MetricsQueryEditor = ({ query, datasource, onChange, onItemCountCha
|
|||||||
isLoading={hostsLoading}
|
isLoading={hostsLoading}
|
||||||
onChange={onFilterChange('host')}
|
onChange={onFilterChange('host')}
|
||||||
placeholder="Host name"
|
placeholder="Host name"
|
||||||
|
createCustomValue={true}
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
</QueryEditorRow>
|
</QueryEditorRow>
|
||||||
@@ -271,6 +273,7 @@ export const MetricsQueryEditor = ({ query, datasource, onChange, onItemCountCha
|
|||||||
options={appOptions}
|
options={appOptions}
|
||||||
isLoading={appsLoading}
|
isLoading={appsLoading}
|
||||||
onChange={onFilterChange('application')}
|
onChange={onFilterChange('application')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Application name"
|
placeholder="Application name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
@@ -283,6 +286,7 @@ export const MetricsQueryEditor = ({ query, datasource, onChange, onItemCountCha
|
|||||||
options={tagOptions}
|
options={tagOptions}
|
||||||
isLoading={tagsLoading}
|
isLoading={tagsLoading}
|
||||||
onChange={onFilterChange('itemTag')}
|
onChange={onFilterChange('itemTag')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Item tag name"
|
placeholder="Item tag name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
@@ -294,6 +298,7 @@ export const MetricsQueryEditor = ({ query, datasource, onChange, onItemCountCha
|
|||||||
options={itemOptions}
|
options={itemOptions}
|
||||||
isLoading={itemsLoading}
|
isLoading={itemsLoading}
|
||||||
onChange={onFilterChange('item')}
|
onChange={onFilterChange('item')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Item name"
|
placeholder="Item name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
|
|||||||
@@ -166,6 +166,7 @@ export const ProblemsQueryEditor = ({ query, datasource, onChange }: Props) => {
|
|||||||
options={groupsOptions}
|
options={groupsOptions}
|
||||||
isLoading={groupsLoading}
|
isLoading={groupsLoading}
|
||||||
onChange={onFilterChange('group')}
|
onChange={onFilterChange('group')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Group name"
|
placeholder="Group name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
@@ -176,6 +177,7 @@ export const ProblemsQueryEditor = ({ query, datasource, onChange }: Props) => {
|
|||||||
options={hostOptions}
|
options={hostOptions}
|
||||||
isLoading={hostsLoading}
|
isLoading={hostsLoading}
|
||||||
onChange={onFilterChange('host')}
|
onChange={onFilterChange('host')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Host name"
|
placeholder="Host name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
@@ -186,6 +188,7 @@ export const ProblemsQueryEditor = ({ query, datasource, onChange }: Props) => {
|
|||||||
options={proxiesOptions}
|
options={proxiesOptions}
|
||||||
isLoading={proxiesLoading}
|
isLoading={proxiesLoading}
|
||||||
onChange={onFilterChange('proxy')}
|
onChange={onFilterChange('proxy')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Proxy name"
|
placeholder="Proxy name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
@@ -199,6 +202,7 @@ export const ProblemsQueryEditor = ({ query, datasource, onChange }: Props) => {
|
|||||||
options={appOptions}
|
options={appOptions}
|
||||||
isLoading={appsLoading}
|
isLoading={appsLoading}
|
||||||
onChange={onFilterChange('application')}
|
onChange={onFilterChange('application')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Application name"
|
placeholder="Application name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ export const ServicesQueryEditor = ({ query, datasource, onChange }: Props) => {
|
|||||||
options={itServicesOptions}
|
options={itServicesOptions}
|
||||||
isLoading={itServicesLoading}
|
isLoading={itServicesLoading}
|
||||||
onChange={onStringPropChange('itServiceFilter')}
|
onChange={onStringPropChange('itServiceFilter')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Service name"
|
placeholder="Service name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
@@ -105,6 +106,7 @@ export const ServicesQueryEditor = ({ query, datasource, onChange }: Props) => {
|
|||||||
options={slaOptions}
|
options={slaOptions}
|
||||||
isLoading={slaLoading}
|
isLoading={slaLoading}
|
||||||
onChange={onStringPropChange('slaFilter')}
|
onChange={onStringPropChange('slaFilter')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="SLA name"
|
placeholder="SLA name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ export const TextMetricsQueryEditor = ({ query, datasource, onChange }: Props) =
|
|||||||
options={groupsOptions}
|
options={groupsOptions}
|
||||||
isLoading={groupsLoading}
|
isLoading={groupsLoading}
|
||||||
onChange={onFilterChange('group')}
|
onChange={onFilterChange('group')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Group name"
|
placeholder="Group name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
@@ -154,6 +155,7 @@ export const TextMetricsQueryEditor = ({ query, datasource, onChange }: Props) =
|
|||||||
options={hostOptions}
|
options={hostOptions}
|
||||||
isLoading={hostsLoading}
|
isLoading={hostsLoading}
|
||||||
onChange={onFilterChange('host')}
|
onChange={onFilterChange('host')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Host name"
|
placeholder="Host name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
@@ -166,6 +168,7 @@ export const TextMetricsQueryEditor = ({ query, datasource, onChange }: Props) =
|
|||||||
options={appOptions}
|
options={appOptions}
|
||||||
isLoading={appsLoading}
|
isLoading={appsLoading}
|
||||||
onChange={onFilterChange('application')}
|
onChange={onFilterChange('application')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Application name"
|
placeholder="Application name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
@@ -176,6 +179,7 @@ export const TextMetricsQueryEditor = ({ query, datasource, onChange }: Props) =
|
|||||||
options={itemOptions}
|
options={itemOptions}
|
||||||
isLoading={itemsLoading}
|
isLoading={itemsLoading}
|
||||||
onChange={onFilterChange('item')}
|
onChange={onFilterChange('item')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Item name"
|
placeholder="Item name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
|
|||||||
@@ -230,6 +230,7 @@ export const TriggersQueryEditor = ({ query, datasource, onChange }: Props) => {
|
|||||||
isLoading={groupsLoading}
|
isLoading={groupsLoading}
|
||||||
onChange={onFilterChange('group')}
|
onChange={onFilterChange('group')}
|
||||||
placeholder="Group name"
|
placeholder="Group name"
|
||||||
|
createCustomValue={true}
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
<InlineField label="Host" labelWidth={12}>
|
<InlineField label="Host" labelWidth={12}>
|
||||||
@@ -239,6 +240,7 @@ export const TriggersQueryEditor = ({ query, datasource, onChange }: Props) => {
|
|||||||
options={hostOptions}
|
options={hostOptions}
|
||||||
isLoading={hostsLoading}
|
isLoading={hostsLoading}
|
||||||
onChange={onFilterChange('host')}
|
onChange={onFilterChange('host')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Host name"
|
placeholder="Host name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
@@ -250,6 +252,7 @@ export const TriggersQueryEditor = ({ query, datasource, onChange }: Props) => {
|
|||||||
options={proxiesOptions}
|
options={proxiesOptions}
|
||||||
isLoading={proxiesLoading}
|
isLoading={proxiesLoading}
|
||||||
onChange={onFilterChange('proxy')}
|
onChange={onFilterChange('proxy')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Proxy name"
|
placeholder="Proxy name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
@@ -264,6 +267,7 @@ export const TriggersQueryEditor = ({ query, datasource, onChange }: Props) => {
|
|||||||
options={appOptions}
|
options={appOptions}
|
||||||
isLoading={appsLoading}
|
isLoading={appsLoading}
|
||||||
onChange={onFilterChange('application')}
|
onChange={onFilterChange('application')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Application name"
|
placeholder="Application name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
@@ -276,6 +280,7 @@ export const TriggersQueryEditor = ({ query, datasource, onChange }: Props) => {
|
|||||||
options={tagOptions}
|
options={tagOptions}
|
||||||
isLoading={tagsLoading}
|
isLoading={tagsLoading}
|
||||||
onChange={onFilterChange('itemTag')}
|
onChange={onFilterChange('itemTag')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Item tag name"
|
placeholder="Item tag name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
@@ -300,6 +305,7 @@ export const TriggersQueryEditor = ({ query, datasource, onChange }: Props) => {
|
|||||||
options={itemOptions}
|
options={itemOptions}
|
||||||
isLoading={itemsLoading}
|
isLoading={itemsLoading}
|
||||||
onChange={onFilterChange('item')}
|
onChange={onFilterChange('item')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Item name"
|
placeholder="Item name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ export const UserMacrosQueryEditor = ({ query, datasource, onChange }: Props) =>
|
|||||||
options={groupsOptions}
|
options={groupsOptions}
|
||||||
isLoading={groupsLoading}
|
isLoading={groupsLoading}
|
||||||
onChange={onFilterChange('group')}
|
onChange={onFilterChange('group')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Group name"
|
placeholder="Group name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
@@ -111,6 +112,7 @@ export const UserMacrosQueryEditor = ({ query, datasource, onChange }: Props) =>
|
|||||||
options={hostOptions}
|
options={hostOptions}
|
||||||
isLoading={hostsLoading}
|
isLoading={hostsLoading}
|
||||||
onChange={onFilterChange('host')}
|
onChange={onFilterChange('host')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Host name"
|
placeholder="Host name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
@@ -123,6 +125,7 @@ export const UserMacrosQueryEditor = ({ query, datasource, onChange }: Props) =>
|
|||||||
options={macrosOptions}
|
options={macrosOptions}
|
||||||
isLoading={macrosLoading}
|
isLoading={macrosLoading}
|
||||||
onChange={onFilterChange('macro')}
|
onChange={onFilterChange('macro')}
|
||||||
|
createCustomValue={true}
|
||||||
placeholder="Macro name"
|
placeholder="Macro name"
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
|
|||||||
Reference in New Issue
Block a user