瀏覽代碼

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
Peter Holmberg 6 年之前
父節點
當前提交
196f8503a8

+ 6 - 2
packages/grafana-data/src/utils/moment_wrapper.ts

@@ -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,

+ 1 - 0
packages/grafana-ui/package.json

@@ -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",

+ 53 - 0
packages/grafana-ui/src/components/TimePicker/TimeOfDayPicker.story.tsx

@@ -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>
+  );
+});

+ 26 - 0
packages/grafana-ui/src/components/TimePicker/TimeOfDayPicker.tsx

@@ -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>
+  );
+};

+ 2 - 2
packages/grafana-ui/src/components/TimePicker/TimePicker.story.tsx

@@ -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 (

+ 39 - 0
packages/grafana-ui/src/components/TimePicker/_TimeOfDayPicker.scss

@@ -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;
+}

+ 1 - 0
packages/grafana-ui/src/components/index.scss

@@ -14,3 +14,4 @@
 @import 'BarGauge/BarGauge';
 @import 'RefreshPicker/RefreshPicker';
 @import 'TimePicker/TimePicker';
+@import 'TimePicker/TimeOfDayPicker';

+ 1 - 0
packages/grafana-ui/src/components/index.ts

@@ -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

+ 1 - 1
packages/grafana-ui/src/utils/storybook/withRightAlignedStory.tsx

@@ -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>;

+ 5 - 2
public/app/core/components/Select/DashboardPicker.tsx

@@ -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 - 0
public/sass/_variables.dark.generated.scss.rej

@@ -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 - 0
public/sass/_variables.light.generated.scss.rej

@@ -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%);

+ 14 - 2
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"