mirror of
https://github.com/grafana/grafana.git
synced 2025-02-03 12:11:09 -06:00
grafana/ui: Add Time of day picker (#18894)
* Adding DashboardPicker component * fix prop names * fix prop names pt2 * add component and modify utils * add showHour prop * add minuteStep to TimeOfDayPicker, add value to DashboardPicker * fix for dashboard picker, missed adding file * Adding story * add another story for hiding hour and style fixes * fix these generated files * fixes after review * rename current value * fix type issue on onChange * fix story
This commit is contained in:
parent
7b856ae040
commit
196f8503a8
@ -1,7 +1,6 @@
|
||||
import { TimeZone } from '../types/time';
|
||||
/* tslint:disable:import-blacklist ban ban-types */
|
||||
import moment, { MomentInput, DurationInputArg1 } from 'moment';
|
||||
|
||||
import moment, { Moment, MomentInput, DurationInputArg1 } from 'moment';
|
||||
export interface DateTimeBuiltinFormat {
|
||||
__momentBuiltinFormatBrand: any;
|
||||
}
|
||||
@ -72,6 +71,7 @@ export interface DateTime extends Object {
|
||||
utc: () => DateTime;
|
||||
utcOffset: () => number;
|
||||
hour?: () => number;
|
||||
minute?: () => number;
|
||||
}
|
||||
|
||||
export const setLocale = (language: string) => {
|
||||
@ -98,6 +98,10 @@ export const dateTime = (input?: DateTimeInput, formatInput?: FormatInput): Date
|
||||
return moment(input as MomentInput, formatInput) as DateTime;
|
||||
};
|
||||
|
||||
export const dateTimeAsMoment = (input?: DateTimeInput) => {
|
||||
return dateTime(input) as Moment;
|
||||
};
|
||||
|
||||
export const dateTimeForTimeZone = (
|
||||
timezone?: TimeZone,
|
||||
input?: DateTimeInput,
|
||||
|
@ -34,6 +34,7 @@
|
||||
"lodash": "4.17.14",
|
||||
"moment": "2.24.0",
|
||||
"papaparse": "4.6.3",
|
||||
"rc-time-picker": "^3.7.2",
|
||||
"react": "16.8.6",
|
||||
"react-calendar": "2.18.1",
|
||||
"react-color": "2.17.0",
|
||||
|
@ -0,0 +1,53 @@
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
|
||||
import { TimeOfDayPicker } from './TimeOfDayPicker';
|
||||
import { UseState } from '../../utils/storybook/UseState';
|
||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
import { dateTime } from '@grafana/data';
|
||||
|
||||
const TimeOfDayPickerStories = storiesOf('UI/TimeOfDayPicker', module);
|
||||
|
||||
TimeOfDayPickerStories.addDecorator(withCenteredStory);
|
||||
|
||||
TimeOfDayPickerStories.add('default', () => {
|
||||
return (
|
||||
<UseState
|
||||
initialState={{
|
||||
value: dateTime(Date.now()),
|
||||
}}
|
||||
>
|
||||
{(value, updateValue) => {
|
||||
return (
|
||||
<TimeOfDayPicker
|
||||
onChange={newValue => {
|
||||
action('on selected')(newValue);
|
||||
updateValue({ value: newValue });
|
||||
}}
|
||||
value={value.value}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</UseState>
|
||||
);
|
||||
});
|
||||
|
||||
TimeOfDayPickerStories.add('only minutes', () => {
|
||||
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>
|
||||
);
|
||||
});
|
@ -0,0 +1,26 @@
|
||||
import React, { FC } from 'react';
|
||||
import RcTimePicker from 'rc-time-picker';
|
||||
import { dateTime, DateTime, dateTimeAsMoment } from '@grafana/data';
|
||||
|
||||
interface Props {
|
||||
onChange: (value: DateTime) => void;
|
||||
value: DateTime;
|
||||
showHour?: boolean;
|
||||
minuteStep?: number;
|
||||
}
|
||||
|
||||
export const TimeOfDayPicker: FC<Props> = ({ minuteStep = 1, showHour = true, onChange, value }) => {
|
||||
return (
|
||||
<div>
|
||||
<RcTimePicker
|
||||
defaultValue={dateTimeAsMoment()}
|
||||
onChange={(value: any) => onChange(dateTime(value))}
|
||||
allowEmpty={false}
|
||||
showSecond={false}
|
||||
value={dateTimeAsMoment(value)}
|
||||
showHour={showHour}
|
||||
minuteStep={minuteStep}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -4,12 +4,12 @@ import { action } from '@storybook/addon-actions';
|
||||
|
||||
import { TimePicker } from './TimePicker';
|
||||
import { UseState } from '../../utils/storybook/UseState';
|
||||
import { withRighAlignedStory } from '../../utils/storybook/withRightAlignedStory';
|
||||
import { withRightAlignedStory } from '../../utils/storybook/withRightAlignedStory';
|
||||
import { TimeFragment, dateTime } from '@grafana/data';
|
||||
|
||||
const TimePickerStories = storiesOf('UI/TimePicker', module);
|
||||
|
||||
TimePickerStories.addDecorator(withRighAlignedStory);
|
||||
TimePickerStories.addDecorator(withRightAlignedStory);
|
||||
|
||||
TimePickerStories.add('default', () => {
|
||||
return (
|
||||
|
@ -0,0 +1,39 @@
|
||||
@import '../../node_modules/rc-time-picker/assets/index.css';
|
||||
|
||||
.rc-time-picker-input,
|
||||
.rc-time-picker-panel-input-wrap,
|
||||
.rc-time-picker-panel-inner {
|
||||
background-color: $input-bg;
|
||||
color: $input-color;
|
||||
border-color: $input-border-color;
|
||||
font-size: $font-size-base;
|
||||
}
|
||||
|
||||
.rc-time-picker-input {
|
||||
padding: $input-padding;
|
||||
height: $input-height;
|
||||
}
|
||||
|
||||
.rc-time-picker-panel {
|
||||
width: 176px;
|
||||
}
|
||||
|
||||
.rc-time-picker-panel-select {
|
||||
width: 50%;
|
||||
|
||||
&:only-child {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.rc-time-picker-panel-select-option-selected {
|
||||
background-color: $menu-dropdown-hover-bg;
|
||||
}
|
||||
|
||||
li:hover {
|
||||
background-color: $menu-dropdown-hover-bg;
|
||||
}
|
||||
}
|
||||
|
||||
.rc-time-picker-panel-narrow {
|
||||
max-width: none;
|
||||
}
|
@ -14,3 +14,4 @@
|
||||
@import 'BarGauge/BarGauge';
|
||||
@import 'RefreshPicker/RefreshPicker';
|
||||
@import 'TimePicker/TimePicker';
|
||||
@import 'TimePicker/TimeOfDayPicker';
|
||||
|
@ -35,6 +35,7 @@ export { StatsPicker } from './StatsPicker/StatsPicker';
|
||||
export { Input, InputStatus } from './Input/Input';
|
||||
export { RefreshPicker } from './RefreshPicker/RefreshPicker';
|
||||
export { TimePicker } from './TimePicker/TimePicker';
|
||||
export { TimeOfDayPicker } from './TimePicker/TimeOfDayPicker';
|
||||
export { List } from './List/List';
|
||||
|
||||
// Renderless
|
||||
|
@ -17,4 +17,4 @@ const RightAlignedStory: React.FunctionComponent<{}> = ({ children }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const withRighAlignedStory = (story: RenderFunction) => <RightAlignedStory>{story()}</RightAlignedStory>;
|
||||
export const withRightAlignedStory = (story: RenderFunction) => <RightAlignedStory>{story()}</RightAlignedStory>;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { AsyncSelect } from '@grafana/ui';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { debounce } from 'lodash';
|
||||
import { getBackendSrv } from 'app/core/services/backend_srv';
|
||||
import { DashboardSearchHit, DashboardDTO } from 'app/types';
|
||||
@ -7,6 +8,7 @@ import { DashboardSearchHit, DashboardDTO } from 'app/types';
|
||||
export interface Props {
|
||||
className?: string;
|
||||
onSelected: (dashboard: DashboardDTO) => void;
|
||||
currentDashboardId: SelectableValue<number>;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
@ -36,7 +38,7 @@ export class DashboardPicker extends PureComponent<Props, State> {
|
||||
.then((result: DashboardSearchHit[]) => {
|
||||
const dashboards = result.map((item: DashboardSearchHit) => {
|
||||
return {
|
||||
id: item.uid,
|
||||
id: item.id,
|
||||
value: item.id,
|
||||
label: `${item.folderTitle ? item.folderTitle : 'General'}/${item.title}`,
|
||||
};
|
||||
@ -48,7 +50,7 @@ export class DashboardPicker extends PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { className, onSelected } = this.props;
|
||||
const { className, onSelected, currentDashboardId } = this.props;
|
||||
const { isLoading } = this.state;
|
||||
|
||||
return (
|
||||
@ -63,6 +65,7 @@ export class DashboardPicker extends PureComponent<Props, State> {
|
||||
onChange={onSelected}
|
||||
placeholder="Select dashboard"
|
||||
noOptionsMessage={() => 'No dashboards found'}
|
||||
value={currentDashboardId}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
6
public/sass/_variables.dark.generated.scss.rej
Normal file
6
public/sass/_variables.dark.generated.scss.rej
Normal file
@ -0,0 +1,6 @@
|
||||
diff a/public/sass/_variables.dark.generated.scss b/public/sass/_variables.dark.generated.scss (rejected hunks)
|
||||
@@ -94,2 +94,2 @@ $textShadow: none;
|
||||
-$brand-gradient-horizontal: linear-gradient(to right, #f05a28 30%, #fbca0a 99%);
|
||||
-$brand-gradient-vertical: linear-gradient(#f05a28 30%, #fbca0a 99%);
|
||||
+$brand-gradient-horizontal: linear-gradient(to right, #F05A28 30%, #FBCA0A 99%);
|
||||
+$brand-gradient-vertical: linear-gradient(#F05A28 30%, #FBCA0A 99%);
|
6
public/sass/_variables.light.generated.scss.rej
Normal file
6
public/sass/_variables.light.generated.scss.rej
Normal file
@ -0,0 +1,6 @@
|
||||
diff a/public/sass/_variables.light.generated.scss b/public/sass/_variables.light.generated.scss (rejected hunks)
|
||||
@@ -86,2 +86,2 @@ $text-shadow-faint: none;
|
||||
-$brand-gradient-horizontal: linear-gradient(to right, #f05a28 30%, #fbca0a 99%);
|
||||
-$brand-gradient-vertical: linear-gradient(#f05a28 30%, #fbca0a 99%);
|
||||
+$brand-gradient-horizontal: linear-gradient(to right, #F05A28 30%, #FBCA0A 99%);
|
||||
+$brand-gradient-vertical: linear-gradient(#F05A28 30%, #FBCA0A 99%);
|
16
yarn.lock
16
yarn.lock
@ -12068,7 +12068,7 @@ module-alias@2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/module-alias/-/module-alias-2.2.0.tgz#a2e32275381642252bf0c51405f7a09a367479b5"
|
||||
|
||||
moment@2.24.0:
|
||||
moment@2.24.0, moment@2.x:
|
||||
version "2.24.0"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
|
||||
|
||||
@ -14629,7 +14629,7 @@ qw@~1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/qw/-/qw-1.0.1.tgz#efbfdc740f9ad054304426acb183412cc8b996d4"
|
||||
|
||||
raf@^3.1.0, raf@^3.4.0:
|
||||
raf@^3.1.0, raf@^3.4.0, raf@^3.4.1:
|
||||
version "3.4.1"
|
||||
resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
|
||||
dependencies:
|
||||
@ -14722,6 +14722,18 @@ rc-cascader@0.14.0:
|
||||
shallow-equal "^1.0.0"
|
||||
warning "^4.0.1"
|
||||
|
||||
rc-time-picker@^3.7.2:
|
||||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/rc-time-picker/-/rc-time-picker-3.7.2.tgz#fabe5501adf1374d31a2d3b47f1ba89fc2dc2467"
|
||||
integrity sha512-UVWO9HXGyZoM4I2THlJsEAFcZQz+tYwdcpoHXCEFZsRLz9L2+7vV4EMp9Wa3UrtzMFEt83qSAX/90dCJeKl9sg==
|
||||
dependencies:
|
||||
classnames "2.x"
|
||||
moment "2.x"
|
||||
prop-types "^15.5.8"
|
||||
raf "^3.4.1"
|
||||
rc-trigger "^2.2.0"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
|
||||
rc-trigger@^2.2.0:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-2.6.2.tgz#a9c09ba5fad63af3b2ec46349c7db6cb46657001"
|
||||
|
Loading…
Reference in New Issue
Block a user