mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Input: Width prop (#23615)
* Add width property * Remove unused import * Spelling mistake * Add width to interface * Make width optional * Remove size * Update snapshot * Remove size from places * Add size prop for button * Update width * Update snapshots
This commit is contained in:
parent
a2d741f60f
commit
9bbc007cb9
@ -207,6 +207,7 @@
|
||||
"@grafana/slate-react": "0.22.9-grafana",
|
||||
"@reduxjs/toolkit": "1.3.4",
|
||||
"@torkelo/react-select": "3.0.8",
|
||||
"@types/braintree__sanitize-url": "4.0.0",
|
||||
"@types/md5": "^2.1.33",
|
||||
"@types/react-loadable": "5.5.2",
|
||||
"@types/react-virtualized-auto-sizer": "1.0.0",
|
||||
|
@ -57,7 +57,6 @@ export const withCustomValue = () => {
|
||||
formatCreateLabel={val => onCreateLabel + val}
|
||||
initialValue="Custom Initial Value"
|
||||
onSelect={val => console.log(val)}
|
||||
size="md"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -3,7 +3,6 @@ import { Icon } from '../Icon/Icon';
|
||||
import RCCascader from 'rc-cascader';
|
||||
|
||||
import { Select } from '../Select/Select';
|
||||
import { FormInputSize } from '../Forms/types';
|
||||
import { Input } from '../Input/Input';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { css } from 'emotion';
|
||||
@ -15,7 +14,8 @@ interface CascaderProps {
|
||||
placeholder?: string;
|
||||
options: CascaderOption[];
|
||||
onSelect(val: string): void;
|
||||
size?: FormInputSize;
|
||||
/** Sets the width to a multiple of 8px. Should only be used with inline forms. Setting width of the container is preferred in other cases.*/
|
||||
width?: number;
|
||||
initialValue?: string;
|
||||
allowCustomValue?: boolean;
|
||||
/** A function for formatting the message for custom value creation. Only applies when allowCustomValue is set to true*/
|
||||
@ -174,7 +174,7 @@ export class Cascader extends React.PureComponent<CascaderProps, CascaderState>
|
||||
};
|
||||
|
||||
render() {
|
||||
const { size, allowCustomValue, placeholder } = this.props;
|
||||
const { allowCustomValue, placeholder, width } = this.props;
|
||||
const { focusCascade, isSearching, searchableOptions, rcValue, activeLabel } = this.state;
|
||||
|
||||
return (
|
||||
@ -187,9 +187,9 @@ export class Cascader extends React.PureComponent<CascaderProps, CascaderState>
|
||||
onChange={this.onSelect}
|
||||
onBlur={this.onBlur}
|
||||
options={searchableOptions}
|
||||
size={size}
|
||||
onCreateOption={this.onCreateOption}
|
||||
formatCreateLabel={this.props.formatCreateLabel}
|
||||
width={width}
|
||||
/>
|
||||
) : (
|
||||
<RCCascader
|
||||
@ -206,7 +206,7 @@ export class Cascader extends React.PureComponent<CascaderProps, CascaderState>
|
||||
>
|
||||
<div className={disableDivFocus}>
|
||||
<Input
|
||||
size={size}
|
||||
width={width}
|
||||
placeholder={placeholder}
|
||||
onBlur={this.onBlurCascade}
|
||||
value={activeLabel}
|
||||
|
@ -70,24 +70,18 @@ const renderForm = (defaultValues?: Partial<FormDTO>) => (
|
||||
<Legend>Edit user</Legend>
|
||||
|
||||
<Field label="Name" invalid={!!errors.name} error="Name is required">
|
||||
<Input name="name" placeholder="Roger Waters" size="md" ref={register({ required: true })} />
|
||||
<Input name="name" placeholder="Roger Waters" ref={register({ required: true })} />
|
||||
</Field>
|
||||
|
||||
<Field label="Email" invalid={!!errors.email} error="E-mail is required">
|
||||
<Input
|
||||
id="email"
|
||||
name="email"
|
||||
placeholder="roger.waters@grafana.com"
|
||||
size="md"
|
||||
ref={register({ required: true })}
|
||||
/>
|
||||
<Input id="email" name="email" placeholder="roger.waters@grafana.com" ref={register({ required: true })} />
|
||||
</Field>
|
||||
|
||||
<Field label="Username">
|
||||
<Input name="username" placeholder="mr.waters" size="md" ref={register} />
|
||||
<Input name="username" placeholder="mr.waters" ref={register} />
|
||||
</Field>
|
||||
<Field label="Nested object">
|
||||
<Input name="nested.path" placeholder="Nested path" size="md" ref={register} />
|
||||
<Input name="nested.path" placeholder="Nested path" ref={register} />
|
||||
</Field>
|
||||
|
||||
<Field label="Textarea" invalid={!!errors.text} error="Text is required">
|
||||
@ -185,7 +179,6 @@ export const asyncValidation = () => {
|
||||
<Input
|
||||
name="name"
|
||||
placeholder="Roger Waters"
|
||||
size="md"
|
||||
ref={register({ validate: validateAsync(passAsyncValidation) })}
|
||||
/>
|
||||
</Field>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useForm, Mode, OnSubmit, DeepPartial } from 'react-hook-form';
|
||||
import { FormAPI } from '../../types';
|
||||
import { css } from 'emotion';
|
||||
|
||||
interface FormProps<T> {
|
||||
validateOn?: Mode;
|
||||
@ -9,6 +10,8 @@ interface FormProps<T> {
|
||||
defaultValues?: DeepPartial<T>;
|
||||
onSubmit: OnSubmit<T>;
|
||||
children: (api: FormAPI<T>) => React.ReactNode;
|
||||
/** Sets max-width for container. Use it instead of setting individual widths on inputs.*/
|
||||
maxWidth?: number;
|
||||
}
|
||||
|
||||
export function Form<T>({
|
||||
@ -18,6 +21,7 @@ export function Form<T>({
|
||||
validateFieldsOnMount,
|
||||
children,
|
||||
validateOn = 'onSubmit',
|
||||
maxWidth = 400,
|
||||
}: FormProps<T>) {
|
||||
const { handleSubmit, register, errors, control, triggerValidation, getValues, formState } = useForm<T>({
|
||||
mode: validateOn,
|
||||
@ -30,5 +34,14 @@ export function Form<T>({
|
||||
}
|
||||
}, []);
|
||||
|
||||
return <form onSubmit={handleSubmit(onSubmit)}>{children({ register, errors, control, getValues, formState })}</form>;
|
||||
return (
|
||||
<form
|
||||
className={css`
|
||||
max-width: ${maxWidth}px;
|
||||
`}
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
>
|
||||
{children({ register, errors, control, getValues, formState })}
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
@ -12,11 +12,11 @@ Used for regular text input. For an array of data or tree-structured data, consi
|
||||
To add more context to the input you can add either text or an icon before or after the input. You can use the `prefix` and `suffix` props for this. Try some examples in the canvas!
|
||||
|
||||
```jsx
|
||||
<Input prefix={<Icon name="search" />} size="sm" />
|
||||
<Input prefix={<Icon name="search" />} />
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Input prefix={<Icon name="search" />} size="sm" />
|
||||
<Input prefix={<Icon name="search" />} />
|
||||
</Preview>
|
||||
|
||||
## Usage in forms with Field
|
||||
|
@ -50,6 +50,7 @@ export const simple = () => {
|
||||
|
||||
const VISUAL_GROUP = 'Visual options';
|
||||
// ---
|
||||
const width = number('Width', 0, undefined, VISUAL_GROUP);
|
||||
const placeholder = text('Placeholder', 'Enter your name here...', VISUAL_GROUP);
|
||||
const before = boolean('Addon before', false, VISUAL_GROUP);
|
||||
const after = boolean('Addon after', false, VISUAL_GROUP);
|
||||
@ -84,6 +85,7 @@ export const simple = () => {
|
||||
<div style={{ width: containerWidth }}>
|
||||
<Input
|
||||
disabled={disabled}
|
||||
width={width}
|
||||
prefix={prefixEl}
|
||||
invalid={invalid}
|
||||
suffix={suffixEl}
|
||||
|
@ -1,13 +1,14 @@
|
||||
import React, { HTMLProps, ReactNode } from 'react';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { css, cx } from 'emotion';
|
||||
import { getFocusStyle, inputSizes, sharedInputStyle } from '../Forms/commonStyles';
|
||||
import { getFocusStyle, sharedInputStyle } from '../Forms/commonStyles';
|
||||
import { stylesFactory, useTheme } from '../../themes';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { useClientRect } from '../../utils/useClientRect';
|
||||
import { FormInputSize } from '../Forms/types';
|
||||
|
||||
export interface Props extends Omit<HTMLProps<HTMLInputElement>, 'prefix' | 'size'> {
|
||||
/** Sets the width to a multiple of 8px. Should only be used with inline forms. Setting width of the container is preferred in other cases.*/
|
||||
width?: number;
|
||||
/** Show an invalid state around the input */
|
||||
invalid?: boolean;
|
||||
/** Show an icon as a prefix in the input */
|
||||
@ -20,15 +21,15 @@ export interface Props extends Omit<HTMLProps<HTMLInputElement>, 'prefix' | 'siz
|
||||
addonBefore?: ReactNode;
|
||||
/** Add a component as an addon after the input */
|
||||
addonAfter?: ReactNode;
|
||||
size?: FormInputSize;
|
||||
}
|
||||
|
||||
interface StyleDeps {
|
||||
theme: GrafanaTheme;
|
||||
invalid: boolean;
|
||||
width?: number;
|
||||
}
|
||||
|
||||
export const getInputStyles = stylesFactory(({ theme, invalid = false }: StyleDeps) => {
|
||||
export const getInputStyles = stylesFactory(({ theme, invalid = false, width }: StyleDeps) => {
|
||||
const { palette, colors } = theme;
|
||||
const borderRadius = theme.border.radius.sm;
|
||||
const height = theme.spacing.formInputHeight;
|
||||
@ -56,7 +57,7 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false }: StyleDe
|
||||
css`
|
||||
label: input-wrapper;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
width: ${width ? `${8 * width}px` : '100%'};
|
||||
height: ${height}px;
|
||||
border-radius: ${borderRadius};
|
||||
&:hover {
|
||||
@ -213,7 +214,7 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false }: StyleDe
|
||||
});
|
||||
|
||||
export const Input = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
|
||||
const { className, addonAfter, addonBefore, prefix, suffix, invalid, loading, size = 'auto', ...restProps } = props;
|
||||
const { className, addonAfter, addonBefore, prefix, suffix, invalid, loading, width = 0, ...restProps } = props;
|
||||
/**
|
||||
* Prefix & suffix are positioned absolutely within inputWrapper. We use client rects below to apply correct padding to the input
|
||||
* when prefix/suffix is larger than default (28px = 16px(icon) + 12px(left/right paddings)).
|
||||
@ -223,10 +224,10 @@ export const Input = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
|
||||
const [suffixRect, suffixRef] = useClientRect<HTMLDivElement>();
|
||||
|
||||
const theme = useTheme();
|
||||
const styles = getInputStyles({ theme, invalid: !!invalid });
|
||||
const styles = getInputStyles({ theme, invalid: !!invalid, width });
|
||||
|
||||
return (
|
||||
<div className={cx(styles.wrapper, inputSizes()[size], className)}>
|
||||
<div className={cx(styles.wrapper, className)}>
|
||||
{!!addonBefore && <div className={styles.addon}>{addonBefore}</div>}
|
||||
|
||||
<div className={styles.inputWrapper}>
|
||||
|
@ -29,7 +29,7 @@ Used for horizontally aligning several elements (e.g. Button, Select) with a pre
|
||||
<Preview>
|
||||
<HorizontalGroup>
|
||||
<Select
|
||||
size="sm"
|
||||
width={25}
|
||||
onChange={() => {}}
|
||||
options={[
|
||||
{ value: 1, label: "Option 1" },
|
||||
@ -37,7 +37,7 @@ Used for horizontally aligning several elements (e.g. Button, Select) with a pre
|
||||
]}
|
||||
/>
|
||||
<Select
|
||||
size="sm"
|
||||
width={25}
|
||||
onChange={() => {}}
|
||||
options={[
|
||||
{ value: 1, label: "Option 1" },
|
||||
@ -45,7 +45,7 @@ Used for horizontally aligning several elements (e.g. Button, Select) with a pre
|
||||
]}
|
||||
/>
|
||||
<Select
|
||||
size="sm"
|
||||
width={25}
|
||||
onChange={() => {}}
|
||||
options={[
|
||||
{ value: 1, label: "Option 1" },
|
||||
@ -69,7 +69,7 @@ Used for vertically aligning several elements (e.g. Button, Select) with a prede
|
||||
<Preview>
|
||||
<VerticalGroup justify="center">
|
||||
<Select
|
||||
size="sm"
|
||||
width={25}
|
||||
onChange={() => {}}
|
||||
options={[
|
||||
{ value: 1, label: "Option 1" },
|
||||
@ -77,7 +77,7 @@ Used for vertically aligning several elements (e.g. Button, Select) with a prede
|
||||
]}
|
||||
/>
|
||||
<Select
|
||||
size="sm"
|
||||
width={25}
|
||||
onChange={() => {}}
|
||||
options={[
|
||||
{ value: 1, label: "Option 1" },
|
||||
@ -85,7 +85,7 @@ Used for vertically aligning several elements (e.g. Button, Select) with a prede
|
||||
]}
|
||||
/>
|
||||
<Select
|
||||
size="sm"
|
||||
width={25}
|
||||
onChange={() => {}}
|
||||
options={[
|
||||
{ value: 1, label: "Option 1" },
|
||||
|
@ -80,7 +80,6 @@ const basicSelectAsync = () => {
|
||||
onChange={v => {
|
||||
setValue(v);
|
||||
}}
|
||||
size="md"
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -117,7 +116,6 @@ const multiSelect = () => {
|
||||
onChange={v => {
|
||||
setValue(v);
|
||||
}}
|
||||
size="md"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
@ -3,7 +3,7 @@ import { Select, AsyncSelect, MultiSelect, AsyncMultiSelect } from './Select';
|
||||
import { withCenteredStory, withHorizontallyCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { getAvailableIcons, IconName } from '../../types';
|
||||
import { select, boolean } from '@storybook/addon-knobs';
|
||||
import { select, boolean, number } from '@storybook/addon-knobs';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { Button } from '../Button';
|
||||
import { ButtonSelect } from './ButtonSelect';
|
||||
@ -50,6 +50,7 @@ const getKnobs = () => {
|
||||
const VISUAL_GROUP = 'Visual options';
|
||||
// ---
|
||||
const prefix = select('Prefix', prefixSuffixOpts, null, VISUAL_GROUP);
|
||||
const width = number('Width', 0, undefined, VISUAL_GROUP);
|
||||
|
||||
let prefixEl: any = prefix;
|
||||
if (prefix && prefix.match(/icon-/g)) {
|
||||
@ -57,6 +58,7 @@ const getKnobs = () => {
|
||||
}
|
||||
|
||||
return {
|
||||
width,
|
||||
disabled,
|
||||
invalid,
|
||||
loading,
|
||||
@ -67,6 +69,7 @@ const getKnobs = () => {
|
||||
const getDynamicProps = () => {
|
||||
const knobs = getKnobs();
|
||||
return {
|
||||
width: knobs.width,
|
||||
disabled: knobs.disabled,
|
||||
isLoading: knobs.loading,
|
||||
invalid: knobs.invalid,
|
||||
@ -85,7 +88,6 @@ export const basic = () => {
|
||||
onChange={v => {
|
||||
setValue(v);
|
||||
}}
|
||||
size="md"
|
||||
{...getDynamicProps()}
|
||||
/>
|
||||
</>
|
||||
@ -105,7 +107,6 @@ export const basicSelectPlainValue = () => {
|
||||
onChange={v => {
|
||||
setValue(v.value);
|
||||
}}
|
||||
size="md"
|
||||
{...getDynamicProps()}
|
||||
/>
|
||||
</>
|
||||
@ -138,7 +139,6 @@ export const SelectWithOptionDescriptions = () => {
|
||||
onChange={v => {
|
||||
setValue(v.value);
|
||||
}}
|
||||
size="md"
|
||||
{...getDynamicProps()}
|
||||
/>
|
||||
</>
|
||||
@ -159,7 +159,6 @@ export const multiPlainValue = () => {
|
||||
onChange={v => {
|
||||
setValue(v.map((v: any) => v.value));
|
||||
}}
|
||||
size="md"
|
||||
{...getDynamicProps()}
|
||||
/>
|
||||
</>
|
||||
@ -177,7 +176,6 @@ export const multiSelect = () => {
|
||||
onChange={v => {
|
||||
setValue(v);
|
||||
}}
|
||||
size="md"
|
||||
{...getDynamicProps()}
|
||||
/>
|
||||
</>
|
||||
@ -195,7 +193,6 @@ export const multiSelectAsync = () => {
|
||||
onChange={v => {
|
||||
setValue(v);
|
||||
}}
|
||||
size="md"
|
||||
allowCustomValue
|
||||
{...getDynamicProps()}
|
||||
/>
|
||||
@ -212,7 +209,6 @@ export const buttonSelect = () => {
|
||||
onChange={v => {
|
||||
setValue(v);
|
||||
}}
|
||||
size="md"
|
||||
allowCustomValue
|
||||
icon={icon}
|
||||
{...getDynamicProps()}
|
||||
@ -231,7 +227,6 @@ export const basicSelectAsync = () => {
|
||||
onChange={v => {
|
||||
setValue(v);
|
||||
}}
|
||||
size="md"
|
||||
{...getDynamicProps()}
|
||||
/>
|
||||
);
|
||||
@ -247,7 +242,6 @@ export const customizedControl = () => {
|
||||
onChange={v => {
|
||||
setValue(v);
|
||||
}}
|
||||
size="md"
|
||||
renderControl={React.forwardRef(({ isOpen, value, ...otherProps }, ref) => {
|
||||
return (
|
||||
<Button {...otherProps} ref={ref}>
|
||||
@ -266,14 +260,13 @@ export const autoMenuPlacement = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ height: '95vh', display: 'flex', alignItems: 'flex-end' }}>
|
||||
<div style={{ width: '100%', height: '95vh', display: 'flex', alignItems: 'flex-end' }}>
|
||||
<Select
|
||||
options={generateOptions()}
|
||||
value={value}
|
||||
onChange={v => {
|
||||
setValue(v);
|
||||
}}
|
||||
size="md"
|
||||
{...getDynamicProps()}
|
||||
/>
|
||||
</div>
|
||||
@ -293,7 +286,6 @@ export const customValueCreation = () => {
|
||||
onChange={v => {
|
||||
setValue(v);
|
||||
}}
|
||||
size="md"
|
||||
allowCustomValue
|
||||
onCreateOption={v => {
|
||||
const customValue: SelectableValue<string> = { value: kebabCase(v), label: v };
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { deprecationWarning } from '@grafana/data';
|
||||
// @ts-ignore
|
||||
import { default as ReactSelect } from '@torkelo/react-select';
|
||||
// @ts-ignore
|
||||
@ -11,7 +10,6 @@ import { default as AsyncCreatable } from '@torkelo/react-select/async-creatable
|
||||
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { css, cx } from 'emotion';
|
||||
import { inputSizesPixels } from '../Forms/commonStyles';
|
||||
import resetSelectStyles from './resetSelectStyles';
|
||||
import { SelectMenu, SelectMenuOptions } from './SelectMenu';
|
||||
import { IndicatorsContainer } from './IndicatorsContainer';
|
||||
@ -100,7 +98,6 @@ export function SelectBase<T>({
|
||||
placeholder = 'Choose',
|
||||
prefix,
|
||||
renderControl,
|
||||
size = 'auto',
|
||||
tabSelectsValue = true,
|
||||
className,
|
||||
value,
|
||||
@ -178,13 +175,6 @@ export function SelectBase<T>({
|
||||
value: isMulti ? selectedValue : selectedValue[0],
|
||||
};
|
||||
|
||||
// width property is deprecated in favor of size or className
|
||||
let widthClass = '';
|
||||
if (width) {
|
||||
deprecationWarning('Select', 'width property', 'size or className');
|
||||
widthClass = 'width-' + width;
|
||||
}
|
||||
|
||||
if (allowCustomValue) {
|
||||
ReactSelectComponent = Creatable;
|
||||
creatableProps.formatCreateLabel = formatCreateLabel ?? ((input: string) => `Create: ${input}`);
|
||||
@ -275,10 +265,10 @@ export function SelectBase<T>({
|
||||
}),
|
||||
container: () => ({
|
||||
position: 'relative',
|
||||
width: inputSizesPixels(size),
|
||||
width: width ? `${8 * width}px` : '100%',
|
||||
}),
|
||||
}}
|
||||
className={cx('select-container', widthClass, className)}
|
||||
className={cx('select-container', className)}
|
||||
{...commonSelectProps}
|
||||
{...creatableProps}
|
||||
{...asyncSelectProps}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import React from 'react';
|
||||
import { FormInputSize } from '../Forms/types';
|
||||
|
||||
export type SelectValue<T> = T | SelectableValue<T> | T[] | Array<SelectableValue<T>>;
|
||||
|
||||
@ -45,9 +44,9 @@ export interface SelectCommonProps<T> {
|
||||
prefix?: JSX.Element | string | null;
|
||||
/** Use a custom element to control Select. A proper ref to the renderControl is needed if 'portal' isn't set to null*/
|
||||
renderControl?: ControlComponent<T>;
|
||||
size?: FormInputSize;
|
||||
tabSelectsValue?: boolean;
|
||||
value?: SelectValue<T>;
|
||||
/** Sets the width to a multiple of 8px. Should only be used with inline forms. Setting width of the container is preferred in other cases.*/
|
||||
width?: number;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@ TimeZonePickerStories.add('default', () => {
|
||||
action('on selected')(newValue);
|
||||
updateValue({ value: newValue });
|
||||
}}
|
||||
size="sm"
|
||||
/>
|
||||
);
|
||||
}}
|
||||
|
@ -1,16 +1,15 @@
|
||||
import React, { FC } from 'react';
|
||||
import { getTimeZoneGroups } from '@grafana/data';
|
||||
import { Cascader } from '../index';
|
||||
import { FormInputSize } from '../Forms/types';
|
||||
|
||||
interface Props {
|
||||
value: string;
|
||||
size?: FormInputSize;
|
||||
width?: number;
|
||||
|
||||
onChange: (newValue: string) => void;
|
||||
}
|
||||
|
||||
export const TimeZonePicker: FC<Props> = ({ onChange, value, size = 'md' }) => {
|
||||
export const TimeZonePicker: FC<Props> = ({ onChange, value, width }) => {
|
||||
const timeZoneGroups = getTimeZoneGroups();
|
||||
|
||||
const groupOptions = timeZoneGroups.map(group => {
|
||||
@ -41,7 +40,7 @@ export const TimeZonePicker: FC<Props> = ({ onChange, value, size = 'md' }) => {
|
||||
options={groupOptions}
|
||||
initialValue={selectedValue?.value}
|
||||
onSelect={(newValue: string) => onChange(newValue)}
|
||||
size={size}
|
||||
width={width}
|
||||
placeholder="Select timezone"
|
||||
/>
|
||||
);
|
||||
|
@ -195,7 +195,7 @@ exports[`TimePicker renders buttons correctly 1`] = `
|
||||
"listItem": "-1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.3)",
|
||||
},
|
||||
"spacing": Object {
|
||||
"d": "14px",
|
||||
"d": "16px",
|
||||
"formButtonHeight": 32,
|
||||
"formFieldsetMargin": "16px",
|
||||
"formInputAffixPaddingHorizontal": "4px",
|
||||
@ -511,7 +511,7 @@ exports[`TimePicker renders content correctly after beeing open 1`] = `
|
||||
"listItem": "-1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.3)",
|
||||
},
|
||||
"spacing": Object {
|
||||
"d": "14px",
|
||||
"d": "16px",
|
||||
"formButtonHeight": 32,
|
||||
"formFieldsetMargin": "16px",
|
||||
"formInputAffixPaddingHorizontal": "4px",
|
||||
|
@ -25,7 +25,7 @@ export function ValuePicker<T>({
|
||||
options,
|
||||
onChange,
|
||||
variant,
|
||||
size,
|
||||
size = 'sm',
|
||||
isFullWidth = true,
|
||||
}: ValuePickerProps<T>) {
|
||||
const [isPicking, setIsPicking] = useState(false);
|
||||
|
@ -75,7 +75,7 @@ const theme: GrafanaThemeCommons = {
|
||||
},
|
||||
spacing: {
|
||||
insetSquishMd: '4px 8px',
|
||||
d: '14px',
|
||||
d: '16px',
|
||||
xxs: '2px',
|
||||
xs: '4px',
|
||||
sm: '8px',
|
||||
|
@ -15,8 +15,8 @@ export const FilterInput: FC<Props> = props => (
|
||||
// Replaces the usage of ref
|
||||
autoFocus
|
||||
prefix={<Icon name="search" />}
|
||||
width={40}
|
||||
type="text"
|
||||
size="md"
|
||||
value={props.value ? unEscapeStringFromRegex(props.value) : ''}
|
||||
onChange={event => props.onChange(escapeStringForRegex(event.currentTarget.value))}
|
||||
placeholder={props.placeholder ?? ''}
|
||||
|
@ -3,14 +3,13 @@ import { debounce } from 'lodash';
|
||||
import { useAsyncFn } from 'react-use';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { AsyncSelect } from '@grafana/ui';
|
||||
import { FormInputSize } from '@grafana/ui/src/components/Forms/types';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import { DashboardSearchHit, DashboardDTO } from 'app/types';
|
||||
|
||||
export interface Props {
|
||||
onSelected: (dashboard: DashboardDTO) => void;
|
||||
currentDashboard?: SelectableValue<number>;
|
||||
size?: FormInputSize;
|
||||
width?: number;
|
||||
isClearable?: boolean;
|
||||
invalid?: boolean;
|
||||
disabled?: boolean;
|
||||
@ -29,7 +28,7 @@ const getDashboards = (query = '') => {
|
||||
export const DashboardPicker: FC<Props> = ({
|
||||
onSelected,
|
||||
currentDashboard,
|
||||
size = 'md',
|
||||
width,
|
||||
isClearable = false,
|
||||
invalid,
|
||||
disabled,
|
||||
@ -43,7 +42,7 @@ export const DashboardPicker: FC<Props> = ({
|
||||
|
||||
return (
|
||||
<AsyncSelect
|
||||
size={size}
|
||||
width={width}
|
||||
isLoading={state.loading}
|
||||
isClearable={isClearable}
|
||||
defaultOptions={true}
|
||||
|
@ -1,21 +1,20 @@
|
||||
import React, { FC } from 'react';
|
||||
import { OrgRole } from '@grafana/data';
|
||||
import { Select, FormInputSize } from '@grafana/ui';
|
||||
import { Select } from '@grafana/ui';
|
||||
|
||||
interface Props {
|
||||
value: OrgRole;
|
||||
size?: FormInputSize;
|
||||
onChange: (role: OrgRole) => void;
|
||||
}
|
||||
|
||||
const options = Object.keys(OrgRole).map(key => ({ label: key, value: key }));
|
||||
|
||||
export const OrgRolePicker: FC<Props> = ({ value, onChange, size }) => (
|
||||
export const OrgRolePicker: FC<Props> = ({ value, onChange, ...restProps }) => (
|
||||
<Select
|
||||
size={size}
|
||||
value={value}
|
||||
options={options}
|
||||
onChange={val => onChange(val.value as OrgRole)}
|
||||
placeholder="Choose role..."
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
|
@ -37,15 +37,15 @@ const UserCreatePage: React.FC<UserCreatePageProps> = ({ navModel, updateLocatio
|
||||
return (
|
||||
<>
|
||||
<Field label="Name" required invalid={!!errors.name} error={!!errors.name && 'Name is required'}>
|
||||
<Input name="name" size="md" ref={register({ required: true })} />
|
||||
<Input name="name" ref={register({ required: true })} />
|
||||
</Field>
|
||||
|
||||
<Field label="E-mail">
|
||||
<Input name="email" size="md" ref={register} />
|
||||
<Input name="email" ref={register} />
|
||||
</Field>
|
||||
|
||||
<Field label="Username">
|
||||
<Input name="login" size="md" ref={register} />
|
||||
<Input name="login" ref={register} />
|
||||
</Field>
|
||||
<Field
|
||||
label="Password"
|
||||
@ -54,7 +54,6 @@ const UserCreatePage: React.FC<UserCreatePageProps> = ({ navModel, updateLocatio
|
||||
error={!!errors.password && 'Password is required and must contain at least 4 characters'}
|
||||
>
|
||||
<Input
|
||||
size="md"
|
||||
type="password"
|
||||
name="password"
|
||||
ref={register({
|
||||
|
@ -43,7 +43,7 @@ const UserListAdminPageUnConnected: React.FC<Props> = props => {
|
||||
<div>
|
||||
<HorizontalGroup justify="space-between">
|
||||
<Input
|
||||
size="md"
|
||||
width={40}
|
||||
type="text"
|
||||
placeholder="Search user by login,email or name"
|
||||
tabIndex={1}
|
||||
|
@ -267,7 +267,6 @@ export class UserProfileRow extends PureComponent<UserProfileRowProps, UserProfi
|
||||
<td className="width-25" colSpan={2}>
|
||||
{this.state.editing ? (
|
||||
<Input
|
||||
size="md"
|
||||
type={inputType}
|
||||
defaultValue={value}
|
||||
onBlur={this.onInputBlur}
|
||||
|
@ -90,7 +90,6 @@ export const OverrideFieldConfigEditor: React.FC<Props> = props => {
|
||||
<ValuePicker
|
||||
icon="plus"
|
||||
label="Add override"
|
||||
size="md"
|
||||
variant="secondary"
|
||||
options={fieldMatchersUI
|
||||
.list()
|
||||
|
@ -161,7 +161,6 @@ export const OverrideEditor: React.FC<OverrideEditorProps> = ({
|
||||
<ValuePicker
|
||||
label="Add override property"
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
icon="plus"
|
||||
options={configPropertiesOptions}
|
||||
onChange={o => {
|
||||
|
@ -52,7 +52,6 @@ export class TransformationsEditor extends React.PureComponent<Props> {
|
||||
|
||||
return (
|
||||
<ValuePicker
|
||||
size="md"
|
||||
variant="secondary"
|
||||
label="Add transformation"
|
||||
options={availableTransformers}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
exports[`MetaInfoText should render component 1`] = `
|
||||
<div
|
||||
className="css-1u65mbf"
|
||||
className="css-1jdkzq2"
|
||||
>
|
||||
<Memo(MetaInfoItem)
|
||||
key="0-label"
|
||||
|
@ -85,7 +85,6 @@ class DashboardImportUnConnected extends PureComponent<Props> {
|
||||
{({ register, errors }) => (
|
||||
<Field invalid={!!errors.gcomDashboard} error={errors.gcomDashboard && errors.gcomDashboard.message}>
|
||||
<Input
|
||||
size="md"
|
||||
name="gcomDashboard"
|
||||
placeholder="Grafana.com dashboard url or id"
|
||||
type="text"
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React, { FC, useEffect, useState } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Forms,
|
||||
FormAPI,
|
||||
FormsOnSubmit,
|
||||
HorizontalGroup,
|
||||
@ -9,6 +8,7 @@ import {
|
||||
Input,
|
||||
Field,
|
||||
InputControl,
|
||||
Legend,
|
||||
} from '@grafana/ui';
|
||||
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
|
||||
import DataSourcePicker from 'app/core/components/Select/DataSourcePicker';
|
||||
@ -51,11 +51,10 @@ export const ImportDashboardForm: FC<Props> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Forms.Legend>Options</Forms.Legend>
|
||||
<Legend>Options</Legend>
|
||||
<Field label="Name" invalid={!!errors.title} error={errors.title && errors.title.message}>
|
||||
<Input
|
||||
name="title"
|
||||
size="md"
|
||||
type="text"
|
||||
ref={register({
|
||||
required: 'Name is required',
|
||||
@ -83,18 +82,13 @@ export const ImportDashboardForm: FC<Props> = ({
|
||||
<>
|
||||
{!uidReset ? (
|
||||
<Input
|
||||
size="md"
|
||||
name="uid"
|
||||
disabled
|
||||
ref={register({ validate: async (v: string) => await validateUid(v) })}
|
||||
addonAfter={!uidReset && <Button onClick={onUidReset}>Change uid</Button>}
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
size="md"
|
||||
name="uid"
|
||||
ref={register({ required: true, validate: async (v: string) => await validateUid(v) })}
|
||||
/>
|
||||
<Input name="uid" ref={register({ required: true, validate: async (v: string) => await validateUid(v) })} />
|
||||
)}
|
||||
</>
|
||||
</Field>
|
||||
@ -129,12 +123,7 @@ export const ImportDashboardForm: FC<Props> = ({
|
||||
invalid={errors.constants && !!errors.constants[index]}
|
||||
key={constantIndex}
|
||||
>
|
||||
<Input
|
||||
ref={register({ required: true })}
|
||||
name={`${constantIndex}`}
|
||||
size="md"
|
||||
defaultValue={input.value}
|
||||
/>
|
||||
<Input ref={register({ required: true })} name={`${constantIndex}`} defaultValue={input.value} />
|
||||
</Field>
|
||||
);
|
||||
})}
|
||||
|
@ -55,7 +55,6 @@ export const NewOrgPage: FC<PropsWithState> = ({ navModel }) => {
|
||||
<>
|
||||
<Field label="Organization name" invalid={!!errors.name} error={errors.name && errors.name.message}>
|
||||
<Input
|
||||
size="md"
|
||||
placeholder="Org. name"
|
||||
name="name"
|
||||
ref={register({
|
||||
|
@ -63,10 +63,10 @@ export const UserInviteForm: FC<Props> = ({ updateLocation }) => {
|
||||
error={!!errors.loginOrEmail && 'Email or Username is required'}
|
||||
label="Email or Username"
|
||||
>
|
||||
<Input size="md" name="loginOrEmail" placeholder="email@example.com" ref={register({ required: true })} />
|
||||
<Input name="loginOrEmail" placeholder="email@example.com" ref={register({ required: true })} />
|
||||
</Field>
|
||||
<Field invalid={!!errors.name} label="Name">
|
||||
<Input size="md" name="name" placeholder="(optional)" ref={register} />
|
||||
<Input name="name" placeholder="(optional)" ref={register} />
|
||||
</Field>
|
||||
<Field invalid={!!errors.role} label="Role">
|
||||
<InputControl as={RadioButtonGroup} control={control} options={roles} name="role" />
|
||||
|
@ -66,20 +66,19 @@ export const SignupForm: FC<Props> = props => {
|
||||
<>
|
||||
{verifyEmailEnabled && (
|
||||
<Field label="Email verification code (sent to your email)">
|
||||
<Input name="code" size="md" ref={register} placeholder="Code" />
|
||||
<Input name="code" ref={register} placeholder="Code" />
|
||||
</Field>
|
||||
)}
|
||||
{!autoAssignOrg && (
|
||||
<Field label="Org. name">
|
||||
<Input size="md" name="orgName" placeholder="Org. name" ref={register} />
|
||||
<Input name="orgName" placeholder="Org. name" ref={register} />
|
||||
</Field>
|
||||
)}
|
||||
<Field label="Your name">
|
||||
<Input size="md" name="name" placeholder="(optional)" ref={register} />
|
||||
<Input name="name" placeholder="(optional)" ref={register} />
|
||||
</Field>
|
||||
<Field label="Email" invalid={!!errors.email} error={!!errors.email && errors.email.message}>
|
||||
<Input
|
||||
size="md"
|
||||
name="email"
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
@ -94,7 +93,6 @@ export const SignupForm: FC<Props> = props => {
|
||||
</Field>
|
||||
<Field label="Password" invalid={!!errors.password} error={!!errors.password && errors.password.message}>
|
||||
<Input
|
||||
size="md"
|
||||
name="password"
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
|
@ -11,6 +11,7 @@ interface SearchFieldProps extends Omit<React.InputHTMLAttributes<HTMLInputEleme
|
||||
onChange: (query: string) => void;
|
||||
onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
|
||||
clearable?: boolean;
|
||||
width?: number;
|
||||
}
|
||||
|
||||
const getSearchFieldStyles = (theme: GrafanaTheme) => ({
|
||||
|
@ -58,7 +58,6 @@ export const SearchResultsFilter: FC<Props> = ({
|
||||
) : (
|
||||
<HorizontalGroup spacing="md">
|
||||
<Select
|
||||
size="sm"
|
||||
placeholder="Filter by starred"
|
||||
key={starredFilterOptions?.find(f => f.value === selectedStarredFilter)?.label}
|
||||
options={starredFilterOptions}
|
||||
@ -66,7 +65,6 @@ export const SearchResultsFilter: FC<Props> = ({
|
||||
/>
|
||||
|
||||
<TagFilter
|
||||
size="sm"
|
||||
placeholder="Filter by tag"
|
||||
tags={selectedTagFilter}
|
||||
tagOptions={searchSrv.getDashboardTags}
|
||||
|
@ -75,7 +75,6 @@ const SingupInvitedPageUnconnected: FC<DispatchProps & ConnectedProps> = ({ code
|
||||
<>
|
||||
<Field invalid={!!errors.email} error={!!errors.email && errors.email.message} label="Email">
|
||||
<Input
|
||||
size="md"
|
||||
placeholder="email@example.com"
|
||||
name="email"
|
||||
ref={register({
|
||||
@ -88,19 +87,13 @@ const SingupInvitedPageUnconnected: FC<DispatchProps & ConnectedProps> = ({ code
|
||||
/>
|
||||
</Field>
|
||||
<Field invalid={!!errors.name} error={!!errors.name && errors.name.message} label="Name">
|
||||
<Input size="md" placeholder="Name (optional)" name="name" ref={register} />
|
||||
<Input placeholder="Name (optional)" name="name" ref={register} />
|
||||
</Field>
|
||||
<Field invalid={!!errors.username} error={!!errors.username && errors.username.message} label="Username">
|
||||
<Input
|
||||
size="md"
|
||||
placeholder="Username"
|
||||
name="username"
|
||||
ref={register({ required: 'Username is required' })}
|
||||
/>
|
||||
<Input placeholder="Username" name="username" ref={register({ required: 'Username is required' })} />
|
||||
</Field>
|
||||
<Field invalid={!!errors.password} error={!!errors.password && errors.password.message} label="Password">
|
||||
<Input
|
||||
size="md"
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
name="password"
|
||||
|
@ -163,7 +163,13 @@ export class PromQueryEditor extends PureComponent<Props, State> {
|
||||
|
||||
<div className="gf-form">
|
||||
<div className="gf-form-label width-7">Format</div>
|
||||
<Select isSearchable={false} options={FORMAT_OPTIONS} onChange={this.onFormatChange} value={formatOption} />
|
||||
<Select
|
||||
width={16}
|
||||
isSearchable={false}
|
||||
options={FORMAT_OPTIONS}
|
||||
onChange={this.onFormatChange}
|
||||
value={formatOption}
|
||||
/>
|
||||
<Switch label="Instant" checked={instant} onChange={this.onInstantChange} />
|
||||
|
||||
<FormLabel width={10} tooltip="Link to Graph in Prometheus">
|
||||
|
@ -148,6 +148,7 @@ exports[`Render PromQueryEditor with basic options should render 1`] = `
|
||||
"value": "time_series",
|
||||
}
|
||||
}
|
||||
width={16}
|
||||
/>
|
||||
<Switch
|
||||
checked={false}
|
||||
|
@ -29,7 +29,7 @@ $space-md: 16px !default;
|
||||
$space-lg: 24px !default;
|
||||
$space-xl: 32px !default;
|
||||
|
||||
$spacer: 14px !default;
|
||||
$spacer: 16px !default;
|
||||
$spacer-x: $spacer !default;
|
||||
$spacer-y: $spacer !default;
|
||||
$spacers: (
|
||||
|
@ -8,20 +8,20 @@
|
||||
// widths
|
||||
@for $i from 1 through 30 {
|
||||
.width-#{$i} {
|
||||
width: ($spacer * $i) - $space-xs !important;
|
||||
width: ($spacer * $i) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@for $i from 1 through 30 {
|
||||
.max-width-#{$i} {
|
||||
max-width: ($spacer * $i) - $space-xs !important;
|
||||
max-width: ($spacer * $i) !important;
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@for $i from 1 through 30 {
|
||||
.min-width-#{$i} {
|
||||
min-width: ($spacer * $i) - $space-xs !important;
|
||||
min-width: ($spacer * $i) !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user