diff --git a/package.json b/package.json index eae360e41e8..eee6772d821 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/packages/grafana-ui/src/components/Cascader/Cascader.story.tsx b/packages/grafana-ui/src/components/Cascader/Cascader.story.tsx index 4d19cc00c23..ab5dd1a560a 100644 --- a/packages/grafana-ui/src/components/Cascader/Cascader.story.tsx +++ b/packages/grafana-ui/src/components/Cascader/Cascader.story.tsx @@ -57,7 +57,6 @@ export const withCustomValue = () => { formatCreateLabel={val => onCreateLabel + val} initialValue="Custom Initial Value" onSelect={val => console.log(val)} - size="md" /> ); }; diff --git a/packages/grafana-ui/src/components/Cascader/Cascader.tsx b/packages/grafana-ui/src/components/Cascader/Cascader.tsx index 00834df5e2b..bbf55d0a0f4 100644 --- a/packages/grafana-ui/src/components/Cascader/Cascader.tsx +++ b/packages/grafana-ui/src/components/Cascader/Cascader.tsx @@ -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 }; 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 onChange={this.onSelect} onBlur={this.onBlur} options={searchableOptions} - size={size} onCreateOption={this.onCreateOption} formatCreateLabel={this.props.formatCreateLabel} + width={width} /> ) : ( >
) => ( Edit user - + - + - + - + @@ -185,7 +179,6 @@ export const asyncValidation = () => { diff --git a/packages/grafana-ui/src/components/Forms/Form.tsx b/packages/grafana-ui/src/components/Forms/Form.tsx index 50b17eef43e..94fb26f848b 100644 --- a/packages/grafana-ui/src/components/Forms/Form.tsx +++ b/packages/grafana-ui/src/components/Forms/Form.tsx @@ -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 { validateOn?: Mode; @@ -9,6 +10,8 @@ interface FormProps { defaultValues?: DeepPartial; onSubmit: OnSubmit; children: (api: FormAPI) => React.ReactNode; + /** Sets max-width for container. Use it instead of setting individual widths on inputs.*/ + maxWidth?: number; } export function Form({ @@ -18,6 +21,7 @@ export function Form({ validateFieldsOnMount, children, validateOn = 'onSubmit', + maxWidth = 400, }: FormProps) { const { handleSubmit, register, errors, control, triggerValidation, getValues, formState } = useForm({ mode: validateOn, @@ -30,5 +34,14 @@ export function Form({ } }, []); - return
{children({ register, errors, control, getValues, formState })}
; + return ( +
+ {children({ register, errors, control, getValues, formState })} +
+ ); } diff --git a/packages/grafana-ui/src/components/Input/Input.mdx b/packages/grafana-ui/src/components/Input/Input.mdx index 60e991afcdf..67be24b9a60 100644 --- a/packages/grafana-ui/src/components/Input/Input.mdx +++ b/packages/grafana-ui/src/components/Input/Input.mdx @@ -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 -} size="sm" /> +} /> ``` - } size="sm" /> + } /> ## Usage in forms with Field diff --git a/packages/grafana-ui/src/components/Input/Input.story.tsx b/packages/grafana-ui/src/components/Input/Input.story.tsx index 6c1249152dd..65051fe00f8 100644 --- a/packages/grafana-ui/src/components/Input/Input.story.tsx +++ b/packages/grafana-ui/src/components/Input/Input.story.tsx @@ -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 = () => {
, '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, '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((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((props, ref) => { const [suffixRect, suffixRef] = useClientRect(); const theme = useTheme(); - const styles = getInputStyles({ theme, invalid: !!invalid }); + const styles = getInputStyles({ theme, invalid: !!invalid, width }); return ( -
+
{!!addonBefore &&
{addonBefore}
}
diff --git a/packages/grafana-ui/src/components/Layout/Layout.mdx b/packages/grafana-ui/src/components/Layout/Layout.mdx index 304c2adb3a1..928f8ebe2fa 100644 --- a/packages/grafana-ui/src/components/Layout/Layout.mdx +++ b/packages/grafana-ui/src/components/Layout/Layout.mdx @@ -29,7 +29,7 @@ Used for horizontally aligning several elements (e.g. Button, Select) with a pre {}} options={[ { value: 1, label: "Option 1" }, @@ -45,7 +45,7 @@ Used for horizontally aligning several elements (e.g. Button, Select) with a pre ]} /> {}} options={[ { value: 1, label: "Option 1" }, @@ -77,7 +77,7 @@ Used for vertically aligning several elements (e.g. Button, Select) with a prede ]} /> {}} options={[ { value: 1, label: "Option 1" }, diff --git a/packages/grafana-ui/src/components/Select/Select.mdx b/packages/grafana-ui/src/components/Select/Select.mdx index 5ca57e225c5..5e202393f8d 100644 --- a/packages/grafana-ui/src/components/Select/Select.mdx +++ b/packages/grafana-ui/src/components/Select/Select.mdx @@ -80,7 +80,6 @@ const basicSelectAsync = () => { onChange={v => { setValue(v); }} - size="md" /> ); }; @@ -117,7 +116,6 @@ const multiSelect = () => { onChange={v => { setValue(v); }} - size="md" /> ); diff --git a/packages/grafana-ui/src/components/Select/Select.story.tsx b/packages/grafana-ui/src/components/Select/Select.story.tsx index 4dcf2f1027a..4578e210f6b 100644 --- a/packages/grafana-ui/src/components/Select/Select.story.tsx +++ b/packages/grafana-ui/src/components/Select/Select.story.tsx @@ -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 ( } /> ) : ( - await validateUid(v) })} - /> + await validateUid(v) })} /> )} @@ -129,12 +123,7 @@ export const ImportDashboardForm: FC = ({ invalid={errors.constants && !!errors.constants[index]} key={constantIndex} > - + ); })} diff --git a/public/app/features/org/NewOrgPage.tsx b/public/app/features/org/NewOrgPage.tsx index 538c2532170..80b19ec67ae 100644 --- a/public/app/features/org/NewOrgPage.tsx +++ b/public/app/features/org/NewOrgPage.tsx @@ -55,7 +55,6 @@ export const NewOrgPage: FC = ({ navModel }) => { <> = ({ updateLocation }) => { error={!!errors.loginOrEmail && 'Email or Username is required'} label="Email or Username" > - + - + diff --git a/public/app/features/profile/SignupForm.tsx b/public/app/features/profile/SignupForm.tsx index 2ad5e30940f..0c4e340b411 100644 --- a/public/app/features/profile/SignupForm.tsx +++ b/public/app/features/profile/SignupForm.tsx @@ -66,20 +66,19 @@ export const SignupForm: FC = props => { <> {verifyEmailEnabled && ( - + )} {!autoAssignOrg && ( - + )} - + = props => { void; onKeyDown?: (e: React.KeyboardEvent) => void; clearable?: boolean; + width?: number; } const getSearchFieldStyles = (theme: GrafanaTheme) => ({ diff --git a/public/app/features/search/components/SearchResultsFilter.tsx b/public/app/features/search/components/SearchResultsFilter.tsx index 72017acfb46..8a887235297 100644 --- a/public/app/features/search/components/SearchResultsFilter.tsx +++ b/public/app/features/search/components/SearchResultsFilter.tsx @@ -58,7 +58,6 @@ export const SearchResultsFilter: FC = ({ ) : ( = ({ code /> - + - + {
Format
- diff --git a/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap b/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap index fdf2728020a..bce7ab79f88 100644 --- a/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap +++ b/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap @@ -148,6 +148,7 @@ exports[`Render PromQueryEditor with basic options should render 1`] = ` "value": "time_series", } } + width={16} />