Chore: remove UseState + add support for controls in TimeOfDayPicker/TimeRangeInput story (#53040)

* remove UseState + add support for controls in TimeOfDayPicker story

* remove UseState + add controls support in TimeRangeInput story

* Add documentation + fix error when clearing

* properly type range
This commit is contained in:
Ashley Harrison 2022-08-02 13:33:59 +01:00 committed by GitHub
parent db08ece3db
commit 9c6aab3bc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 82 additions and 119 deletions

View File

@ -1401,11 +1401,6 @@ exports[`better eslint`] = {
"packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"packages/grafana-ui/src/components/DateTimePickers/TimeRangeInput.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"],
[0, 0, 0, "Do not use any type assertions.", "2"]
],
"packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneOption.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],

View File

@ -1,57 +1,38 @@
import { action } from '@storybook/addon-actions';
import { ComponentMeta } from '@storybook/react';
import { useArgs } from '@storybook/client-api';
import { ComponentMeta, ComponentStory } from '@storybook/react';
import React from 'react';
import { dateTime } from '@grafana/data';
import { TimeOfDayPicker } from '@grafana/ui';
import { UseState } from '../../utils/storybook/UseState';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
const meta: ComponentMeta<typeof TimeOfDayPicker> = {
title: 'Pickers and Editors/TimePickers/TimeOfDayPicker',
component: TimeOfDayPicker,
decorators: [withCenteredStory],
parameters: {
controls: {
exclude: ['onChange'],
},
},
args: {
value: dateTime(Date.now()),
},
argTypes: { value: { control: 'date' } },
};
export const basic = () => {
export const Basic: ComponentStory<typeof TimeOfDayPicker> = (args) => {
const [, updateArgs] = useArgs();
return (
<UseState
initialState={{
value: dateTime(Date.now()),
<TimeOfDayPicker
{...args}
onChange={(newValue) => {
action('on selected')(newValue);
updateArgs({ value: newValue });
}}
>
{(value, updateValue) => {
return (
<TimeOfDayPicker
onChange={(newValue) => {
action('on selected')(newValue);
updateValue({ value: newValue });
}}
value={value.value}
/>
);
}}
</UseState>
);
};
export const onlyMinutes = () => {
return (
<UseState initialState={{ value: dateTime(Date.now()) }}>
{(value, updateValue) => {
return (
<TimeOfDayPicker
onChange={(newValue) => {
action('on selected')(newValue);
updateValue({ value: newValue });
}}
value={value.value}
showHour={false}
/>
);
}}
</UseState>
/>
);
};

View File

@ -1,97 +1,82 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/client-api';
import { ComponentMeta, ComponentStory } from '@storybook/react';
import React from 'react';
import { dateTime, DefaultTimeZone, TimeRange, TimeZone } from '@grafana/data';
import { dateTime, DefaultTimeZone, isDateTime, TimeRange } from '@grafana/data';
import { TimeRangeInput } from '@grafana/ui';
import { UseState } from '../../utils/storybook/UseState';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
import { TimeRangeInputProps } from './TimeRangeInput';
import mdx from './TimeRangeInput.mdx';
const now = dateTime(Date.now());
const isOnRangeClear = (value: TimeRange) => {
return (
!value.from.isValid() &&
!value.to.isValid() &&
isDateTime(value.raw.from) &&
!value.raw.from.isValid() &&
isDateTime(value.raw.to) &&
!value.raw.to.isValid()
);
};
const nullRange = {
from: null,
to: null,
raw: {
from: null,
to: null,
},
};
const meta: ComponentMeta<typeof TimeRangeInput> = {
title: 'Pickers and Editors/TimePickers/TimeRangeInput',
component: TimeRangeInput,
decorators: [withCenteredStory],
parameters: {
controls: {
exclude: ['onChange', 'onChangeTimeZone'],
},
docs: {
page: mdx,
},
},
args: {
value: {
from: now.subtract(6, 'h'),
to: now,
raw: {
from: 'now-6h',
to: 'now',
},
},
timeZone: DefaultTimeZone,
},
};
interface State {
value: TimeRange;
timeZone: TimeZone;
}
const getComponentWithState = (initialState: State, props: TimeRangeInputProps) => (
<UseState initialState={initialState}>
{(state, updateValue) => {
return (
<TimeRangeInput
{...props}
value={state.value}
timeZone={state.timeZone}
onChange={(value) => {
action('onChange fired')(value);
updateValue({
...state,
value,
});
}}
onChangeTimeZone={(timeZone) => {
action('onChangeTimeZone fired')(timeZone);
updateValue({
...state,
timeZone,
});
}}
/>
);
}}
</UseState>
);
export const Relative: ComponentStory<typeof TimeRangeInput> = (props) => {
const to = dateTime();
const from = to.subtract(6, 'h');
return getComponentWithState(
{
value: {
from,
to,
raw: {
from: 'now-6h',
to: 'now',
},
},
timeZone: DefaultTimeZone,
},
props
);
};
export const Absolute: ComponentStory<typeof TimeRangeInput> = (props) => {
const to = dateTime();
const from = to.subtract(6, 'h');
return getComponentWithState(
{
value: {
from,
to,
raw: {
from,
to,
},
},
timeZone: DefaultTimeZone,
},
props
export const Basic: ComponentStory<typeof TimeRangeInput> = (args) => {
const [, updateArgs] = useArgs();
return (
<TimeRangeInput
{...args}
onChange={(value) => {
action('onChange fired')(value);
// Need some special logic to handle when the range is cleared since
// storybook controls don't support null datetimes
updateArgs({
value: isOnRangeClear(value) ? nullRange : value,
});
}}
onChangeTimeZone={(timeZone) => {
action('onChangeTimeZone fired')(timeZone);
updateArgs({
timeZone,
});
}}
/>
);
};

View File

@ -14,7 +14,7 @@ import { TimePickerButtonLabel } from './TimeRangePicker';
import { TimePickerContent } from './TimeRangePicker/TimePickerContent';
import { quickOptions } from './options';
const isValidTimeRange = (range: any) => {
const isValidTimeRange = (range: TimeRange) => {
return dateMath.isValid(range.from) && dateMath.isValid(range.to);
};
@ -26,7 +26,9 @@ export interface TimeRangeInputProps {
hideTimeZone?: boolean;
placeholder?: string;
clearable?: boolean;
/** Controls horizontal alignment of the picker menu */
isReversed?: boolean;
/** Controls visibility of the preset time ranges (e.g. **Last 5 minutes**) in the picker menu */
hideQuickRanges?: boolean;
disabled?: boolean;
}
@ -83,7 +85,7 @@ export const TimeRangeInput: FC<TimeRangeInputProps> = ({
onClick={onOpen}
>
{isValidTimeRange(value) ? (
<TimePickerButtonLabel value={value as TimeRange} timeZone={timeZone} />
<TimePickerButtonLabel value={value} timeZone={timeZone} />
) : (
<span className={styles.placeholder}>{placeholder}</span>
)}
@ -101,7 +103,7 @@ export const TimeRangeInput: FC<TimeRangeInputProps> = ({
<ClickOutsideWrapper includeButtonPress={false} onClick={onClose}>
<TimePickerContent
timeZone={timeZone}
value={isValidTimeRange(value) ? (value as TimeRange) : getDefaultTimeRange()}
value={isValidTimeRange(value) ? value : getDefaultTimeRange()}
onChange={onRangeChange}
quickOptions={quickOptions}
onChangeTimeZone={onChangeTimeZone}