Commit 58cc2e34 by Torkel Ödegaard

User picker using common select componnet

parent 104292df
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;
......@@ -2,10 +2,12 @@
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 DescriptionOption from './DescriptionOption';
import { Option, SingleValue } from './PickerOption';
import IndicatorsContainer from './IndicatorsContainer';
import NoOptionsMessage from './NoOptionsMessage';
import ResetStyles from './ResetStyles';
export interface SelectOptionItem {
......@@ -16,20 +18,31 @@ export interface SelectOptionItem {
[key: string]: any;
}
interface Props {
interface CommonProps {
defaultValue?: any;
getOptionLabel?: (item: SelectOptionItem) => string;
getOptionValue?: (item: SelectOptionItem) => string;
onChange: (item: SelectOptionItem) => {} | void;
options: SelectOptionItem[];
placeholder?: string;
width?: number;
value: SelectOptionItem;
value?: SelectOptionItem;
className?: string;
components: object;
}
export class Select extends PureComponent<Props> {
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: '',
......@@ -61,7 +74,8 @@ export class Select extends PureComponent<Props> {
classNamePrefix="gf-form-select-box"
className={selectClassNames}
components={{
Option: DescriptionOption,
Option,
SingleValue,
IndicatorsContainer,
}}
defaultValue={defaultValue}
......@@ -79,4 +93,65 @@ export class Select extends PureComponent<Props> {
}
}
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;
// 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>
);
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment