mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Grafana/UI: Add disable prop to Segment (#30539)
* Grafana/UI: Add disable prop to Segment SegmentSync, SegmentAsync and SegmentInput had the disable prop inherited from HTMLProp but it did not disable the component. The disable prop should now disable the component. * Use InlineLabel instead of span and remove some sass-classes in Segments * Change MetricsQueryEditor test to reflect new layout of AsyncSegment * Use useStyles hook to get themed styles for segment inputs Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
This commit is contained in:
parent
fad81e1696
commit
07bb6b8dae
@ -3,6 +3,9 @@ import { cx } from 'emotion';
|
||||
import _ from 'lodash';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { SegmentSelect, useExpandableLabel, SegmentProps } from './';
|
||||
import { getSegmentStyles } from './styles';
|
||||
import { InlineLabel } from '../Forms/InlineLabel';
|
||||
import { useStyles } from '../../themes';
|
||||
|
||||
export interface SegmentSyncProps<T> extends SegmentProps<T>, Omit<HTMLProps<HTMLDivElement>, 'value' | 'onChange'> {
|
||||
value?: T | SelectableValue<T>;
|
||||
@ -18,19 +21,32 @@ export function Segment<T>({
|
||||
className,
|
||||
allowCustomValue,
|
||||
placeholder,
|
||||
disabled,
|
||||
...rest
|
||||
}: React.PropsWithChildren<SegmentSyncProps<T>>) {
|
||||
const [Label, width, expanded, setExpanded] = useExpandableLabel(false);
|
||||
const styles = useStyles(getSegmentStyles);
|
||||
|
||||
if (!expanded) {
|
||||
const label = _.isObject(value) ? value.label : value;
|
||||
|
||||
return (
|
||||
<Label
|
||||
disabled={disabled}
|
||||
Component={
|
||||
Component || (
|
||||
<a className={cx('gf-form-label', 'query-part', !value && placeholder && 'query-placeholder', className)}>
|
||||
<InlineLabel
|
||||
className={cx(
|
||||
styles.segment,
|
||||
{
|
||||
[styles.queryPlaceholder]: placeholder !== undefined && !value,
|
||||
[styles.disabled]: disabled,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{label || placeholder}
|
||||
</a>
|
||||
</InlineLabel>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
@ -6,6 +6,9 @@ import { SelectableValue } from '@grafana/data';
|
||||
import { useExpandableLabel, SegmentProps } from '.';
|
||||
import { useAsyncFn } from 'react-use';
|
||||
import { AsyncState } from 'react-use/lib/useAsync';
|
||||
import { getSegmentStyles } from './styles';
|
||||
import { InlineLabel } from '../Forms/InlineLabel';
|
||||
import { useStyles } from '../../themes';
|
||||
|
||||
export interface SegmentAsyncProps<T> extends SegmentProps<T>, Omit<HTMLProps<HTMLDivElement>, 'value' | 'onChange'> {
|
||||
value?: T | SelectableValue<T>;
|
||||
@ -20,22 +23,35 @@ export function SegmentAsync<T>({
|
||||
Component,
|
||||
className,
|
||||
allowCustomValue,
|
||||
disabled,
|
||||
placeholder,
|
||||
...rest
|
||||
}: React.PropsWithChildren<SegmentAsyncProps<T>>) {
|
||||
const [state, fetchOptions] = useAsyncFn(loadOptions, [loadOptions]);
|
||||
const [Label, width, expanded, setExpanded] = useExpandableLabel(false);
|
||||
const styles = useStyles(getSegmentStyles);
|
||||
|
||||
if (!expanded) {
|
||||
const label = _.isObject(value) ? value.label : value;
|
||||
|
||||
return (
|
||||
<Label
|
||||
onClick={fetchOptions}
|
||||
disabled={disabled}
|
||||
Component={
|
||||
Component || (
|
||||
<a className={cx('gf-form-label', 'query-part', !value && placeholder && 'query-placeholder', className)}>
|
||||
<InlineLabel
|
||||
className={cx(
|
||||
styles.segment,
|
||||
{
|
||||
[styles.queryPlaceholder]: placeholder !== undefined && !value,
|
||||
[styles.disabled]: disabled,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{label || placeholder}
|
||||
</a>
|
||||
</InlineLabel>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
@ -3,6 +3,9 @@ import { cx, css } from 'emotion';
|
||||
import useClickAway from 'react-use/lib/useClickAway';
|
||||
import { measureText } from '../../utils/measureText';
|
||||
import { useExpandableLabel, SegmentProps } from '.';
|
||||
import { getSegmentStyles } from './styles';
|
||||
import { InlineLabel } from '../Forms/InlineLabel';
|
||||
import { useStyles } from '../../themes';
|
||||
|
||||
export interface SegmentInputProps<T> extends SegmentProps<T>, Omit<HTMLProps<HTMLInputElement>, 'value' | 'onChange'> {
|
||||
value: string | number;
|
||||
@ -18,6 +21,7 @@ export function SegmentInput<T>({
|
||||
Component,
|
||||
className,
|
||||
placeholder,
|
||||
disabled,
|
||||
autofocus = false,
|
||||
...rest
|
||||
}: React.PropsWithChildren<SegmentInputProps<T>>) {
|
||||
@ -25,6 +29,7 @@ export function SegmentInput<T>({
|
||||
const [value, setValue] = useState<number | string>(initialValue);
|
||||
const [inputWidth, setInputWidth] = useState<number>(measureText((initialValue || '').toString(), FONT_SIZE).width);
|
||||
const [Label, , expanded, setExpanded] = useExpandableLabel(autofocus);
|
||||
const styles = useStyles(getSegmentStyles);
|
||||
|
||||
useClickAway(ref, () => {
|
||||
setExpanded(false);
|
||||
@ -34,11 +39,21 @@ export function SegmentInput<T>({
|
||||
if (!expanded) {
|
||||
return (
|
||||
<Label
|
||||
disabled={disabled}
|
||||
Component={
|
||||
Component || (
|
||||
<a className={cx('gf-form-label', 'query-part', !value && placeholder && 'query-placeholder', className)}>
|
||||
<InlineLabel
|
||||
className={cx(
|
||||
styles.segment,
|
||||
{
|
||||
[styles.queryPlaceholder]: placeholder !== undefined && !value,
|
||||
[styles.disabled]: disabled,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{initialValue || placeholder}
|
||||
</a>
|
||||
</InlineLabel>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
21
packages/grafana-ui/src/components/Segment/styles.ts
Normal file
21
packages/grafana-ui/src/components/Segment/styles.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { css } from 'emotion';
|
||||
|
||||
export const getSegmentStyles = (theme: GrafanaTheme) => {
|
||||
return {
|
||||
segment: css`
|
||||
cursor: pointer;
|
||||
width: auto;
|
||||
`,
|
||||
|
||||
queryPlaceholder: css`
|
||||
color: ${theme.palette.gray2};
|
||||
`,
|
||||
|
||||
disabled: css`
|
||||
cursor: not-allowed;
|
||||
opacity: 0.65;
|
||||
box-shadow: none;
|
||||
`,
|
||||
};
|
||||
};
|
@ -5,4 +5,5 @@ export interface SegmentProps<T> {
|
||||
className?: string;
|
||||
allowCustomValue?: boolean;
|
||||
placeholder?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import React, { useState, useRef, ReactElement } from 'react';
|
||||
interface LabelProps {
|
||||
Component: ReactElement;
|
||||
onClick?: () => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export const useExpandableLabel = (
|
||||
@ -12,10 +13,13 @@ export const useExpandableLabel = (
|
||||
const [expanded, setExpanded] = useState<boolean>(initialExpanded);
|
||||
const [width, setWidth] = useState(0);
|
||||
|
||||
const Label: React.FC<LabelProps> = ({ Component, onClick }) => (
|
||||
const Label: React.FC<LabelProps> = ({ Component, onClick, disabled }) => (
|
||||
<div
|
||||
ref={ref}
|
||||
onClick={() => {
|
||||
onClick={
|
||||
disabled
|
||||
? undefined
|
||||
: () => {
|
||||
setExpanded(true);
|
||||
if (ref && ref.current) {
|
||||
setWidth(ref.current.clientWidth * 1.25);
|
||||
@ -23,7 +27,8 @@ export const useExpandableLabel = (
|
||||
if (onClick) {
|
||||
onClick();
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
>
|
||||
{Component}
|
||||
</div>
|
||||
|
@ -107,9 +107,9 @@ describe('QueryEditor', () => {
|
||||
const props = setup();
|
||||
props.query.region = (null as unknown) as string;
|
||||
const wrapper = mount(<MetricsQueryEditor {...props} />);
|
||||
expect(wrapper.find('.gf-form-inline').first().find('.gf-form-label.query-part').first().text()).toEqual(
|
||||
'default'
|
||||
);
|
||||
expect(
|
||||
wrapper.find('.gf-form-inline').first().find('Segment').find('InlineLabel').find('label').text()
|
||||
).toEqual('default');
|
||||
});
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user