Browse Source

Merge branch 'panel-edit-style-changes' into select-refactor

Torkel Ödegaard 7 years ago
parent
commit
ab31d52b77

+ 7 - 5
public/app/core/components/Picker/NoOptionsMessage.tsx

@@ -1,4 +1,4 @@
-import React from 'react';
+import React from 'react';
 import { components } from 'react-select';
 import { OptionProps } from 'react-select/lib/components/Option';
 
@@ -6,13 +6,15 @@ export interface Props {
   children: Element;
 }
 
-export const PickerOption = (props: OptionProps<any>) => {
-  const { children, className } = props;
+export const NoOptionsMessage = (props: OptionProps<any>) => {
+  const { children } = props;
   return (
     <components.Option {...props}>
-      <div className={`description-picker-option__button btn btn-link ${className}`}>{children}</div>
+      <div className="gf-form-select-box__desc-option">
+        <div className="gf-form-select-box__desc-option__body">{children}</div>
+      </div>
     </components.Option>
   );
 };
 
-export default PickerOption;
+export default NoOptionsMessage;

+ 157 - 60
public/app/core/components/Picker/Select.tsx

@@ -1,60 +1,157 @@
-// import React, { PureComponent } from 'react';
-// import Select as ReactSelect from 'react-select';
-// import DescriptionOption from './DescriptionOption';
-// import IndicatorsContainer from './IndicatorsContainer';
-// import ResetStyles from './ResetStyles';
-//
-// export interface OptionType {
-//   label: string;
-//   value: string;
-// }
-//
-// interface Props {
-//   defaultValue?: any;
-//   getOptionLabel: (item: T) => string;
-//   getOptionValue: (item: T) => string;
-//   onChange: (item: T) => {} | void;
-//   options: T[];
-//   placeholder?: string;
-//   width?: number;
-//   value: T;
-//   className?: string;
-// }
-//
-// export class Select<T> extends PureComponent<Props<T>> {
-//   static defaultProps = {
-//     width: null,
-//     className: '',
-//   }
-//
-//   render() {
-//     const { defaultValue, getOptionLabel, getOptionValue, onSelected, options, placeholder, width, value, className } = this.props;
-//     let widthClass = '';
-//     if (width) {
-//       widthClass = 'width-'+width;
-//     }
-//
-//   return (
-//     <ReactSelect
-//       classNamePrefix="gf-form-select-box"
-//       className={`gf-form-input gf-form-input--form-dropdown ${widthClass} ${className}`}
-//       components={{
-//         Option: DescriptionOption,
-//         IndicatorsContainer,
-//       }}
-//       defaultValue={defaultValue}
-//       value={value}
-//       getOptionLabel={getOptionLabel}
-//       getOptionValue={getOptionValue}
-//       menuShouldScrollIntoView={false}
-//       isSearchable={false}
-//       onChange={onSelected}
-//       options={options}
-//       placeholder={placeholder || 'Choose'}
-//       styles={ResetStyles}
-//     />
-//   );
-// }
-// }
-//
-// export default Select;
+// Libraries
+import classNames from 'classnames';
+import React, { PureComponent } from 'react';
+import { default as ReactSelect } from 'react-select';
+import { default as ReactAsyncSelect } from 'react-select/lib/Async';
+
+// Components
+import { Option, SingleValue } from './PickerOption';
+import IndicatorsContainer from './IndicatorsContainer';
+import NoOptionsMessage from './NoOptionsMessage';
+import ResetStyles from './ResetStyles';
+
+export interface SelectOptionItem {
+  label?: string;
+  value?: string;
+  imgUrl?: string;
+  description?: string;
+  [key: string]: any;
+}
+
+interface CommonProps {
+  defaultValue?: any;
+  getOptionLabel?: (item: SelectOptionItem) => string;
+  getOptionValue?: (item: SelectOptionItem) => string;
+  onChange: (item: SelectOptionItem) => {} | void;
+  placeholder?: string;
+  width?: number;
+  value?: SelectOptionItem;
+  className?: string;
+  components: object;
+}
+
+interface SelectProps {
+  options: SelectOptionItem[];
+}
+
+interface AsyncProps {
+  defaultOptions: boolean;
+  loadOptions: (query: string) => Promise<SelectOptionItem[]>;
+  isLoading: boolean;
+  loadingMessage?: () => string;
+  noOptionsMessage?: () => string;
+}
+
+export class Select extends PureComponent<CommonProps & SelectProps> {
+  static defaultProps = {
+    width: null,
+    className: '',
+    components: {},
+  };
+
+  render() {
+    const {
+      defaultValue,
+      getOptionLabel,
+      getOptionValue,
+      onChange,
+      options,
+      placeholder,
+      width,
+      value,
+      className,
+    } = this.props;
+
+    let widthClass = '';
+    if (width) {
+      widthClass = 'width-' + width;
+    }
+
+    const selectClassNames = classNames('gf-form-input', 'gf-form-input--form-dropdown', widthClass, className);
+
+    return (
+      <ReactSelect
+        classNamePrefix="gf-form-select-box"
+        className={selectClassNames}
+        components={{
+          Option,
+          SingleValue,
+          IndicatorsContainer,
+        }}
+        defaultValue={defaultValue}
+        value={value}
+        getOptionLabel={getOptionLabel}
+        getOptionValue={getOptionValue}
+        menuShouldScrollIntoView={false}
+        isSearchable={false}
+        onChange={onChange}
+        options={options}
+        placeholder={placeholder || 'Choose'}
+        styles={ResetStyles}
+      />
+    );
+  }
+}
+
+export class AsyncSelect extends PureComponent<CommonProps & AsyncProps> {
+  static defaultProps = {
+    width: null,
+    className: '',
+    components: {},
+    loadingMessage: () => 'Loading...',
+  };
+
+  render() {
+    const {
+      defaultValue,
+      getOptionLabel,
+      getOptionValue,
+      onChange,
+      placeholder,
+      width,
+      value,
+      className,
+      loadOptions,
+      defaultOptions,
+      isLoading,
+      loadingMessage,
+      noOptionsMessage,
+    } = this.props;
+
+    let widthClass = '';
+    if (width) {
+      widthClass = 'width-' + width;
+    }
+
+    const selectClassNames = classNames('gf-form-input', 'gf-form-input--form-dropdown', widthClass, className);
+
+    return (
+      <ReactAsyncSelect
+        classNamePrefix="gf-form-select-box"
+        className={selectClassNames}
+        components={{
+          Option,
+          SingleValue,
+          IndicatorsContainer,
+          NoOptionsMessage,
+        }}
+        defaultValue={defaultValue}
+        value={value}
+        getOptionLabel={getOptionLabel}
+        getOptionValue={getOptionValue}
+        menuShouldScrollIntoView={false}
+        isSearchable={false}
+        onChange={onChange}
+        loadOptions={loadOptions}
+        isLoading={isLoading}
+        defaultOptions={defaultOptions}
+        placeholder={placeholder || 'Choose'}
+        styles={ResetStyles}
+        loadingMessage={loadingMessage}
+        noOptionsMessage={noOptionsMessage}
+      />
+    );
+  }
+}
+
+export default Select;

+ 10 - 17
public/app/core/components/Picker/UserPicker.tsx

@@ -1,12 +1,15 @@
+// Libraries
 import React, { Component } from 'react';
-import AsyncSelect from 'react-select/lib/Async';
-import PickerOption from './PickerOption';
+
+// Components
+import { AsyncSelect } from 'app/core/components/Picker/Select';
+
+// Utils & Services
 import { debounce } from 'lodash';
 import { getBackendSrv } from 'app/core/services/backend_srv';
+
+// Types
 import { User } from 'app/types';
-import ResetStyles from './ResetStyles';
-import IndicatorsContainer from './IndicatorsContainer';
-import NoOptionsMessage from './NoOptionsMessage';
 
 export interface Props {
   onSelected: (user: User) => void;
@@ -40,6 +43,7 @@ export class UserPicker extends Component<Props, State> {
       .then(result => {
         return result.map(user => ({
           id: user.userId,
+          value: user.userId,
           label: user.login === user.email ? user.login : `${user.login} - ${user.email}`,
           imgUrl: user.avatarUrl,
           login: user.login,
@@ -57,24 +61,13 @@ export class UserPicker extends Component<Props, State> {
     return (
       <div className="user-picker">
         <AsyncSelect
-          classNamePrefix={`gf-form-select-box`}
-          isMulti={false}
+          className={className}
           isLoading={isLoading}
           defaultOptions={true}
           loadOptions={this.debouncedSearch}
           onChange={onSelected}
-          className={`gf-form-input gf-form-input--form-dropdown ${className || ''}`}
-          styles={ResetStyles}
-          components={{
-            Option: PickerOption,
-            IndicatorsContainer,
-            NoOptionsMessage,
-          }}
           placeholder="Select user"
-          loadingMessage={() => 'Loading...'}
           noOptionsMessage={() => 'No users found'}
-          getOptionValue={i => i.id}
-          getOptionLabel={i => i.label}
         />
       </div>
     );

+ 11 - 15
public/app/core/components/SharedPreferences/SharedPreferences.tsx

@@ -1,7 +1,7 @@
 import React, { PureComponent } from 'react';
 
 import { Label } from 'app/core/components/Label/Label';
-import SimplePicker from 'app/core/components/Picker/SimplePicker';
+import Select from 'app/core/components/Picker/Select';
 import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv';
 
 import { DashboardSearchHit } from 'app/types';
@@ -17,12 +17,12 @@ export interface State {
   dashboards: DashboardSearchHit[];
 }
 
-const themes = [{ value: '', text: 'Default' }, { value: 'dark', text: 'Dark' }, { value: 'light', text: 'Light' }];
+const themes = [{ value: '', label: 'Default' }, { value: 'dark', label: 'Dark' }, { value: 'light', label: 'Light' }];
 
 const timezones = [
-  { value: '', text: 'Default' },
-  { value: 'browser', text: 'Local browser time' },
-  { value: 'utc', text: 'UTC' },
+  { value: '', label: 'Default' },
+  { value: 'browser', label: 'Local browser time' },
+  { value: 'utc', label: 'UTC' },
 ];
 
 export class SharedPreferences extends PureComponent<Props, State> {
@@ -91,12 +91,10 @@ export class SharedPreferences extends PureComponent<Props, State> {
         <h3 className="page-heading">Preferences</h3>
         <div className="gf-form">
           <span className="gf-form-label width-11">UI Theme</span>
-          <SimplePicker
+          <Select
             value={themes.find(item => item.value === theme)}
             options={themes}
-            getOptionValue={i => i.value}
-            getOptionLabel={i => i.text}
-            onSelected={theme => this.onThemeChanged(theme.value)}
+            onChange={theme => this.onThemeChanged(theme.value)}
             width={20}
           />
         </div>
@@ -107,11 +105,11 @@ export class SharedPreferences extends PureComponent<Props, State> {
           >
             Home Dashboard
           </Label>
-          <SimplePicker
+          <Select
             value={dashboards.find(dashboard => dashboard.id === homeDashboardId)}
             getOptionValue={i => i.id}
             getOptionLabel={i => i.title}
-            onSelected={(dashboard: DashboardSearchHit) => this.onHomeDashboardChanged(dashboard.id)}
+            onChange={(dashboard: DashboardSearchHit) => this.onHomeDashboardChanged(dashboard.id)}
             options={dashboards}
             placeholder="Chose default dashboard"
             width={20}
@@ -119,11 +117,9 @@ export class SharedPreferences extends PureComponent<Props, State> {
         </div>
         <div className="gf-form">
           <label className="gf-form-label width-11">Timezone</label>
-          <SimplePicker
+          <Select
             value={timezones.find(item => item.value === timezone)}
-            getOptionValue={i => i.value}
-            getOptionLabel={i => i.text}
-            onSelected={timezone => this.onTimeZoneChanged(timezone.value)}
+            onChange={timezone => this.onTimeZoneChanged(timezone.value)}
             options={timezones}
             width={20}
           />

+ 2 - 2
public/app/features/panel/panel_header.ts

@@ -111,11 +111,11 @@ function panelHeader($compile) {
        */
       function togglePanelStackPosition() {
         const menuOpenClass = 'dropdown-menu-open';
-        const panelGridClass = '.react-grid-item.panel';
+        const panelGridClass = '.react-grid-item';
 
         let panelElem = elem
           .find('[data-toggle=dropdown]')
-          .parentsUntil('.panel')
+          .parentsUntil(panelGridClass)
           .parent();
         const menuElem = elem.find('[data-toggle=dropdown]').parent();
         panelElem = panelElem && panelElem.length ? panelElem[0] : undefined;

+ 14 - 16
public/app/plugins/panel/gauge/ValueOptions.tsx

@@ -1,21 +1,21 @@
 import React, { PureComponent } from 'react';
 import { Label } from 'app/core/components/Label/Label';
-import SimplePicker from 'app/core/components/Picker/SimplePicker';
+import Select from 'app/core/components/Picker/Select';
 import UnitPicker from 'app/core/components/Picker/Unit/UnitPicker';
 import { OptionModuleProps } from './module';
 
 const statOptions = [
-  { value: 'min', text: 'Min' },
-  { value: 'max', text: 'Max' },
-  { value: 'avg', text: 'Average' },
-  { value: 'current', text: 'Current' },
-  { value: 'total', text: 'Total' },
-  { value: 'name', text: 'Name' },
-  { value: 'first', text: 'First' },
-  { value: 'delta', text: 'Delta' },
-  { value: 'diff', text: 'Difference' },
-  { value: 'range', text: 'Range' },
-  { value: 'last_time', text: 'Time of last point' },
+  { value: 'min', label: 'Min' },
+  { value: 'max', label: 'Max' },
+  { value: 'avg', label: 'Average' },
+  { value: 'current', label: 'Current' },
+  { value: 'total', label: 'Total' },
+  { value: 'name', label: 'Name' },
+  { value: 'first', label: 'First' },
+  { value: 'delta', label: 'Delta' },
+  { value: 'diff', label: 'Difference' },
+  { value: 'range', label: 'Range' },
+  { value: 'last_time', label: 'Time of last point' },
 ];
 
 const labelWidth = 6;
@@ -43,12 +43,10 @@ export default class ValueOptions extends PureComponent<OptionModuleProps> {
         <h5 className="page-heading">Value</h5>
         <div className="gf-form-inline">
           <Label width={labelWidth}>Stat</Label>
-          <SimplePicker
+          <Select
             width={12}
             options={statOptions}
-            getOptionLabel={i => i.text}
-            getOptionValue={i => i.value}
-            onSelected={this.onStatChange}
+            onChange={this.onStatChange}
             value={statOptions.find(option => option.value === stat)}
           />
         </div>