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": [
|
"packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.tsx:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[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": [
|
"packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneOption.tsx:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
],
|
],
|
||||||
|
@ -1,57 +1,38 @@
|
|||||||
import { action } from '@storybook/addon-actions';
|
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 React from 'react';
|
||||||
|
|
||||||
import { dateTime } from '@grafana/data';
|
import { dateTime } from '@grafana/data';
|
||||||
import { TimeOfDayPicker } from '@grafana/ui';
|
import { TimeOfDayPicker } from '@grafana/ui';
|
||||||
|
|
||||||
import { UseState } from '../../utils/storybook/UseState';
|
|
||||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||||
|
|
||||||
const meta: ComponentMeta<typeof TimeOfDayPicker> = {
|
const meta: ComponentMeta<typeof TimeOfDayPicker> = {
|
||||||
title: 'Pickers and Editors/TimePickers/TimeOfDayPicker',
|
title: 'Pickers and Editors/TimePickers/TimeOfDayPicker',
|
||||||
component: TimeOfDayPicker,
|
component: TimeOfDayPicker,
|
||||||
decorators: [withCenteredStory],
|
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 (
|
return (
|
||||||
<UseState
|
<TimeOfDayPicker
|
||||||
initialState={{
|
{...args}
|
||||||
value: dateTime(Date.now()),
|
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 { action } from '@storybook/addon-actions';
|
||||||
|
import { useArgs } from '@storybook/client-api';
|
||||||
import { ComponentMeta, ComponentStory } from '@storybook/react';
|
import { ComponentMeta, ComponentStory } from '@storybook/react';
|
||||||
import React from '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 { TimeRangeInput } from '@grafana/ui';
|
||||||
|
|
||||||
import { UseState } from '../../utils/storybook/UseState';
|
|
||||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||||
|
|
||||||
import { TimeRangeInputProps } from './TimeRangeInput';
|
|
||||||
import mdx from './TimeRangeInput.mdx';
|
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> = {
|
const meta: ComponentMeta<typeof TimeRangeInput> = {
|
||||||
title: 'Pickers and Editors/TimePickers/TimeRangeInput',
|
title: 'Pickers and Editors/TimePickers/TimeRangeInput',
|
||||||
component: TimeRangeInput,
|
component: TimeRangeInput,
|
||||||
decorators: [withCenteredStory],
|
decorators: [withCenteredStory],
|
||||||
parameters: {
|
parameters: {
|
||||||
|
controls: {
|
||||||
|
exclude: ['onChange', 'onChangeTimeZone'],
|
||||||
|
},
|
||||||
docs: {
|
docs: {
|
||||||
page: mdx,
|
page: mdx,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
args: {
|
||||||
|
value: {
|
||||||
|
from: now.subtract(6, 'h'),
|
||||||
|
to: now,
|
||||||
|
raw: {
|
||||||
|
from: 'now-6h',
|
||||||
|
to: 'now',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
timeZone: DefaultTimeZone,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
interface State {
|
export const Basic: ComponentStory<typeof TimeRangeInput> = (args) => {
|
||||||
value: TimeRange;
|
const [, updateArgs] = useArgs();
|
||||||
timeZone: TimeZone;
|
return (
|
||||||
}
|
<TimeRangeInput
|
||||||
|
{...args}
|
||||||
const getComponentWithState = (initialState: State, props: TimeRangeInputProps) => (
|
onChange={(value) => {
|
||||||
<UseState initialState={initialState}>
|
action('onChange fired')(value);
|
||||||
{(state, updateValue) => {
|
// Need some special logic to handle when the range is cleared since
|
||||||
return (
|
// storybook controls don't support null datetimes
|
||||||
<TimeRangeInput
|
updateArgs({
|
||||||
{...props}
|
value: isOnRangeClear(value) ? nullRange : value,
|
||||||
value={state.value}
|
});
|
||||||
timeZone={state.timeZone}
|
}}
|
||||||
onChange={(value) => {
|
onChangeTimeZone={(timeZone) => {
|
||||||
action('onChange fired')(value);
|
action('onChangeTimeZone fired')(timeZone);
|
||||||
updateValue({
|
updateArgs({
|
||||||
...state,
|
timeZone,
|
||||||
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
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import { TimePickerButtonLabel } from './TimeRangePicker';
|
|||||||
import { TimePickerContent } from './TimeRangePicker/TimePickerContent';
|
import { TimePickerContent } from './TimeRangePicker/TimePickerContent';
|
||||||
import { quickOptions } from './options';
|
import { quickOptions } from './options';
|
||||||
|
|
||||||
const isValidTimeRange = (range: any) => {
|
const isValidTimeRange = (range: TimeRange) => {
|
||||||
return dateMath.isValid(range.from) && dateMath.isValid(range.to);
|
return dateMath.isValid(range.from) && dateMath.isValid(range.to);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -26,7 +26,9 @@ export interface TimeRangeInputProps {
|
|||||||
hideTimeZone?: boolean;
|
hideTimeZone?: boolean;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
clearable?: boolean;
|
clearable?: boolean;
|
||||||
|
/** Controls horizontal alignment of the picker menu */
|
||||||
isReversed?: boolean;
|
isReversed?: boolean;
|
||||||
|
/** Controls visibility of the preset time ranges (e.g. **Last 5 minutes**) in the picker menu */
|
||||||
hideQuickRanges?: boolean;
|
hideQuickRanges?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
@ -83,7 +85,7 @@ export const TimeRangeInput: FC<TimeRangeInputProps> = ({
|
|||||||
onClick={onOpen}
|
onClick={onOpen}
|
||||||
>
|
>
|
||||||
{isValidTimeRange(value) ? (
|
{isValidTimeRange(value) ? (
|
||||||
<TimePickerButtonLabel value={value as TimeRange} timeZone={timeZone} />
|
<TimePickerButtonLabel value={value} timeZone={timeZone} />
|
||||||
) : (
|
) : (
|
||||||
<span className={styles.placeholder}>{placeholder}</span>
|
<span className={styles.placeholder}>{placeholder}</span>
|
||||||
)}
|
)}
|
||||||
@ -101,7 +103,7 @@ export const TimeRangeInput: FC<TimeRangeInputProps> = ({
|
|||||||
<ClickOutsideWrapper includeButtonPress={false} onClick={onClose}>
|
<ClickOutsideWrapper includeButtonPress={false} onClick={onClose}>
|
||||||
<TimePickerContent
|
<TimePickerContent
|
||||||
timeZone={timeZone}
|
timeZone={timeZone}
|
||||||
value={isValidTimeRange(value) ? (value as TimeRange) : getDefaultTimeRange()}
|
value={isValidTimeRange(value) ? value : getDefaultTimeRange()}
|
||||||
onChange={onRangeChange}
|
onChange={onRangeChange}
|
||||||
quickOptions={quickOptions}
|
quickOptions={quickOptions}
|
||||||
onChangeTimeZone={onChangeTimeZone}
|
onChangeTimeZone={onChangeTimeZone}
|
||||||
|
Loading…
Reference in New Issue
Block a user