// Copyright (c) 2022 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. import React, {Component, ComponentType} from 'react'; import styled from 'styled-components'; import {createSelector} from 'reselect'; import ItemSelector from './item-selector/item-selector'; import {classList} from './item-selector/dropdown-list'; import {toArray} from 'utils/utils'; import {notNullorUndefined} from 'utils/data-utils'; import FieldTokenFactory from '../common/field-token'; import {Field} from 'utils/table-utils/kepler-table'; import {FIELD_TYPES_AGGREGATORS, FIELD_AGGREGATORS} from 'constants/default-settings'; const defaultDisplayOption = d => { const optionName = d.displayName || d.name; const aggregator = d.aggregator; const aggegatorDisplay = FIELD_AGGREGATORS.find(a => a.id === aggregator)?.displayName; if (aggegatorDisplay) { return `${aggegatorDisplay}(${optionName})`; } return optionName; }; const defaultValueOption = d => d.name; const StyledToken = styled.div` display: inline-block; margin: 0 0 0 auto; `; const StyledFieldListItem = styled.div` display: flex; flex: 1 1 auto; margin-right: 10px; line-height: 0; align-items: center; `; FieldListItemFactoryFactory.deps = [FieldTokenFactory]; // custom list Item export function FieldListItemFactoryFactory(FieldToken) { const FieldListItemFactory = (showToken = true) => { const FieldListItem = ({value, displayOption = defaultDisplayOption}) => { return ( {displayOption(value)} {showToken && value.type ? ( ) : null} ); }; return FieldListItem; }; return FieldListItemFactory; } const SuggestedFieldHeader = () =>
Suggested Field
; type FieldType = | string | string[] | { name: string; format: string | null; }[] | { format?: string; id?: string; name?: string; fieldIdx?: number; type?: number; } | Field; interface FieldSelectorFactoryProps { fields?: FieldType[]; onSelect: ( items: | ReadonlyArray | string | number | boolean | object | null ) => void; placement?: string; value?: FieldType | null; filterFieldTypes?: FieldType | FieldType[]; inputTheme?: string; placeholder?: string; erasable?: boolean; error?: boolean; multiSelect?: boolean; closeOnSelect?: boolean; showToken?: boolean; suggested?: ReadonlyArray | null; CustomChickletComponent?: ComponentType; size?: string; isLoading?: boolean; aggregator?: any, withAggregator?: any onBlur?: any, onFocus?: any, } function FieldSelectorFactory( FieldListItemFactory: ReturnType ): ComponentType { class FieldSelector extends Component { static defaultProps = { erasable: true, error: false, fields: [], onSelect: () => {}, placement: 'bottom', value: null, aggregator: null, withAggregator: false, multiSelect: false, closeOnSelect: true, showToken: true, placeholder: 'placeholder.selectField' }; fieldsSelector = props => props.fields; filteredFieldsSelector = props => props.withAggregator ? props.fields : props.fields.filter( field => !toArray(props.value).find(d => (d.name ? d.name === field.name : d === field.name)) ); valueSelector = props => props.value; aggregatorSelector = props => props.aggregator; filterFieldTypesSelector = props => props.filterFieldTypes; showTokenSelector = props => props.showToken; withAggregatorSelector = props => props.withAggregator; selectedItemsSelector = createSelector( this.fieldsSelector, this.valueSelector, this.aggregatorSelector, (fields, value, aggregator) => toArray(value) .map(d => { const field = fields.find(f => notNullorUndefined(d) && d.name ? d.name === defaultValueOption(f) : d === defaultValueOption(f) ); if (field && aggregator) { return {...field, aggregator}; } return field; }) .filter(d => d) ); fieldOptionsSelector = createSelector( this.filteredFieldsSelector, this.valueSelector, this.filterFieldTypesSelector, this.aggregatorSelector, this.withAggregatorSelector, (fields, value, filterFieldTypes, aggregator, withAggregator) => { const fieldsWithAggregators = fields.map(field => { return { ...field, ...(withAggregator && { aggregators: FIELD_TYPES_AGGREGATORS[field.type]?.filter(agg => { return field.id === value ? agg !== aggregator : true; }) }) }; }); if (!filterFieldTypes) { return fieldsWithAggregators; } const filters = Array.isArray(filterFieldTypes) ? filterFieldTypes : [filterFieldTypes]; return fieldsWithAggregators.filter(f => filters.includes(f.type)); } ); fieldListItemSelector = createSelector(this.showTokenSelector, FieldListItemFactory); render() { return (
d} closeOnSelect={this.props.closeOnSelect} displayOption={defaultDisplayOption} filterOption="displayName" fixedOptions={this.props.suggested} inputTheme={this.props.inputTheme} size={this.props.size} isError={this.props.error} isLoading={this.props.isLoading} selectedItems={this.selectedItemsSelector(this.props)} erasable={this.props.erasable} options={this.fieldOptionsSelector(this.props)} multiSelect={this.props.multiSelect} placeholder={this.props.placeholder} placement={this.props.placement} onChange={this.props.onSelect} DropDownLineItemRenderComponent={this.fieldListItemSelector(this.props)} DropdownHeaderComponent={this.props.suggested ? SuggestedFieldHeader : null} CustomChickletComponent={this.props.CustomChickletComponent} withSubOptions={this.props.withAggregator} onBlur={this.props.onBlur} onFocus={this.props.onFocus} />
); } } return FieldSelector; } FieldSelectorFactory.deps = [FieldListItemFactoryFactory]; export default FieldSelectorFactory;