mirror of
https://github.com/grafana/grafana.git
synced 2025-02-10 23:55:47 -06:00
Merge remote-tracking branch 'origin/main' into resource-store
This commit is contained in:
commit
6a08224725
@ -1,129 +0,0 @@
|
||||
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/packages/grafana-ui/src/components/Select/SelectBase.tsx
|
||||
import { cx } from '@emotion/css';
|
||||
import { max } from 'lodash';
|
||||
import { RefCallback } from 'react';
|
||||
import * as React from 'react';
|
||||
import { MenuListProps } from 'react-select';
|
||||
import { FixedSizeList as List } from 'react-window';
|
||||
|
||||
import { SelectableValue, toIconName } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { CustomScrollbar, Icon, getSelectStyles, useTheme2 } from '@grafana/ui';
|
||||
|
||||
interface SelectMenuProps {
|
||||
maxHeight: number;
|
||||
innerRef: RefCallback<HTMLDivElement>;
|
||||
innerProps: {};
|
||||
}
|
||||
|
||||
export const SelectMenu = ({ children, maxHeight, innerRef, innerProps }: React.PropsWithChildren<SelectMenuProps>) => {
|
||||
const theme = useTheme2();
|
||||
const styles = getSelectStyles(theme);
|
||||
|
||||
return (
|
||||
<div {...innerProps} className={styles.menu} style={{ maxHeight }} aria-label="Select options menu">
|
||||
<CustomScrollbar scrollRefCallback={innerRef} autoHide={false} autoHeightMax="inherit" hideHorizontalTrack>
|
||||
{children}
|
||||
</CustomScrollbar>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
SelectMenu.displayName = 'SelectMenu';
|
||||
|
||||
const VIRTUAL_LIST_ITEM_HEIGHT = 37;
|
||||
const VIRTUAL_LIST_WIDTH_ESTIMATE_MULTIPLIER = 7;
|
||||
|
||||
// A virtualized version of the SelectMenu, descriptions for SelectableValue options not supported since those are of a variable height.
|
||||
//
|
||||
// To support the virtualized list we have to "guess" the width of the menu container based on the longest available option.
|
||||
// the reason for this is because all of the options will be positioned absolute, this takes them out of the document and no space
|
||||
// is created for them, thus the container can't grow to accomodate.
|
||||
//
|
||||
// VIRTUAL_LIST_ITEM_HEIGHT and WIDTH_ESTIMATE_MULTIPLIER are both magic numbers.
|
||||
// Some characters (such as emojis and other unicode characters) may consist of multiple code points in which case the width would be inaccurate (but larger than needed).
|
||||
export const VirtualizedSelectMenu = ({ children, maxHeight, options, getValue }: MenuListProps<SelectableValue>) => {
|
||||
const theme = useTheme2();
|
||||
const styles = getSelectStyles(theme);
|
||||
const [value] = getValue();
|
||||
|
||||
const valueIndex = value ? options.findIndex((option: SelectableValue<unknown>) => option.value === value.value) : 0;
|
||||
const initialOffset = valueIndex * VIRTUAL_LIST_ITEM_HEIGHT;
|
||||
|
||||
if (!Array.isArray(children)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const longestOption = max(options.map((option) => option.label?.length)) ?? 0;
|
||||
const widthEstimate = longestOption * VIRTUAL_LIST_WIDTH_ESTIMATE_MULTIPLIER;
|
||||
const heightEstimate = Math.min(options.length * VIRTUAL_LIST_ITEM_HEIGHT, maxHeight);
|
||||
|
||||
return (
|
||||
<List
|
||||
className={styles.menu}
|
||||
height={heightEstimate}
|
||||
width={widthEstimate}
|
||||
aria-label="Select options menu"
|
||||
itemCount={children.length}
|
||||
itemSize={VIRTUAL_LIST_ITEM_HEIGHT}
|
||||
initialScrollOffset={initialOffset}
|
||||
>
|
||||
{({ index, style }) => <div style={{ ...style, overflow: 'hidden' }}>{children[index]}</div>}
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
VirtualizedSelectMenu.displayName = 'VirtualizedSelectMenu';
|
||||
|
||||
interface SelectMenuOptionProps<T> {
|
||||
isDisabled: boolean;
|
||||
isFocused: boolean;
|
||||
isSelected: boolean;
|
||||
innerProps: JSX.IntrinsicElements['div'];
|
||||
innerRef: RefCallback<HTMLDivElement>;
|
||||
renderOptionLabel?: (value: SelectableValue<T>) => JSX.Element;
|
||||
data: SelectableValue<T>;
|
||||
}
|
||||
|
||||
export const SelectMenuOptions = ({
|
||||
children,
|
||||
data,
|
||||
innerProps,
|
||||
innerRef,
|
||||
isFocused,
|
||||
isSelected,
|
||||
renderOptionLabel,
|
||||
}: React.PropsWithChildren<SelectMenuOptionProps<unknown>>) => {
|
||||
const theme = useTheme2();
|
||||
const styles = getSelectStyles(theme);
|
||||
const icon = data.icon ? toIconName(data.icon) : undefined;
|
||||
// We are removing onMouseMove and onMouseOver from innerProps because they cause the whole
|
||||
// list to re-render everytime the user hovers over an option. This is a performance issue.
|
||||
// See https://github.com/JedWatson/react-select/issues/3128#issuecomment-451936743
|
||||
const { onMouseMove, onMouseOver, ...rest } = innerProps;
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={innerRef}
|
||||
className={cx(
|
||||
styles.option,
|
||||
isFocused && styles.optionFocused,
|
||||
isSelected && styles.optionSelected,
|
||||
data.isDisabled && styles.optionDisabled
|
||||
)}
|
||||
{...rest}
|
||||
data-testid={selectors.components.Select.option}
|
||||
title={data.title}
|
||||
>
|
||||
{icon && <Icon name={icon} className={styles.optionIcon} />}
|
||||
{data.imgUrl && <img className={styles.optionImage} src={data.imgUrl} alt={data.label || String(data.value)} />}
|
||||
<div className={styles.optionBody}>
|
||||
<span>{renderOptionLabel ? renderOptionLabel(data) : children}</span>
|
||||
{data.description && <div className={styles.optionDescription}>{data.description}</div>}
|
||||
{data.component && <data.component />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
SelectMenuOptions.displayName = 'SelectMenuOptions';
|
@ -18,12 +18,12 @@ import {
|
||||
Icon,
|
||||
InlineField,
|
||||
InlineFieldRow,
|
||||
SelectMenuOptions,
|
||||
useStyles2,
|
||||
useTheme2,
|
||||
} from '@grafana/ui';
|
||||
|
||||
import { PrometheusDatasource } from '../../datasource';
|
||||
import { SelectMenuOptions } from '../../gcopypaste/packages/grafana-ui/src/components/Select/SelectBase';
|
||||
import { truncateResult } from '../../language_utils';
|
||||
import { regexifyLabelValuesQueryString } from '../parsingUtils';
|
||||
import { QueryBuilderLabelFilter } from '../shared/types';
|
||||
|
Loading…
Reference in New Issue
Block a user