Select: Make portalling the menu opt-in, but opt-in *everywhere* (#37501) (#37552)

* Select: Don't portal by default

* Select: Portal all the Selects

* Fix indendentation in this comment

* Select: Remove @example docs until formatting is correct

* Docs: Add some documentation for the Select changes

* Update docs/sources/whatsnew/whats-new-in-v8-1.md

Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com>

* Update docs/sources/whatsnew/whats-new-in-v8-1.md

Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com>

* Update packages/grafana-ui/src/components/Select/types.ts

Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com>

* Update public/app/core/components/TransformersUI/configFromQuery/ConfigFromQueryTransformerEditor.tsx

Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com>

* Update public/app/core/components/TransformersUI/configFromQuery/ConfigFromQueryTransformerEditor.tsx

Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com>

* Update public/app/core/components/TransformersUI/configFromQuery/ConfigFromQueryTransformerEditor.tsx

Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com>

* Update public/app/core/components/TransformersUI/prepareTimeSeries/PrepareTimeSeriesEditor.tsx

Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com>

* Docs: Variants instead of varients

* Update public/app/core/components/TransformersUI/configFromQuery/ConfigFromQueryTransformerEditor.tsx

Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com>

Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com>
(cherry picked from commit 8aa3845f70)
This commit is contained in:
Ashley Harrison
2021-08-04 17:40:54 +02:00
committed by GitHub
parent 6513bbfaf2
commit f3df336b17
153 changed files with 345 additions and 71 deletions
@@ -116,6 +116,22 @@ We’ve made some changes to the plugins UI to help make it easier to discover a
New panel summaries and preview on the top level [Visualizations]({{< relref "../panels/visualizations/_index.md" >}}) page to help users pick or learn about specific visualizations more easily.
### Upcoming changes to the Select component
The `@grafana/ui` exposes a `Select` component, and its variants `MultiSelect`, `AsyncSelect`, and `AsyncMultiSelect`. We have made some internal changes to these components to make the behavior and positioning more consistent in all scenarios.
To test the changes, you can use the `menuShouldPortal` property:
```jsx
<Select
menuShouldPortal
{...otherProps}
/>
```
Tests are most likely to be affected. There are some tips for fixing these in the original pull request at [https://github.com/grafana/grafana/pull/36398](https://github.com/grafana/grafana/pull/36398).
We’d love as much feedback as possible about this change, because we are considering making this the default behavior in a future release of Grafana.
## Enterprise features
These features are included in the Grafana Enterprise edition.
@@ -157,8 +157,9 @@ const addVariable = (config: PartialAddVariableConfig, isFirst: boolean): AddVar
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalTypeSelect()
.should('be.visible')
.within(() => {
e2e.components.Select.singleValue().should('have.text', 'Query').click().type(`${type}{enter}`);
e2e.components.Select.singleValue().should('have.text', 'Query').click();
});
e2e.components.Select.option().should('be.visible').contains(type).click();
}
if (label) {
@@ -144,6 +144,7 @@ export class DataSourcePicker extends PureComponent<DataSourcePickerProps, DataS
return (
<div aria-label={selectors.components.DataSourcePicker.container}>
<Select
menuShouldPortal
className={styles.select}
isMulti={false}
isClearable={false}
@@ -193,6 +193,7 @@ export class Cascader extends React.PureComponent<CascaderProps, CascaderState>
<div>
{isSearching ? (
<Select
menuShouldPortal
allowCustomValue={allowCustomValue}
placeholder={placeholder}
autoFocus={!focusCascade}
@@ -100,6 +100,7 @@ export const DataSourceHttpSettings: React.FC<HttpSettingsProps> = (props) => {
const accessSelect = (
<Select
menuShouldPortal
width={20}
options={ACCESS_OPTIONS}
value={ACCESS_OPTIONS.filter((o) => o.value === dataSourceConfig.access)[0] || DEFAULT_ACCESS_OPTION}
@@ -43,6 +43,7 @@ export const TimeZonePicker: React.FC<Props> = (props) => {
return (
<Select
menuShouldPortal
value={selected}
placeholder="Type to search (country, city, abbreviation)"
autoFocus={autoFocus}
@@ -28,7 +28,7 @@ describe('Field', () => {
it('renders with the inputId of its children', () => {
render(
<Field label="My other label">
<Select inputId="my-select-input" onChange={() => {}} />
<Select menuShouldPortal inputId="my-select-input" onChange={() => {}} />
</Field>
);
@@ -111,7 +111,7 @@ const renderForm = (defaultValues?: FormDTO) => (
rules={{
required: true,
}}
render={({ field }) => <Select {...field} options={selectOptions} />}
render={({ field }) => <Select menuShouldPortal {...field} options={selectOptions} />}
/>
</Field>
@@ -43,6 +43,7 @@ export const withSelect = () => {
return (
<InlineField label="Select option">
<Select
menuShouldPortal
width={16}
onChange={action('item selected')}
options={[
@@ -28,7 +28,7 @@ describe('InlineField', () => {
it('renders with the inputId of its children', () => {
render(
<InlineField label="My other label">
<Select inputId="my-select-input" onChange={() => {}} />
<Select menuShouldPortal inputId="my-select-input" onChange={() => {}} />
</InlineField>
);
@@ -69,6 +69,7 @@ export const Basic: Story = (args) => {
{(value, updateValue) => {
return (
<Select
menuShouldPortal
{...args}
onChange={(value: SelectableValue<string>) => {
action('onChanged fired')(value);
@@ -20,7 +20,7 @@ export const FieldNameMatcherEditor = memo<MatcherUIProps<string>>((props) => {
);
const selectedOption = selectOptions.find((v) => v.value === options);
return <Select value={selectedOption} options={selectOptions} onChange={onChange} />;
return <Select menuShouldPortal value={selectedOption} options={selectOptions} onChange={onChange} />;
});
FieldNameMatcherEditor.displayName = 'FieldNameMatcherEditor';
@@ -28,6 +28,7 @@ export const FieldNamePicker: React.FC<StandardEditorProps<string, FieldNamePick
return (
<>
<Select
menuShouldPortal
value={selectedOption}
options={selectOptions}
onChange={onSelectChange}
@@ -36,7 +36,7 @@ export const FieldNamesMatcherEditor = memo<MatcherUIProps<ByNamesMatcherOptions
return <Input value={displayNames} readOnly={true} disabled={true} prefix={prefix} />;
}
return <MultiSelect value={options.names} options={selectOptions} onChange={onChange} />;
return <MultiSelect menuShouldPortal value={options.names} options={selectOptions} onChange={onChange} />;
});
FieldNamesMatcherEditor.displayName = 'FieldNameMatcherEditor';
@@ -16,7 +16,7 @@ export const FieldTypeMatcherEditor = memo<MatcherUIProps<string>>((props) => {
);
const selectedOption = selectOptions.find((v) => v.value === options);
return <Select value={selectedOption} options={selectOptions} onChange={onChange} />;
return <Select menuShouldPortal value={selectedOption} options={selectOptions} onChange={onChange} />;
});
FieldTypeMatcherEditor.displayName = 'FieldTypeMatcherEditor';
@@ -23,7 +23,7 @@ export const FieldsByFrameRefIdMatcher = memo<MatcherUIProps<string>>((props) =>
);
const selectedOption = selectOptions.find((v) => v.value === options);
return <Select value={selectedOption} options={selectOptions} onChange={onChange} />;
return <Select menuShouldPortal value={selectedOption} options={selectOptions} onChange={onChange} />;
});
FieldsByFrameRefIdMatcher.displayName = 'FieldsByFrameRefIdMatcher';
@@ -74,7 +74,14 @@ export const FieldColorEditor: React.FC<FieldConfigEditorProps<FieldColor | unde
if (mode === FieldColorModeId.Fixed) {
return (
<div className={styles.group}>
<Select minMenuHeight={200} options={options} value={mode} onChange={onModeChange} className={styles.select} />
<Select
menuShouldPortal
minMenuHeight={200}
options={options}
value={mode}
onChange={onModeChange}
className={styles.select}
/>
<ColorValueEditor value={value?.fixedColor} onChange={onColorChange} />
</div>
);
@@ -90,7 +97,7 @@ export const FieldColorEditor: React.FC<FieldConfigEditorProps<FieldColor | unde
return (
<>
<div style={{ marginBottom: theme.spacing(2) }}>
<Select minMenuHeight={200} options={options} value={mode} onChange={onModeChange} />
<Select menuShouldPortal minMenuHeight={200} options={options} value={mode} onChange={onModeChange} />
</div>
<Field label="Color series by">
<RadioButtonGroup value={value?.seriesBy ?? 'last'} options={seriesModes} onChange={onSeriesModeChange} />
@@ -99,7 +106,7 @@ export const FieldColorEditor: React.FC<FieldConfigEditorProps<FieldColor | unde
);
}
return <Select minMenuHeight={200} options={options} value={mode} onChange={onModeChange} />;
return <Select menuShouldPortal minMenuHeight={200} options={options} value={mode} onChange={onModeChange} />;
};
interface ModeProps {
@@ -44,6 +44,7 @@ export function SegmentSelect<T>({
return (
<div {...rest} ref={ref}>
<Select
menuShouldPortal
width={width}
noOptionsMessage={noOptionsMessage}
placeholder={placeholder}
@@ -91,6 +91,7 @@ export const Basic: Story<StoryProps> = (args) => {
return (
<>
<Select
menuShouldPortal
options={generateOptions()}
value={value}
onChange={(v) => {
@@ -111,6 +112,7 @@ export const BasicSelectPlainValue: Story<StoryProps> = (args) => {
return (
<>
<Select
menuShouldPortal
options={generateOptions()}
value={value}
onChange={(v) => {
@@ -144,6 +146,7 @@ export const SelectWithOptionDescriptions: Story = (args) => {
return (
<>
<Select
menuShouldPortal
options={options}
value={value}
onChange={(v) => {
@@ -166,6 +169,7 @@ export const MultiPlainValue: Story = (args) => {
return (
<>
<MultiSelect
menuShouldPortal
options={generateOptions()}
value={value}
onChange={(v) => {
@@ -184,6 +188,7 @@ export const MultiSelectWithOptionGroups: Story = (args) => {
return (
<>
<MultiSelect
menuShouldPortal
options={[
{ label: '1', value: '1' },
{ label: '2', value: '2', options: [{ label: '5', value: '5' }] },
@@ -206,6 +211,7 @@ export const MultiSelectBasic: Story = (args) => {
return (
<>
<MultiSelect
menuShouldPortal
options={generateOptions()}
value={value}
onChange={(v) => {
@@ -229,6 +235,7 @@ export const MultiSelectAsync: Story = (args) => {
return (
<AsyncMultiSelect
menuShouldPortal
loadOptions={loadAsyncOptions}
defaultOptions
value={value}
@@ -250,6 +257,7 @@ export const BasicSelectAsync: Story = (args) => {
return (
<AsyncSelect
menuShouldPortal
loadOptions={loadAsyncOptions}
defaultOptions
value={value}
@@ -270,6 +278,7 @@ export const AutoMenuPlacement: Story = (args) => {
<>
<div style={{ width: '100%', height: '95vh', display: 'flex', alignItems: 'flex-end' }}>
<Select
menuShouldPortal
options={generateOptions()}
value={value}
onChange={(v) => {
@@ -294,6 +303,7 @@ export const CustomValueCreation: Story = (args) => {
return (
<>
<Select
menuShouldPortal
options={[...options, ...customOptions]}
value={value}
onChange={(v) => {
@@ -19,11 +19,11 @@ describe('SelectBase', () => {
];
it('renders without error', () => {
render(<SelectBase onChange={onChangeHandler} />);
render(<SelectBase menuShouldPortal onChange={onChangeHandler} />);
});
it('renders empty options information', () => {
render(<SelectBase onChange={onChangeHandler} />);
render(<SelectBase menuShouldPortal onChange={onChangeHandler} />);
userEvent.click(screen.getByText(/choose/i));
expect(screen.queryByText(/no options found/i)).toBeVisible();
});
@@ -32,7 +32,7 @@ describe('SelectBase', () => {
render(
<>
<label htmlFor="my-select">My select</label>
<SelectBase onChange={onChangeHandler} options={options} inputId="my-select" />
<SelectBase menuShouldPortal onChange={onChangeHandler} options={options} inputId="my-select" />
</>
);
@@ -47,7 +47,7 @@ describe('SelectBase', () => {
return (
<>
<button onClick={() => setValue(null)}>clear value</button>
<SelectBase value={value} onChange={setValue} options={[option]} />
<SelectBase menuShouldPortal value={value} onChange={setValue} options={[option]} />
</>
);
};
@@ -61,7 +61,7 @@ describe('SelectBase', () => {
describe('when openMenuOnFocus prop', () => {
describe('is provided', () => {
it('opens on focus', () => {
render(<SelectBase onChange={onChangeHandler} openMenuOnFocus />);
render(<SelectBase menuShouldPortal onChange={onChangeHandler} openMenuOnFocus />);
fireEvent.focus(screen.getByRole('textbox'));
expect(screen.queryByText(/no options found/i)).toBeVisible();
});
@@ -73,7 +73,7 @@ describe('SelectBase', () => {
${'ArrowUp'}
${' '}
`('opens on arrow down/up or space', ({ key }) => {
render(<SelectBase onChange={onChangeHandler} />);
render(<SelectBase menuShouldPortal onChange={onChangeHandler} />);
fireEvent.focus(screen.getByRole('textbox'));
fireEvent.keyDown(screen.getByRole('textbox'), { key });
expect(screen.queryByText(/no options found/i)).toBeVisible();
@@ -112,6 +112,7 @@ describe('SelectBase', () => {
it('should only display maxVisibleValues options, and additional number of values should be displayed as indicator', () => {
render(
<SelectBase
menuShouldPortal
onChange={onChangeHandler}
isMulti={true}
maxVisibleValues={3}
@@ -128,6 +129,7 @@ describe('SelectBase', () => {
it('should show all selected options when menu is open', () => {
render(
<SelectBase
menuShouldPortal
onChange={onChangeHandler}
isMulti={true}
maxVisibleValues={3}
@@ -147,6 +149,7 @@ describe('SelectBase', () => {
it('should not show all selected options when menu is open', () => {
render(
<SelectBase
menuShouldPortal
onChange={onChangeHandler}
isMulti={true}
maxVisibleValues={3}
@@ -167,6 +170,7 @@ describe('SelectBase', () => {
it('should always show all selected options', () => {
render(
<SelectBase
menuShouldPortal
onChange={onChangeHandler}
isMulti={true}
options={excessiveOptions}
@@ -183,7 +187,7 @@ describe('SelectBase', () => {
describe('options', () => {
it('renders menu with provided options', () => {
render(<SelectBase options={options} onChange={onChangeHandler} />);
render(<SelectBase menuShouldPortal options={options} onChange={onChangeHandler} />);
userEvent.click(screen.getByText(/choose/i));
const menuOptions = screen.getAllByLabelText('Select option');
expect(menuOptions).toHaveLength(2);
@@ -192,7 +196,7 @@ describe('SelectBase', () => {
it('call onChange handler when option is selected', async () => {
const spy = jest.fn();
render(<SelectBase onChange={spy} options={options} aria-label="My select" />);
render(<SelectBase menuShouldPortal onChange={spy} options={options} aria-label="My select" />);
const selectEl = screen.getByLabelText('My select');
expect(selectEl).toBeInTheDocument();
@@ -117,8 +117,8 @@ export function SelectBase<T>({
minMenuHeight,
maxVisibleValues,
menuPlacement = 'auto',
menuPortalTarget,
menuPosition,
menuShouldPortal = false,
noOptionsMessage = 'No options found',
onBlur,
onChange,
@@ -138,10 +138,8 @@ export function SelectBase<T>({
width,
isValidNewOption,
}: SelectBaseProps<T>) {
if (menuPortalTarget !== undefined) {
deprecationWarning('SelectBase', 'menuPortalTarget');
} else {
menuPortalTarget = document.body;
if (menuShouldPortal === false) {
deprecationWarning('SelectBase', 'menuShouldPortal={false}', 'menuShouldPortal={true}');
}
const theme = useTheme2();
const styles = getSelectStyles(theme);
@@ -206,9 +204,9 @@ export function SelectBase<T>({
maxVisibleValues,
menuIsOpen: isOpen,
menuPlacement,
menuPortalTarget,
menuPosition,
menuShouldBlockScroll: true,
menuPortalTarget: menuShouldPortal ? document.body : undefined,
menuShouldScrollIntoView: false,
onBlur,
onChange: onChangeWithEmpty,
@@ -350,6 +348,7 @@ export function SelectBase<T>({
bottom,
position,
minWidth: '100%',
zIndex: theme.zIndex.dropdown,
}),
container: () => ({
position: 'relative',
@@ -41,13 +41,13 @@ export interface SelectCommonProps<T> {
minMenuHeight?: number;
maxVisibleValues?: number;
menuPlacement?: 'auto' | 'bottom' | 'top';
/**
* @deprecated Setting `menuPortalTarget` to null will revert to previous `Select` behaviour.
* This is provided as an escape hatch for cases where portalling is a breaking change (e.g. `Select` wrapped in `ClickOutsideWrapper`).
* It's recommended to achieve the same behaviour using `onCloseMenu`, as this will be removed at some point.
*/
menuPortalTarget?: HTMLElement | null;
menuPosition?: 'fixed' | 'absolute';
/**
* @deprecated
* Setting to true will portal the menu to `document.body`.
* This property will soon be removed and portalling will be the default behavior.
*/
menuShouldPortal?: boolean;
/** The message to display when no options could be found */
noOptionsMessage?: string;
onBlur?: () => void;
@@ -68,6 +68,7 @@ export class StatsPicker extends PureComponent<Props> {
const select = fieldReducers.selectOptions(stats);
return (
<Select
menuShouldPortal
value={select.current}
className={className}
isClearable={!defaultStat}
@@ -134,7 +134,12 @@ export const ThemeDemo = () => {
<Input placeholder="Placeholder" value="Disabled value" />
</Field>
<Field label="Select">
<Select options={selectOptions} value={selectValue} onChange={(v) => setSelectValue(v?.value!)} />
<Select
menuShouldPortal
options={selectOptions}
value={selectValue}
onChange={(v) => setSelectValue(v?.value!)}
/>
</Field>
<Field label="Radio label">
<RadioButtonGroup options={radioOptions} value={radioValue} onChange={setRadioValue} />
@@ -148,6 +148,7 @@ export function ValueMappingEditRow({ mapping, index, onChange, onRemove, onDupl
)}
{mapping.type === MappingType.SpecialValue && (
<Select
menuShouldPortal
value={specialMatchOptions.find((v) => v.value === mapping.specialMatch)}
options={specialMatchOptions}
onChange={onChangeSpecialMatch}
@@ -56,6 +56,7 @@ export function ValuePicker<T>({
{isPicking && (
<span>
<Select
menuShouldPortal
placeholder={label}
options={options}
aria-label={selectors.components.ValuePicker.select(label)}
@@ -134,6 +134,7 @@ const ScaleDistributionEditor: React.FC<FieldOverrideEditorProps<ScaleDistributi
/>
{value.type === ScaleDistribution.Log && (
<Select
menuShouldPortal
allowCustomValue={false}
autoFocus
options={LOG_DISTRIBUTION_OPTIONS}
@@ -69,7 +69,7 @@ export class InputQueryEditor extends PureComponent<Props, State> {
<div>
<InlineField label="Data" labelWidth={8}>
<>
<Select width={20} options={options} value={selected} onChange={this.onSourceChange} />
<Select menuShouldPortal width={20} options={options} value={selected} onChange={this.onSourceChange} />
{query.data ? (
<div style={{ alignSelf: 'center' }}>{describeDataFrame(query.data)}</div>
) : (
@@ -50,6 +50,7 @@ export function FolderFilter({ onChange: propsOnChange, maxMenuHeight }: FolderF
</span>
)}
<AsyncMultiSelect
menuShouldPortal
{...selectOptions}
isLoading={loading}
loadOptions={debouncedLoadOptions}
@@ -56,7 +56,7 @@ export const PanelTypeFilter = ({ onChange: propsOnChange, maxMenuHeight }: Prop
Clear types
</span>
)}
<MultiSelect {...selectOptions} prefix={<Icon name="filter" />} aria-label="Panel Type filter" />
<MultiSelect menuShouldPortal {...selectOptions} prefix={<Icon name="filter" />} aria-label="Panel Type filter" />
</div>
);
};
@@ -100,6 +100,7 @@ class AddPermissions extends Component<Props, NewDashboardAclItem> {
{() => (
<HorizontalGroup>
<Select
menuShouldPortal
isSearchable={false}
value={this.state.type}
options={dashboardAclTargets}
@@ -117,6 +118,7 @@ class AddPermissions extends Component<Props, NewDashboardAclItem> {
<span className={styles.label}>Can</span>
<Select
menuShouldPortal
isSearchable={false}
value={this.state.permission}
options={dashboardPermissionLevels}
@@ -25,6 +25,7 @@ export default class DisabledPermissionListItem extends Component<Props, any> {
<td>
<div className="gf-form">
<Select
menuShouldPortal
options={dashboardPermissionLevels}
onChange={() => {}}
disabled={true}
@@ -75,6 +75,7 @@ export default class PermissionsListItem extends PureComponent<Props> {
<td className="query-keyword">Can</td>
<td>
<Select
menuShouldPortal
isSearchable={false}
options={dashboardPermissionLevels}
onChange={this.onPermissionChanged}
@@ -35,6 +35,7 @@ export const DashboardPicker: FC<Props> = ({ onChange, value, width, isClearable
return (
<AsyncSelect
menuShouldPortal
width={width}
isClearable={isClearable}
defaultOptions={true}
@@ -165,6 +165,7 @@ export class FolderPicker extends PureComponent<Props, State> {
return (
<div aria-label={selectors.components.FolderPicker.container}>
<AsyncSelect
menuShouldPortal
loadingMessage="Loading folders..."
defaultOptions
defaultValue={folder}
@@ -24,6 +24,7 @@ export const MetricSelect: FC<Props> = (props) => {
return (
<Select
menuShouldPortal
className={className}
isMulti={false}
isClearable={false}
@@ -48,6 +48,7 @@ export class OrgPicker extends PureComponent<Props, State> {
return (
<AsyncSelect
menuShouldPortal
className={className}
isLoading={isLoading}
defaultOptions={true}
@@ -28,6 +28,7 @@ export const SortPicker: FC<Props> = ({ onChange, value, placeholder, filter })
const selected = options?.find((opt) => opt.value === value);
return !loading ? (
<Select
menuShouldPortal
key={value}
width={25}
onChange={onChange}
@@ -57,6 +57,7 @@ export class TeamPicker extends Component<Props, State> {
return (
<div className="user-picker" data-testid="teamPicker">
<AsyncSelect
menuShouldPortal
isLoading={isLoading}
defaultOptions={true}
loadOptions={this.debouncedSearch}
@@ -65,6 +65,7 @@ export class UserPicker extends Component<Props, State> {
return (
<div className="user-picker" data-testid="userPicker">
<AsyncSelect
menuShouldPortal
isClearable
className={className}
isLoading={isLoading}
@@ -10,6 +10,7 @@ exports[`FolderPicker should render 1`] = `
defaultValue={null}
loadOptions={[Function]}
loadingMessage="Loading folders..."
menuShouldPortal={true}
onChange={[Function]}
onCreateOption={[Function]}
value={null}
@@ -145,6 +145,7 @@ export class SharedPreferences extends PureComponent<Props, State> {
aria-label="User preferences home dashboard drop down"
>
<Select
menuShouldPortal
value={dashboards.find((dashboard) => dashboard.id === homeDashboardId)}
getOptionValue={(i) => i.id}
getOptionLabel={this.getFullDashName}
@@ -107,7 +107,7 @@ export const TagFilter: FC<Props> = ({
Clear tags
</span>
)}
<AsyncMultiSelect {...selectOptions} prefix={<Icon name="tag-alt" />} aria-label="Tag filter" />
<AsyncMultiSelect menuShouldPortal {...selectOptions} prefix={<Icon name="tag-alt" />} aria-label="Tag filter" />
</div>
);
};
@@ -300,6 +300,7 @@ export class CalculateFieldTransformerEditor extends React.PureComponent<
</div>
<div className="gf-form">
<Select
menuShouldPortal
allowCustomValue={true}
placeholder="Field or number"
options={leftNames}
@@ -308,12 +309,14 @@ export class CalculateFieldTransformerEditor extends React.PureComponent<
onChange={this.onBinaryLeftChanged}
/>
<Select
menuShouldPortal
className="width-8 gf-form-spacing"
options={ops}
value={options.operator ?? ops[0].value}
onChange={this.onBinaryOperationChanged}
/>
<Select
menuShouldPortal
allowCustomValue={true}
placeholder="Field or number"
className="min-width-10"
@@ -341,6 +344,7 @@ export class CalculateFieldTransformerEditor extends React.PureComponent<
<div className="gf-form">
<div className="gf-form-label width-8">Mode</div>
<Select
menuShouldPortal
className="width-18"
options={calculationModes}
value={calculationModes.find((v) => v.value === mode)}
@@ -57,6 +57,7 @@ export class ConcatenateTransformerEditor extends React.PureComponent<Concatenat
<div className="gf-form">
<div className="gf-form-label width-8">Name</div>
<Select
menuShouldPortal
className="width-18"
options={nameModes}
value={nameModes.find((v) => v.value === frameNameMode)}
@@ -77,6 +77,7 @@ export const FilterByValueFilterEditor: React.FC<Props> = (props) => {
<div className="gf-form gf-form-spacing">
<div className="gf-form-label width-7">Field</div>
<Select
menuShouldPortal
className="min-width-15 max-width-24"
placeholder="Field Name"
options={fieldsAsOptions}
@@ -87,6 +88,7 @@ export const FilterByValueFilterEditor: React.FC<Props> = (props) => {
<div className="gf-form gf-form-spacing">
<div className="gf-form-label">Match</div>
<Select
menuShouldPortal
className="width-12"
placeholder="Select test"
options={matcherOptions}
@@ -86,6 +86,7 @@ export const GroupByFieldConfiguration: React.FC<FieldProps> = ({ fieldName, con
<div className={cx('gf-form', styles.cell)}>
<div className={cx('gf-form-spacing', styles.rowSpacing)}>
<Select
menuShouldPortal
className="width-12"
options={options}
value={config?.operation}
@@ -42,6 +42,7 @@ export const LabelsAsFieldsTransformerEditor: React.FC<TransformerUIProps<Labels
<div className="gf-form">
<div className="gf-form-label width-8">Value field name</div>
<Select
menuShouldPortal
isClearable={true}
allowCustomValue={false}
placeholder="(Optional) Select label"
@@ -64,6 +64,7 @@ export const ReduceTransformerEditor: React.FC<TransformerUIProps<ReduceTransfor
Mode
</div>
<Select
menuShouldPortal
options={modes}
value={modes.find((v) => v.value === options.mode) || modes[0]}
onChange={onSelectMode}
@@ -32,7 +32,7 @@ export const SeriesToFieldsTransformerEditor: React.FC<TransformerUIProps<Series
<div className="gf-form-inline">
<div className="gf-form gf-form--grow">
<div className="gf-form-label width-8">Field name</div>
<Select options={fieldNames} value={options.byField} onChange={onSelectField} isClearable />
<Select menuShouldPortal options={fieldNames} value={options.byField} onChange={onSelectField} isClearable />
</div>
</div>
);
@@ -28,6 +28,7 @@ export const SortByTransformerEditor: React.FC<TransformerUIProps<SortByTransfor
<InlineFieldRow key={`${s.field}/${index}`}>
<InlineField label="Field" labelWidth={10} grow={true}>
<Select
menuShouldPortal
options={fieldNames}
value={s.field}
placeholder="Select field"
@@ -51,12 +51,12 @@ export function ConfigFromQueryTransformerEditor({ input, onChange, options }: P
<>
<InlineFieldRow>
<InlineField label="Config query" labelWidth={20}>
<Select onChange={onRefIdChange} options={refIds} value={currentRefId} width={30} />
<Select menuShouldPortal onChange={onRefIdChange} options={refIds} value={currentRefId} width={30} />
</InlineField>
</InlineFieldRow>
<InlineFieldRow>
<InlineField label="Apply to" labelWidth={20}>
<Select onChange={onMatcherChange} options={matchers} value={currentMatcher.id} width={30} />
<Select menuShouldPortal onChange={onMatcherChange} options={matchers} value={currentMatcher.id} width={30} />
</InlineField>
</InlineFieldRow>
<InlineFieldRow>
@@ -91,10 +91,10 @@ export const configFromQueryTransformRegistryItem: TransformerRegistryItem<Confi
description: configFromDataTransformer.description,
state: PluginState.beta,
help: `
### Use cases
### Use cases
This transformation allow you select one query and from it extract standard options like
**Min**, **Max**, **Unit** and **Thresholds** and apply it to other query results.
This transformation allows you select one query and from it extract standard options such as
**Min**, **Max**, **Unit**, and **Thresholds** and apply them to other query results.
This enables dynamic query driven visualization configuration.
### Options
@@ -130,15 +130,14 @@ Output (Same as Input[0] but now with config on the Value field)
| 1626178119127 | 10 |
| 1626178119129 | 30 |
As you can see each row in the source data becomes a separate field. Each field now also has a max
config option set. Options like min, max, unit and thresholds are all part of field configuration
and if set like this will be used by the visualization instead of any options manually configured
Each row in the source data becomes a separate field. Each field now also has a maximum
configuration option set. Options such as **min**, **max**, **unit**, and **thresholds** are all part of field configuration, and if they are set like this, they will be used by the visualization instead of any options that are manually configured.
in the panel editor options pane.
## Value mappings
You can also transform a query result into value mappings. This is is a bit different as here every
row in the config query result will be used to define a single value mapping row. See example below.
You can also transform a query result into value mappings. This is is a bit different because every
row in the configuration query result is used to define a single value mapping row. See the following example.
Config query result:
@@ -73,6 +73,7 @@ export function FieldToConfigMappingEditor({ frame, mappings, onChange, withRedu
<td className={styles.labelCell}>{row.fieldName}</td>
<td className={styles.selectCell} data-testid={`${row.fieldName}-config-key`}>
<Select
menuShouldPortal
options={configProps}
value={row.configOption}
placeholder={row.placeholder}
@@ -53,6 +53,7 @@ export function PrepareTimeSeriesEditor(props: TransformerUIProps<PrepareTimeSer
<InlineFieldRow>
<InlineField label="Format" labelWidth={12}>
<Select
menuShouldPortal
width={35}
options={formats}
value={formats.find((v) => v.value === options.format) || formats[0]}
@@ -85,9 +86,9 @@ export const prepareTimeseriesTransformerRegistryItem: TransformerRegistryItem<P
name: prepareTimeSeriesTransformer.name,
description: prepareTimeSeriesTransformer.description,
help: `
### Use cases
This will take query results and transform them into a predictable timeseries format.
### Use cases
This takes query results and transforms them into a predictable timeseries format.
This transformer may be especially useful when using old panels that only expect the
many-frame timeseries format.
`,
@@ -12,6 +12,7 @@ const options = Object.keys(OrgRole).map((key) => ({ label: key, value: key }));
export const OrgRolePicker: FC<Props> = ({ value, onChange, ...restProps }) => (
<Select
menuShouldPortal
value={value}
options={options}
onChange={(val) => onChange(val.value as OrgRole)}
@@ -106,6 +106,7 @@ export class AlertRuleListUnconnected extends PureComponent<Props> {
<div className="width-13">
<Select
menuShouldPortal
options={this.stateFilters}
onChange={this.onStateFilterChanged}
value={this.getStateFilter()}
@@ -30,7 +30,7 @@ export const BasicSettings: FC<Props> = ({
<Field label="Type">
<InputControl
name="type"
render={({ field: { ref, ...field } }) => <Select {...field} options={channels} />}
render={({ field: { ref, ...field } }) => <Select menuShouldPortal {...field} options={channels} />}
control={control}
rules={{ required: true }}
/>
@@ -29,7 +29,7 @@ export const OptionElement: FC<Props> = ({ control, option, register, invalid })
control={control}
name={`${modelValue}`}
render={({ field: { ref, ...field } }) => (
<Select {...field} options={option.selectOptions ?? undefined} invalid={invalid} />
<Select menuShouldPortal {...field} options={option.selectOptions ?? undefined} invalid={invalid} />
)}
/>
);
@@ -46,6 +46,7 @@ export const AlertManagerPicker: FC<Props> = ({ onChange, current, disabled = fa
data-testid="alertmanager-picker"
>
<Select
menuShouldPortal
width={29}
className="ds-picker select-container"
backspaceRemovesValue={false}
@@ -42,6 +42,7 @@ export const AmRootRouteForm: FC<AmRootRouteFormProps> = ({
<InputControl
render={({ field: { onChange, ref, ...field } }) => (
<Select
menuShouldPortal
{...field}
className={styles.input}
onChange={(value) => onChange(mapSelectValueToString(value))}
@@ -68,6 +69,7 @@ export const AmRootRouteForm: FC<AmRootRouteFormProps> = ({
<InputControl
render={({ field: { onChange, ref, ...field } }) => (
<MultiSelect
menuShouldPortal
{...field}
allowCustomValue
className={styles.input}
@@ -113,6 +115,7 @@ export const AmRootRouteForm: FC<AmRootRouteFormProps> = ({
<InputControl
render={({ field: { onChange, ref, ...field } }) => (
<Select
menuShouldPortal
{...field}
className={styles.input}
onChange={(value) => onChange(mapSelectValueToString(value))}
@@ -147,6 +150,7 @@ export const AmRootRouteForm: FC<AmRootRouteFormProps> = ({
<InputControl
render={({ field: { onChange, ref, ...field } }) => (
<Select
menuShouldPortal
{...field}
className={styles.input}
onChange={(value) => onChange(mapSelectValueToString(value))}
@@ -181,6 +185,7 @@ export const AmRootRouteForm: FC<AmRootRouteFormProps> = ({
<InputControl
render={({ field: { onChange, ref, ...field } }) => (
<Select
menuShouldPortal
{...field}
className={styles.input}
menuPlacement="top"
@@ -117,6 +117,7 @@ export const AmRoutesExpandedForm: FC<AmRoutesExpandedFormProps> = ({ onCancel,
<InputControl
render={({ field: { onChange, ref, ...field } }) => (
<Select
menuShouldPortal
{...field}
className={formStyles.input}
onChange={(value) => onChange(mapSelectValueToString(value))}
@@ -141,6 +142,7 @@ export const AmRoutesExpandedForm: FC<AmRoutesExpandedFormProps> = ({ onCancel,
<InputControl
render={({ field: { onChange, ref, ...field } }) => (
<MultiSelect
menuShouldPortal
{...field}
allowCustomValue
className={formStyles.input}
@@ -188,6 +190,7 @@ export const AmRoutesExpandedForm: FC<AmRoutesExpandedFormProps> = ({ onCancel,
<InputControl
render={({ field: { onChange, ref, ...field } }) => (
<Select
menuShouldPortal
{...field}
className={formStyles.input}
onChange={(value) => onChange(mapSelectValueToString(value))}
@@ -221,6 +224,7 @@ export const AmRoutesExpandedForm: FC<AmRoutesExpandedFormProps> = ({ onCancel,
<InputControl
render={({ field: { onChange, ref, ...field } }) => (
<Select
menuShouldPortal
{...field}
className={formStyles.input}
onChange={(value) => onChange(mapSelectValueToString(value))}
@@ -254,6 +258,7 @@ export const AmRoutesExpandedForm: FC<AmRoutesExpandedFormProps> = ({ onCancel,
<InputControl
render={({ field: { onChange, ref, ...field } }) => (
<Select
menuShouldPortal
{...field}
className={formStyles.input}
menuPlacement="top"
@@ -75,7 +75,13 @@ export function ChannelSubForm<R extends ChannelValues>({
name={name('type')}
defaultValue={defaultValues.type}
render={({ field: { ref, onChange, ...field } }) => (
<Select {...field} width={37} options={typeOptions} onChange={(value) => onChange(value?.value)} />
<Select
menuShouldPortal
{...field}
width={37}
options={typeOptions}
onChange={(value) => onChange(value?.value)}
/>
)}
control={control}
rules={{ required: true }}
@@ -96,6 +96,7 @@ const OptionInput: FC<Props & { id: string }> = ({ option, invalid, id, pathPref
<InputControl
render={({ field: { onChange, ref, ...field } }) => (
<Select
menuShouldPortal
{...field}
options={option.selectOptions ?? undefined}
invalid={invalid}
@@ -73,7 +73,12 @@ export const AlertTypeStep: FC<Props> = ({ editingExistingRule }) => {
>
<InputControl
render={({ field: { onChange, ref, ...field } }) => (
<Select {...field} options={alertTypeOptions} onChange={(v: SelectableValue) => onChange(v?.value)} />
<Select
menuShouldPortal
{...field}
options={alertTypeOptions}
onChange={(v: SelectableValue) => onChange(v?.value)}
/>
)}
name="type"
control={control}
@@ -30,6 +30,7 @@ export const CloudConditionsStep: FC = () => {
name="forTimeUnit"
render={({ field: { onChange, ref, ...field } }) => (
<Select
menuShouldPortal
{...field}
options={timeOptions}
onChange={(value) => onChange(value?.value)}
@@ -47,6 +47,7 @@ export const ConditionField: FC = () => {
name="condition"
render={({ field: { onChange, ref, ...field } }) => (
<Select
menuShouldPortal
{...field}
width={42}
options={options}
@@ -21,5 +21,5 @@ export const GrafanaAlertStatePicker: FC<Props> = ({ includeNoData, ...props })
}
return options.filter((opt) => opt.value !== GrafanaAlertStateDecision.NoData);
}, [includeNoData]);
return <Select options={opts} {...props} />;
return <Select menuShouldPortal options={opts} {...props} />;
};
@@ -55,6 +55,7 @@ export const SelectWithAdd: FC<Props> = ({
} else {
return (
<Select
menuShouldPortal
width={width}
options={_options}
value={value}
@@ -147,6 +147,7 @@ export class AnnotationFieldMapper extends PureComponent<Props, State> {
</td>
{/* <td>
<Select
menuShouldPortal
value={valueOptions.find(v => v.value === mapping.source) || valueOptions[0]}
options={valueOptions}
onChange={(v: SelectableValue<AnnotationEventFieldSource>) => {
@@ -156,6 +157,7 @@ export class AnnotationFieldMapper extends PureComponent<Props, State> {
</td> */}
<td>
<Select
menuShouldPortal
value={currentValue}
options={picker}
placeholder={row.placeholder || row.key}
@@ -87,7 +87,7 @@ export const LinkSettingsEdit: React.FC<LinkSettingsEditProps> = ({ editLinkIdx,
<Input name="title" id="title" value={linkSettings.title} onChange={onChange} autoFocus={isNew} />
</Field>
<Field label="Type">
<Select value={linkSettings.type} options={linkTypeOptions} onChange={onTypeChange} />
<Select menuShouldPortal value={linkSettings.type} options={linkTypeOptions} onChange={onTypeChange} />
</Field>
{linkSettings.type === 'dashboards' && (
<>
@@ -105,7 +105,7 @@ export const LinkSettingsEdit: React.FC<LinkSettingsEditProps> = ({ editLinkIdx,
<Input name="tooltip" value={linkSettings.tooltip} onChange={onChange} placeholder="Open dashboard" />
</Field>
<Field label="Icon">
<Select value={linkSettings.icon} options={linkIconOptions} onChange={onIconChange} />
<Select menuShouldPortal value={linkSettings.icon} options={linkIconOptions} onChange={onIconChange} />
</Field>
</>
)}
@@ -146,6 +146,7 @@ export function getPanelFrameCategory(props: OptionPaneRenderProps): OptionsPane
const maxPerRowOptions = [2, 3, 4, 6, 8, 12].map((value) => ({ label: value.toString(), value }));
return (
<Select
menuShouldPortal
options={maxPerRowOptions}
value={panel.maxPerRow}
onChange={(value) => onPanelConfigChange('maxPerRow', value.value)}
@@ -36,5 +36,5 @@ export const RepeatRowSelect: FC<Props> = ({ repeat, onChange }) => {
const onSelectChange = useCallback((option: SelectableValue<string | null>) => onChange(option.value!), [onChange]);
return <Select value={repeat} onChange={onSelectChange} options={variableOptions} />;
return <Select menuShouldPortal value={repeat} onChange={onSelectChange} options={variableOptions} />;
};
@@ -226,7 +226,13 @@ export class ShareSnapshot extends PureComponent<Props, State> {
<Input width={30} value={snapshotName} onChange={this.onSnapshotNameChange} />
</Field>
<Field label="Expire">
<Select width={30} options={expireOptions} value={selectedExpireOption} onChange={this.onExpireChange} />
<Select
menuShouldPortal
width={30}
options={expireOptions}
value={selectedExpireOption}
onChange={this.onExpireChange}
/>
</Field>
<Field
label="Timeout (seconds)"
@@ -200,6 +200,7 @@ export function RichHistoryQueriesTab(props: Props) {
{!activeDatasourceOnly && (
<div aria-label="Filter datasources" className={styles.multiselect}>
<MultiSelect
menuShouldPortal
options={listOfDatasources}
value={datasourceFilters}
placeholder="Filter queries for data sources(s)"
@@ -218,6 +219,7 @@ export function RichHistoryQueriesTab(props: Props) {
</div>
<div aria-label="Sort queries" className={styles.sort}>
<Select
menuShouldPortal
value={sortOrderOptions.filter((order) => order.value === sortOrder)}
options={sortOrderOptions}
placeholder="Sort queries by"
@@ -84,7 +84,12 @@ export function RichHistorySettings(props: RichHistorySettingsProps) {
className="space-between"
>
<div className={styles.input}>
<Select value={selectedOption} options={retentionPeriodOptions} onChange={onChangeRetentionPeriod}></Select>
<Select
menuShouldPortal
value={selectedOption}
options={retentionPeriodOptions}
onChange={onChangeRetentionPeriod}
></Select>
</div>
</Field>
<Field label="Default active tab" description=" " className="space-between">
@@ -118,6 +118,7 @@ export function RichHistoryStarredTab(props: Props) {
{!activeDatasourceOnly && (
<div aria-label="Filter datasources" className={styles.multiselect}>
<MultiSelect
menuShouldPortal
options={listOfDatasources}
value={datasourceFilters}
placeholder="Filter queries for specific data sources(s)"
@@ -136,6 +137,7 @@ export function RichHistoryStarredTab(props: Props) {
</div>
<div aria-label="Sort queries" className={styles.sort}>
<Select
menuShouldPortal
options={sortOrderOptions}
value={sortOrderOptions.filter((order) => order.value === sortOrder)}
placeholder="Sort queries by"
@@ -45,7 +45,13 @@ export class ExpressionQueryEditor extends PureComponent<Props> {
return (
<div>
<InlineField label="Operation" labelWidth={labelWidth}>
<Select options={gelTypes} value={selected} onChange={this.onSelectExpressionType} width={25} />
<Select
menuShouldPortal
options={gelTypes}
value={selected}
onChange={this.onSelectExpressionType}
width={25}
/>
</InlineField>
{this.renderExpressionType()}
</div>
@@ -79,6 +79,7 @@ export const Condition: FC<Props> = ({ condition, index, onChange, onRemoveCondi
/>
)}
<Select
menuShouldPortal
options={reducerFunctions}
onChange={onReducerFunctionChange}
width={20}
@@ -86,6 +87,7 @@ export const Condition: FC<Props> = ({ condition, index, onChange, onRemoveCondi
/>
<div className={styles.button}>OF</div>
<Select
menuShouldPortal
onChange={onRefIdChange}
options={refIds}
width={15}
@@ -24,10 +24,10 @@ export const Reduce: FC<Props> = ({ labelWidth, onChange, refIds, query }) => {
return (
<InlineFieldRow>
<InlineField label="Function" labelWidth={labelWidth}>
<Select options={reducerTypes} value={reducer} onChange={onSelectReducer} width={25} />
<Select menuShouldPortal options={reducerTypes} value={reducer} onChange={onSelectReducer} width={25} />
</InlineField>
<InlineField label="Input" labelWidth={labelWidth}>
<Select onChange={onRefIdChange} options={refIds} value={query.expression} width={20} />
<Select menuShouldPortal onChange={onRefIdChange} options={refIds} value={query.expression} width={20} />
</InlineField>
</InlineFieldRow>
);
@@ -34,7 +34,7 @@ export const Resample: FC<Props> = ({ labelWidth, onChange, refIds, query }) =>
<>
<InlineFieldRow>
<InlineField label="Input" labelWidth={labelWidth}>
<Select onChange={onRefIdChange} options={refIds} value={query.expression} width={20} />
<Select menuShouldPortal onChange={onRefIdChange} options={refIds} value={query.expression} width={20} />
</InlineField>
</InlineFieldRow>
<InlineFieldRow>
@@ -42,10 +42,22 @@ export const Resample: FC<Props> = ({ labelWidth, onChange, refIds, query }) =>
<Input onChange={onWindowChange} value={query.window} width={15} />
</InlineField>
<InlineField label="Downsample">
<Select options={downsamplingTypes} value={downsampler} onChange={onSelectDownsampler} width={25} />
<Select
menuShouldPortal
options={downsamplingTypes}
value={downsampler}
onChange={onSelectDownsampler}
width={25}
/>
</InlineField>
<InlineField label="Upsample">
<Select options={upsamplingTypes} value={upsampler} onChange={onSelectUpsampler} width={25} />
<Select
menuShouldPortal
options={upsamplingTypes}
value={upsampler}
onChange={onSelectUpsampler}
width={25}
/>
</InlineField>
</InlineFieldRow>
</>
@@ -104,6 +104,7 @@ export const InspectDataOptions: FC<Props> = ({
{data!.length > 1 && (
<Field label="Show data frame">
<Select
menuShouldPortal
options={selectableOptions}
value={selectedDataFrame}
onChange={onDataFrameChange}
@@ -132,7 +132,7 @@ export class InspectJSONTab extends PureComponent<Props, State> {
<>
<div className={styles.toolbar} aria-label={selectors.components.PanelInspector.Json.content}>
<Field label="Select source" className="flex-grow-1">
<Select options={jsonOptions} value={selected} onChange={this.onSelectChanged} />
<Select menuShouldPortal options={jsonOptions} value={selected} onChange={this.onSelectChanged} />
</Field>
{this.hasPanelJSON && isPanelJSON && canEdit && (
<Button className={styles.toolbarItem} onClick={this.onApplyPanelModel}>
@@ -54,6 +54,7 @@ export function OpenLibraryPanelModal({ libraryPanel, onDismiss }: OpenLibraryPa
.Please choose which dashboard to view the panel in:
</p>
<AsyncSelect
menuShouldPortal
isClearable
isLoading={loading}
defaultOptions={true}
@@ -86,6 +86,7 @@ export default function Browse({ route }: GrafanaRouteComponentProps): ReactElem
</div>
<div>
<Select
menuShouldPortal
width={24}
value={sortBy}
onChange={onSortByChange}
@@ -49,6 +49,7 @@ export class TeamMemberRow extends PureComponent<Props> {
<div className="gf-form">
{signedInUserIsTeamAdmin && (
<Select
menuShouldPortal
isSearchable={false}
options={teamsPermissionLevels}
onChange={(item) => this.onPermissionChange(item, member)}
@@ -107,6 +107,7 @@ exports[`Render when feature toggle editorsCanAdmin is turned off should not ren
isMulti={false}
isSearchable={false}
maxMenuHeight={300}
menuShouldPortal={true}
onChange={[Function]}
openMenuOnFocus={false}
options={
@@ -197,6 +198,7 @@ exports[`Render when feature toggle editorsCanAdmin is turned on should render p
isMulti={false}
isSearchable={false}
maxMenuHeight={300}
menuShouldPortal={true}
onChange={[Function]}
openMenuOnFocus={false}
options={
@@ -33,6 +33,7 @@ export function VariableSelectField({
</InlineFormLabel>
<div aria-label={ariaLabel}>
<Select
menuShouldPortal
onChange={onChange}
value={value}
width={width ?? 25}
@@ -21,6 +21,7 @@ export const Aggregation: FC<Props> = (props) => {
return (
<QueryEditorField labelWidth={18} label="Group by function" data-testid="cloud-monitoring-aggregation">
<Select
menuShouldPortal
width={16}
onChange={({ value }) => props.onChange(value!)}
value={selected}
@@ -20,6 +20,7 @@ export const AlignmentFunction: FC<Props> = ({ query, templateVariableOptions, o
return (
<Select
menuShouldPortal
width={SELECT_WIDTH}
onChange={({ value }) => onChange({ ...query, perSeriesAligner: value! })}
value={[...alignOptions, ...templateVariableOptions].find((s) => s.value === perSeriesAligner)}
@@ -24,6 +24,7 @@ export const AlignmentPeriod: FC<Props> = ({ templateVariableOptions, onChange,
return (
<Select
menuShouldPortal
width={selectWidth}
onChange={({ value }) => onChange({ ...query, alignmentPeriod: value! })}
value={[...options, ...templateVariableOptions].find((s) => s.value === query.alignmentPeriod)}
@@ -71,6 +71,7 @@ export class ConfigEditor extends PureComponent<Props> {
<FieldSet>
<InlineField label="Authentication type" labelWidth={20}>
<Select
menuShouldPortal
width={40}
value={authTypes.find((x) => x.value === jsonData.authenticationType) || authTypes[0]}
options={authTypes}
@@ -22,6 +22,7 @@ export const VariableQueryField: FC<VariableQueryFieldProps> = ({
return (
<InlineField label={label} labelWidth={20}>
<Select
menuShouldPortal
width={25}
allowCustomValue={allowCustomValue}
value={value}
@@ -32,6 +32,7 @@ export const GroupBy: FunctionComponent<Props> = ({
tooltip="You can reduce the amount of data returned for a metric by combining different time series. To combine multiple time series, you can specify a grouping and a function. Grouping is done on the basis of labels. The grouping function is used to combine the time series in the group into a single time series."
>
<MultiSelect
menuShouldPortal
width={INPUT_WIDTH}
placeholder="Choose label"
options={options}
@@ -54,6 +54,7 @@ export const LabelFilter: FunctionComponent<Props> = ({
const AddFilter = () => {
return (
<Select
menuShouldPortal
allowCustomValue
options={[variableOptionGroup, ...labelsToGroupedOptions(Object.keys(labels))]}
onChange={({ value: key = '' }) =>
@@ -77,6 +78,7 @@ export const LabelFilter: FunctionComponent<Props> = ({
{filters.map(({ key, operator, value, condition }, index) => (
<HorizontalGroup key={index} spacing="xs" width="auto">
<Select
menuShouldPortal
width={SELECT_WIDTH}
allowCustomValue
formatCreateLabel={(v) => `Use label key: ${v}`}
@@ -91,6 +93,7 @@ export const LabelFilter: FunctionComponent<Props> = ({
}}
/>
<Select
menuShouldPortal
value={operator}
options={operators.map(toOption)}
onChange={({ value: operator = '=' }) =>
@@ -100,6 +103,7 @@ export const LabelFilter: FunctionComponent<Props> = ({
renderControl={OperatorButton}
/>
<Select
menuShouldPortal
width={SELECT_WIDTH}
formatCreateLabel={(v) => `Use label value: ${v}`}
allowCustomValue
@@ -123,6 +123,7 @@ export function Metrics(props: Props) {
<QueryEditorRow>
<QueryEditorField labelWidth={LABEL_WIDTH} label="Service">
<Select
menuShouldPortal
width={SELECT_WIDTH}
onChange={onServiceChange}
value={[...services, ...templateVariableOptions].find((s) => s.value === service)}
@@ -138,6 +139,7 @@ export function Metrics(props: Props) {
</QueryEditorField>
<QueryEditorField label="Metric name" labelWidth={INNER_LABEL_WIDTH}>
<Select
menuShouldPortal
width={SELECT_WIDTH}
onChange={onMetricTypeChange}
value={[...metrics, ...templateVariableOptions].find((s) => s.value === metricType)}
@@ -29,6 +29,7 @@ export function Project({ projectName, datasource, onChange, templateVariableOpt
return (
<QueryEditorRow label="Project">
<Select
menuShouldPortal
width={SELECT_WIDTH}
allowCustomValue
formatCreateLabel={(v) => `Use project: ${v}`}
@@ -76,6 +76,7 @@ export class QueryEditor extends PureComponent<Props> {
}
>
<Select
menuShouldPortal
width={SELECT_WIDTH}
value={queryType}
options={QUERY_TYPES}
@@ -36,6 +36,7 @@ export const SLO: React.FC<Props> = ({ query, templateVariableOptions, onChange,
return (
<QueryEditorRow label="SLO">
<Select
menuShouldPortal
width={SELECT_WIDTH}
allowCustomValue
value={query?.sloId && { value: query?.sloId, label: query?.sloName || query?.sloId }}
@@ -17,6 +17,7 @@ export const Selector: React.FC<Props> = ({ query, templateVariableOptions, onCh
return (
<QueryEditorRow label="Selector">
<Select
menuShouldPortal
width={SELECT_WIDTH}
allowCustomValue
value={[...SELECTORS, ...templateVariableOptions].find((s) => s.value === query?.selectorName ?? '')}
@@ -36,6 +36,7 @@ export const Service: React.FC<Props> = ({ query, templateVariableOptions, onCha
return (
<QueryEditorRow label="Service">
<Select
menuShouldPortal
width={SELECT_WIDTH}
allowCustomValue
value={query?.serviceId && { value: query?.serviceId, label: query?.serviceName || query?.serviceId }}

Some files were not shown because too many files have changed in this diff Show More