openreplay/frontend/app/components/BugFinder/Attributes/AttributeValueField.js
2022-01-17 17:06:01 +05:30

194 lines
5.6 KiB
JavaScript

import React from 'react';
import { connect } from 'react-redux';
import cn from 'classnames';
import stl from './attributeItem.css'
import { Dropdown } from 'semantic-ui-react';
import { LinkStyledInput, CircularLoader } from 'UI';
import { KEYS } from 'Types/filter/customFilter';
import Event, { TYPES } from 'Types/filter/event';
import CustomFilter from 'Types/filter/customFilter';
import { setActiveKey, addCustomFilter, removeCustomFilter, applyFilter, updateValue } from 'Duck/filters';
import DurationFilter from '../DurationFilter/DurationFilter';
import AutoComplete from '../AutoComplete';
const DEFAULT = null;
const getHeader = (type) => {
if (type === 'LOCATION') return 'Path';
return type;
}
@connect(null, {
setActiveKey,
addCustomFilter,
removeCustomFilter,
applyFilter,
updateValue,
})
class AttributeValueField extends React.PureComponent {
state = {
minDuration: this.props.filter.minDuration,
maxDuration: this.props.filter.maxDuration,
}
onValueChange = (e, { name: key, value }) => {
this.props.addCustomFilter(key, value);
};
onDurationChange = (durationValues) => {
this.setState(durationValues);
}
isAutoComplete = (type) => {
switch (type) {
case TYPES.METADATA:
case TYPES.CLICK:
case TYPES.CONSOLE:
case TYPES.GRAPHQL:
case TYPES.FETCH:
case TYPES.STATEACTION:
case TYPES.USERID:
case TYPES.USERANONYMOUSID:
case TYPES.REVID:
case TYPES.GRAPHQL:
case TYPES.CUSTOM:
case TYPES.LOCATION:
case TYPES.VIEW:
case TYPES.INPUT:
case 'metadata':
return true;
}
return false;
}
handleClose = (e) => {
const { filter, onChange } = this.props;
if (filter.key === KEYS.DURATION) {
const { maxDuration, minDuration, key } = filter;
if (maxDuration || minDuration) return;
if (maxDuration !== this.state.maxDuration ||
minDuration !== this.state.minDuration) {
onChange(e, { name: 'value', value: [this.state.minDuration, this.state.maxDuration] });
}
}
}
renderField() {
const { filter, onChange } = this.props;
if (filter.key === KEYS.DURATION) {
const { maxDuration, minDuration } = this.state;
return (
<DurationFilter
onChange={ this.onDurationChange }
onEnterPress={ this.handleClose }
onBlur={this.handleClose}
minDuration={ minDuration }
maxDuration={ maxDuration }
/>
);
}
const { options = [], handleSearchChange, loading } = this.props;
return (
<Dropdown
className={ cn(stl.filterDropdown) }
placeholder="Select"
name="value"
search
selection
value={ filter.value || DEFAULT }
options={ options }
multiple={options.length > 0 || options.size > 0}
onChange={ onChange }
onSearchChange={handleSearchChange}
icon={ null }
noResultsMessage={loading ? <div>
<CircularLoader loading={ loading } style={ { marginRight: '8px' } } />
</div>: 'No results found.'}
/>
)
}
optionMapping = (values) => {
const { filter } = this.props;
if ([KEYS.USER_DEVICE, KEYS.USER_OS, KEYS.USER_BROWSER, KEYS.REFERRER, KEYS.PLATFORM].indexOf(filter.type) !== -1) {
return values.map(item => ({ type: TYPES.METADATA, value: item })).map(CustomFilter);
} else {
return values.map(Event);
}
}
getParams = filter => {
const params = {};
if (filter.type === TYPES.METADATA) {
params.key = filter.key
}
params.type = filter.type
if (filter.type === TYPES.ERROR && filter.source) {
params.source = filter.source
}
return params;
}
onAddValue = () => {
const { index, filter } = this.props;
this.props.updateValue('filters', index, filter.value.concat(""));
}
onRemoveValue = (valueIndex) => {
const { index, filter } = this.props;
this.props.updateValue('filters', index, filter.value.filter((_, i) => i !== valueIndex));
}
onChange = (name, value, valueIndex) => {
const { index, filter } = this.props;
this.props.updateValue('filters', index, filter.value.map((item, i) => i === valueIndex ? value : item));
}
render() {
// const { filter, onChange } = this.props;
const { filter } = this.props;
const _showAutoComplete = this.isAutoComplete(filter.type);
const _params = _showAutoComplete ? this.getParams(filter) : {};
let _optionsEndpoint= '/events/search';
return (
<React.Fragment>
{ _showAutoComplete ? filter.value.map((v, i) => (
<AutoComplete
name={ 'value' }
endpoint={ _optionsEndpoint }
value={ v }
index={ i }
params={ _params }
optionMapping={this.optionMapping}
onSelect={ (e, { name, value }) => onChange(name, value, i) }
headerText={ <h5 className={ stl.header }>{ getHeader(filter.type) }</h5> }
fullWidth={ (filter.type === TYPES.CONSOLE || filter.type === TYPES.LOCATION || filter.type === TYPES.CUSTOM) && filter.value }
onRemoveValue={() => this.onRemoveValue(i)}
onAddValue={this.onAddValue}
showCloseButton={i !== filter.value.length - 1}
/>
))
: this.renderField()
}
{ filter.type === 'INPUT' &&
<LinkStyledInput
displayLabel="Specify value"
placeholder="Specify value"
name="custom"
onChange={ onChange }
value={filter.custom}
/>
}
</React.Fragment>
);
}
}
export default AttributeValueField;