mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
db08ece3db
commit
9c6aab3bc9
@ -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"]
|
||||
],
|
||||
|
@ -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>
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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}
|
||||
|
Loading…
Reference in New Issue
Block a user