ui: filter modal wip
This commit is contained in:
parent
36feeb5ba9
commit
9909511e94
10 changed files with 350 additions and 262 deletions
|
|
@ -298,14 +298,13 @@ const FilterAutoComplete: React.FC<Props> = ({
|
|||
<Icon name="close" size="12" />
|
||||
</div>
|
||||
)}
|
||||
{showOrButton && (
|
||||
<div onClick={onAddValue} className="color-teal">
|
||||
<span className="px-1">or</span>
|
||||
</div>
|
||||
)}
|
||||
{/*{showOrButton && (*/}
|
||||
{/* <div onClick={onAddValue} className="color-teal">*/}
|
||||
{/* <span className="px-1">or</span>*/}
|
||||
{/* </div>*/}
|
||||
{/*)}*/}
|
||||
</div>
|
||||
</div>
|
||||
{!showOrButton && !hideOrText && <div className="ml-3">or</div>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,90 +1,102 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Icon } from 'UI';
|
||||
import stl from './FilterAutoCompleteLocal.module.css';
|
||||
|
||||
interface Props {
|
||||
showOrButton?: boolean;
|
||||
showCloseButton?: boolean;
|
||||
onRemoveValue?: () => void;
|
||||
onAddValue?: () => void;
|
||||
onRemoveValue?: (index: number) => void;
|
||||
onAddValue?: (index: number) => void;
|
||||
placeholder?: string;
|
||||
onSelect: (e, item) => void;
|
||||
onSelect: (e: any, item: Record<string, any>, index: number) => void;
|
||||
value: any;
|
||||
icon?: string;
|
||||
type?: string;
|
||||
isMultilple?: boolean;
|
||||
isMultiple?: boolean;
|
||||
allowDecimals?: boolean;
|
||||
}
|
||||
|
||||
function FilterAutoCompleteLocal(props: Props) {
|
||||
function FilterAutoCompleteLocal(props: Props & { index: number }) {
|
||||
const {
|
||||
showCloseButton = false,
|
||||
placeholder = 'Enter',
|
||||
showOrButton = false,
|
||||
onRemoveValue = () => null,
|
||||
onAddValue = () => null,
|
||||
value = '',
|
||||
icon = null,
|
||||
type = "text",
|
||||
isMultilple = true,
|
||||
allowDecimals = true,
|
||||
showCloseButton = false,
|
||||
placeholder = 'Enter',
|
||||
showOrButton = false,
|
||||
onRemoveValue = () => null,
|
||||
onAddValue = () => null,
|
||||
value = '',
|
||||
type = 'text',
|
||||
isMultiple = true,
|
||||
allowDecimals = true,
|
||||
index,
|
||||
} = props;
|
||||
const [showModal, setShowModal] = useState(true)
|
||||
const [query, setQuery] = useState(value);
|
||||
|
||||
const onInputChange = (e) => {
|
||||
if(allowDecimals) {
|
||||
if (allowDecimals) {
|
||||
const value = e.target.value;
|
||||
setQuery(value);
|
||||
props.onSelect(null, value);
|
||||
props.onSelect(null, value, index);
|
||||
} else {
|
||||
const value = e.target.value.replace(/[^\d]/, "");
|
||||
const value = e.target.value.replace(/[^\d]/, '');
|
||||
if (+value !== 0) {
|
||||
setQuery(value);
|
||||
props.onSelect(null, value);
|
||||
props.onSelect(null, value, index);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setQuery(value);
|
||||
}, [value])
|
||||
|
||||
const onBlur = (e) => {
|
||||
setTimeout(() => { setShowModal(false) }, 200)
|
||||
props.onSelect(e, { value: query })
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
const handleKeyDown = (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
props.onSelect(e, { value: query })
|
||||
props.onSelect(e, { value: query }, index);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative flex items-center">
|
||||
<div className={stl.wrapper}>
|
||||
<input
|
||||
name="query"
|
||||
onInput={ onInputChange }
|
||||
// onBlur={ onBlur }
|
||||
onFocus={ () => setShowModal(true)}
|
||||
value={ query }
|
||||
autoFocus={ true }
|
||||
type={ type }
|
||||
placeholder={ placeholder }
|
||||
onInput={onInputChange}
|
||||
value={query}
|
||||
autoFocus={true}
|
||||
type={type}
|
||||
placeholder={placeholder}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
<div
|
||||
className={stl.right}
|
||||
>
|
||||
{ showCloseButton && <div onClick={onRemoveValue}><Icon name="close" size="12" /></div> }
|
||||
{ showOrButton && <div onClick={onAddValue} className="color-teal"><span className="px-1">or</span></div> }
|
||||
<div className={stl.right}>
|
||||
{showCloseButton && (
|
||||
<div onClick={() => onRemoveValue(index)}>
|
||||
<Icon name="close" size="12" />
|
||||
</div>
|
||||
)}
|
||||
{showOrButton && isMultiple ? (
|
||||
<div onClick={() => onAddValue(index)} className="color-teal">
|
||||
<span className="px-1">or</span>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{ !showOrButton && isMultilple && <div className="ml-3">or</div> }
|
||||
{!showOrButton && isMultiple ? <div className="ml-2">or</div> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default FilterAutoCompleteLocal;
|
||||
function FilterLocalController(props: Props) {
|
||||
return props.value.map((value, index) => (
|
||||
<FilterAutoCompleteLocal
|
||||
{...props}
|
||||
key={index}
|
||||
index={index}
|
||||
showOrButton={index === props.value.length - 1}
|
||||
showCloseButton={props.value.length > 1}
|
||||
value={value}
|
||||
/>
|
||||
));
|
||||
}
|
||||
|
||||
export default FilterLocalController;
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ export const getMatchingEntries = (
|
|||
|
||||
if (lowerCaseQuery.length === 0)
|
||||
return {
|
||||
matchingCategories: Object.keys(filters),
|
||||
matchingCategories: ['ALL', ...Object.keys(filters)],
|
||||
matchingFilters: filters,
|
||||
};
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ export const getMatchingEntries = (
|
|||
}
|
||||
});
|
||||
|
||||
return { matchingCategories, matchingFilters };
|
||||
return { matchingCategories: ['ALL', ...matchingCategories], matchingFilters };
|
||||
};
|
||||
|
||||
interface Props {
|
||||
|
|
@ -211,7 +211,7 @@ function FilterModal(props: Props) {
|
|||
return (
|
||||
<div
|
||||
className={stl.wrapper}
|
||||
style={{ width: '480px', height: '380px', borderRadius: '.5rem' }}
|
||||
style={{ width: '560px', height: '380px', borderRadius: '.5rem' }}
|
||||
>
|
||||
<Input
|
||||
className={'mb-4'}
|
||||
|
|
@ -224,14 +224,15 @@ function FilterModal(props: Props) {
|
|||
{matchingCategories.map((key) => (
|
||||
<div
|
||||
key={key}
|
||||
className={'rounded p-4 hover:bg-active-blue capitalize'}
|
||||
onClick={() => setCategory(key)}
|
||||
className={cn('rounded px-4 py-2 hover:bg-active-blue capitalize', key === category ? 'bg-active-blue' : '')}
|
||||
>
|
||||
{key.toLowerCase()}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
className={'flex flex-col gap-2 overflow-y-auto w-full'}
|
||||
className={'flex flex-col gap-1 overflow-y-auto w-full'}
|
||||
style={{ maxHeight: 300, flex: 2 }}
|
||||
>
|
||||
{displayedFilters.length
|
||||
|
|
|
|||
|
|
@ -10,16 +10,12 @@ const dropdownStyles = {
|
|||
cursor: 'pointer',
|
||||
height: '26px',
|
||||
minHeight: '26px',
|
||||
backgroundColor: '#f6f6f6',
|
||||
'&:hover': {
|
||||
backgroundColor: '#EEEEEE',
|
||||
},
|
||||
backgroundColor: 'white',
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
valueContainer: (provided: any) => ({
|
||||
...provided,
|
||||
paddingRight: '0px',
|
||||
width: 'fit-content',
|
||||
'& input': {
|
||||
marginTop: '-3px',
|
||||
|
|
@ -29,9 +25,7 @@ const dropdownStyles = {
|
|||
...provided,
|
||||
}),
|
||||
indicatorsContainer: (provided: any) => ({
|
||||
...provided,
|
||||
padding: '0px',
|
||||
height: '26px',
|
||||
display: 'none',
|
||||
}),
|
||||
// option: (provided: any, state: any) => ({
|
||||
// ...provided,
|
||||
|
|
@ -39,11 +33,13 @@ const dropdownStyles = {
|
|||
// }),
|
||||
menu: (provided: any, state: any) => ({
|
||||
...provided,
|
||||
top: 20,
|
||||
marginTop: '0.5rem',
|
||||
left: 0,
|
||||
minWidth: 'fit-content',
|
||||
overflow: 'hidden',
|
||||
zIndex: 100,
|
||||
border: 'none',
|
||||
boxShadow: '0px 4px 10px rgba(0,0,0, 0.15)',
|
||||
}),
|
||||
container: (provided: any) => ({
|
||||
...provided,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ function FilterSelection(props: Props) {
|
|||
} = props;
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
|
||||
const onAddFilter = (filter: any) => {
|
||||
onFilterClick(filter);
|
||||
setShowModal(false);
|
||||
}
|
||||
return (
|
||||
<div className="relative flex-shrink-0">
|
||||
<OutsideClickDetectingDiv
|
||||
|
|
@ -54,13 +58,11 @@ function FilterSelection(props: Props) {
|
|||
) : (
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-lg py-1 px-3 flex items-center cursor-pointer bg-gray-lightest text-ellipsis hover:bg-gray-light-shade',
|
||||
'rounded-lg py-1 px-2 flex items-center cursor-pointer bg-white border border-gray-light text-ellipsis',
|
||||
{ 'opacity-50 pointer-events-none': disabled }
|
||||
)}
|
||||
style={{
|
||||
width: '150px',
|
||||
height: '26px',
|
||||
border: 'solid thin #e9e9e9',
|
||||
}}
|
||||
onClick={() => setShowModal(true)}
|
||||
>
|
||||
|
|
@ -70,14 +72,13 @@ function FilterSelection(props: Props) {
|
|||
>
|
||||
{filter.label}
|
||||
</div>
|
||||
<Icon name="chevron-down" size="14" />
|
||||
</div>
|
||||
)}
|
||||
{showModal && (
|
||||
<div className="absolute mt-2 left-0 rounded-lg shadow bg-white z-50">
|
||||
<FilterModal
|
||||
isLive={isRoute(ASSIST_ROUTE, window.location.pathname)}
|
||||
onFilterClick={onFilterClick}
|
||||
onFilterClick={onAddFilter}
|
||||
excludeFilterKeys={excludeFilterKeys}
|
||||
allowedFilterKeys={allowedFilterKeys}
|
||||
isConditional={isConditional}
|
||||
|
|
|
|||
|
|
@ -7,183 +7,233 @@ import FilterDuration from '../FilterDuration';
|
|||
import { debounce } from 'App/utils';
|
||||
import { assist as assistRoute, isRoute } from 'App/routes';
|
||||
import cn from 'classnames';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
const ASSIST_ROUTE = assistRoute();
|
||||
|
||||
interface Props {
|
||||
filter: any;
|
||||
onUpdate: (filter: any) => void;
|
||||
isConditional?: boolean;
|
||||
filter: any;
|
||||
onUpdate: (filter: any) => void;
|
||||
isConditional?: boolean;
|
||||
}
|
||||
function FilterValue(props: Props) {
|
||||
const { filter } = props;
|
||||
const [durationValues, setDurationValues] = useState({
|
||||
minDuration: filter.value[0],
|
||||
maxDuration: filter.value.length > 1 ? filter.value[1] : filter.value[0],
|
||||
});
|
||||
const showCloseButton = filter.value.length > 1;
|
||||
const lastIndex = filter.value.length - 1;
|
||||
const { filter } = props;
|
||||
const [durationValues, setDurationValues] = useState({
|
||||
minDuration: filter.value[0],
|
||||
maxDuration: filter.value.length > 1 ? filter.value[1] : filter.value[0],
|
||||
});
|
||||
const showCloseButton = filter.value.length > 1;
|
||||
|
||||
const onAddValue = () => {
|
||||
const newValue = filter.value.concat('');
|
||||
props.onUpdate({ ...filter, value: newValue });
|
||||
};
|
||||
const onAddValue = () => {
|
||||
const newValue = filter.value.concat('');
|
||||
props.onUpdate({ ...filter, value: newValue });
|
||||
};
|
||||
|
||||
const onRemoveValue = (valueIndex: any) => {
|
||||
const newValue = filter.value.filter((_: any, index: any) => index !== valueIndex);
|
||||
props.onUpdate({ ...filter, value: newValue });
|
||||
};
|
||||
|
||||
const onChange = (e: any, item: any, valueIndex: any) => {
|
||||
const newValues = filter.value.map((_: any, _index: any) => {
|
||||
if (_index === valueIndex) {
|
||||
return item;
|
||||
}
|
||||
return _;
|
||||
});
|
||||
props.onUpdate({ ...filter, value: newValues });
|
||||
};
|
||||
|
||||
const debounceOnSelect = React.useCallback(debounce(onChange, 500), [onChange]);
|
||||
|
||||
const onDurationChange = (newValues: any) => {
|
||||
setDurationValues({ ...durationValues, ...newValues });
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
if (filter.type === FilterType.DURATION) {
|
||||
const { maxDuration, minDuration } = filter;
|
||||
if (maxDuration || minDuration) return;
|
||||
if (maxDuration !== durationValues.maxDuration || minDuration !== durationValues.minDuration) {
|
||||
props.onUpdate({ ...filter, value: [durationValues.minDuration, durationValues.maxDuration] });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getParms = (key: any) => {
|
||||
let params: any = { type: filter.key };
|
||||
switch (filter.category) {
|
||||
case FilterCategory.METADATA:
|
||||
params = { type: FilterKey.METADATA, key: key };
|
||||
}
|
||||
|
||||
if (isRoute(ASSIST_ROUTE, window.location.pathname)) {
|
||||
params = { ...params, live: true };
|
||||
}
|
||||
|
||||
return params;
|
||||
};
|
||||
|
||||
const renderValueFiled = (value: any, valueIndex: any) => {
|
||||
const showOrButton = valueIndex === lastIndex && filter.type !== FilterType.NUMBER;
|
||||
switch (filter.type) {
|
||||
case FilterType.STRING:
|
||||
return (
|
||||
<FilterAutoCompleteLocal
|
||||
value={value}
|
||||
showCloseButton={showCloseButton}
|
||||
showOrButton={showOrButton}
|
||||
onAddValue={onAddValue}
|
||||
onRemoveValue={() => onRemoveValue(valueIndex)}
|
||||
onSelect={(e, item) => debounceOnSelect(e, item, valueIndex)}
|
||||
icon={filter.icon}
|
||||
/>
|
||||
);
|
||||
case FilterType.DROPDOWN:
|
||||
return (
|
||||
<FilterValueDropdown
|
||||
// search={true}
|
||||
value={value}
|
||||
placeholder={filter.placeholder}
|
||||
// filter={filter}
|
||||
options={filter.options}
|
||||
onChange={({ value }) => onChange(null, { value }, valueIndex)}
|
||||
/>
|
||||
);
|
||||
case FilterType.ISSUE:
|
||||
case FilterType.MULTIPLE_DROPDOWN:
|
||||
return (
|
||||
<FilterValueDropdown
|
||||
search={true}
|
||||
// multiple={true}
|
||||
value={value}
|
||||
// filter={filter}
|
||||
placeholder={filter.placeholder}
|
||||
options={filter.options}
|
||||
onChange={({ value }) => onChange(null, value, valueIndex)}
|
||||
onAddValue={onAddValue}
|
||||
onRemoveValue={() => onRemoveValue(valueIndex)}
|
||||
showCloseButton={showCloseButton}
|
||||
showOrButton={showOrButton}
|
||||
/>
|
||||
);
|
||||
case FilterType.DURATION:
|
||||
return (
|
||||
<FilterDuration
|
||||
onChange={onDurationChange}
|
||||
// onEnterPress={ this.handleClose }
|
||||
onBlur={handleBlur}
|
||||
minDuration={durationValues.minDuration}
|
||||
maxDuration={durationValues.maxDuration}
|
||||
isConditional={props.isConditional}
|
||||
/>
|
||||
);
|
||||
case FilterType.NUMBER_MULTIPLE:
|
||||
return (
|
||||
<FilterAutoCompleteLocal
|
||||
value={value}
|
||||
showCloseButton={showCloseButton}
|
||||
showOrButton={showOrButton}
|
||||
onAddValue={onAddValue}
|
||||
onRemoveValue={() => onRemoveValue(valueIndex)}
|
||||
onSelect={(e, item) => debounceOnSelect(e, item, valueIndex)}
|
||||
icon={filter.icon}
|
||||
type="number"
|
||||
/>
|
||||
);
|
||||
case FilterType.NUMBER:
|
||||
return (
|
||||
<FilterAutoCompleteLocal
|
||||
value={value}
|
||||
showCloseButton={showCloseButton}
|
||||
showOrButton={showOrButton}
|
||||
onAddValue={onAddValue}
|
||||
onRemoveValue={() => onRemoveValue(valueIndex)}
|
||||
onSelect={(e, item) => debounceOnSelect(e, item, valueIndex)}
|
||||
icon={filter.icon}
|
||||
type="number"
|
||||
allowDecimals={false}
|
||||
isMultilple={false}
|
||||
/>
|
||||
);
|
||||
case FilterType.MULTIPLE:
|
||||
return (
|
||||
<FilterAutoComplete
|
||||
value={value}
|
||||
showCloseButton={showCloseButton}
|
||||
showOrButton={showOrButton}
|
||||
onAddValue={onAddValue}
|
||||
onRemoveValue={() => onRemoveValue(valueIndex)}
|
||||
method={'GET'}
|
||||
endpoint="/PROJECT_ID/events/search"
|
||||
params={getParms(filter.key)}
|
||||
headerText={''}
|
||||
placeholder={filter.placeholder}
|
||||
onSelect={(e, item) => onChange(e, item, valueIndex)}
|
||||
icon={filter.icon}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cn("grid gap-3", { 'grid-cols-2': filter.hasSource, 'grid-cols-3' : !filter.hasSource })}>
|
||||
{filter.type === FilterType.DURATION
|
||||
? renderValueFiled(filter.value, 0)
|
||||
: filter.value &&
|
||||
filter.value.map((value: any, valueIndex: any) => <div key={valueIndex}>{renderValueFiled(value, valueIndex)}</div>)}
|
||||
</div>
|
||||
const onRemoveValue = (valueIndex: any) => {
|
||||
const newValue = filter.value.filter(
|
||||
(_: any, index: any) => index !== valueIndex
|
||||
);
|
||||
props.onUpdate({ ...filter, value: newValue });
|
||||
};
|
||||
|
||||
const onChange = (e: any, item: any, valueIndex: any) => {
|
||||
const newValues = filter.value.map((_: any, _index: any) => {
|
||||
if (_index === valueIndex) {
|
||||
return item;
|
||||
}
|
||||
return _;
|
||||
});
|
||||
props.onUpdate({ ...filter, value: newValues });
|
||||
};
|
||||
|
||||
const debounceOnSelect = React.useCallback(debounce(onChange, 500), [
|
||||
onChange,
|
||||
]);
|
||||
|
||||
const onDurationChange = (newValues: any) => {
|
||||
setDurationValues({ ...durationValues, ...newValues });
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
if (filter.type === FilterType.DURATION) {
|
||||
const { maxDuration, minDuration } = filter;
|
||||
if (maxDuration || minDuration) return;
|
||||
if (
|
||||
maxDuration !== durationValues.maxDuration ||
|
||||
minDuration !== durationValues.minDuration
|
||||
) {
|
||||
props.onUpdate({
|
||||
...filter,
|
||||
value: [durationValues.minDuration, durationValues.maxDuration],
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getParms = (key: any) => {
|
||||
let params: any = { type: filter.key };
|
||||
switch (filter.category) {
|
||||
case FilterCategory.METADATA:
|
||||
params = { type: FilterKey.METADATA, key: key };
|
||||
}
|
||||
|
||||
if (isRoute(ASSIST_ROUTE, window.location.pathname)) {
|
||||
params = { ...params, live: true };
|
||||
}
|
||||
|
||||
return params;
|
||||
};
|
||||
|
||||
const renderValueFiled = (value: any[]) => {
|
||||
const showOrButton = filter.value.length > 1;
|
||||
const valueIndex = 0;
|
||||
const BaseFilterLocalAutoComplete = (props) => (
|
||||
<FilterAutoCompleteLocal
|
||||
value={value}
|
||||
showCloseButton={showCloseButton}
|
||||
onAddValue={onAddValue}
|
||||
onRemoveValue={(index) => onRemoveValue(index)}
|
||||
onSelect={(e, item, index) => debounceOnSelect(e, item, index)}
|
||||
icon={filter.icon}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
switch (filter.type) {
|
||||
case FilterType.NUMBER_MULTIPLE:
|
||||
return <BaseFilterLocalAutoComplete type="number" />;
|
||||
case FilterType.NUMBER:
|
||||
return (
|
||||
<BaseFilterLocalAutoComplete
|
||||
type="number"
|
||||
allowDecimals={false}
|
||||
isMultiple={false}
|
||||
/>
|
||||
);
|
||||
case FilterType.STRING:
|
||||
return <BaseFilterLocalAutoComplete />;
|
||||
case FilterType.DROPDOWN:
|
||||
return (
|
||||
<FilterValueDropdown
|
||||
value={value}
|
||||
placeholder={filter.placeholder}
|
||||
options={filter.options}
|
||||
onChange={(item, index) => onChange(null, { value: item.value }, index)}
|
||||
/>
|
||||
);
|
||||
case FilterType.ISSUE:
|
||||
case FilterType.MULTIPLE_DROPDOWN:
|
||||
return (
|
||||
<FilterValueDropdown
|
||||
search={true}
|
||||
value={value}
|
||||
placeholder={filter.placeholder}
|
||||
options={filter.options}
|
||||
onChange={(item, index) => onChange(null, { value: item.value }, index)}
|
||||
onAddValue={onAddValue}
|
||||
onRemoveValue={(ind) => onRemoveValue(ind)}
|
||||
showCloseButton={showCloseButton}
|
||||
showOrButton={showOrButton}
|
||||
/>
|
||||
);
|
||||
case FilterType.DURATION:
|
||||
return (
|
||||
<FilterDuration
|
||||
onChange={onDurationChange}
|
||||
onBlur={handleBlur}
|
||||
minDuration={durationValues.minDuration}
|
||||
maxDuration={durationValues.maxDuration}
|
||||
isConditional={props.isConditional}
|
||||
/>
|
||||
);
|
||||
case FilterType.MULTIPLE:
|
||||
return (
|
||||
<FilterAutoComplete
|
||||
value={value}
|
||||
showCloseButton={showCloseButton}
|
||||
showOrButton={showOrButton}
|
||||
onAddValue={onAddValue}
|
||||
onRemoveValue={() => onRemoveValue(valueIndex)}
|
||||
method={'GET'}
|
||||
endpoint="/PROJECT_ID/events/search"
|
||||
params={getParms(filter.key)}
|
||||
headerText={''}
|
||||
placeholder={filter.placeholder}
|
||||
onSelect={(e, item) => onChange(e, item, valueIndex)}
|
||||
icon={filter.icon}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn('grid gap-3', {
|
||||
'grid-cols-2': filter.hasSource,
|
||||
'grid-cols-3': !filter.hasSource,
|
||||
})}
|
||||
>
|
||||
{renderValueFiled(filter.value)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default FilterValue;
|
||||
// const isEmpty = filter.value.length === 0 || !filter.value[0].length;
|
||||
// return (
|
||||
// <div
|
||||
// className={
|
||||
// 'rounded border border-gray-light px-2 relative w-fit whitespace-nowrap'
|
||||
// }
|
||||
// style={{ height: 26 }}
|
||||
// ref={filterValueContainer}
|
||||
// >
|
||||
// <div onClick={() => setShowValueModal(true)} className={'flex items-center gap-2 '}>
|
||||
// {!isEmpty ? (
|
||||
// <>
|
||||
// <div
|
||||
// className={
|
||||
// 'rounded-xl bg-gray-lighter leading-none px-1 py-0.5'
|
||||
// }
|
||||
// >
|
||||
// {filter.value[0]}
|
||||
// </div>
|
||||
// <div
|
||||
// className={
|
||||
// 'rounded-xl bg-gray-lighter leading-none px-1 py-0.5'
|
||||
// }
|
||||
// >
|
||||
// + {filter.value.length - 1} More
|
||||
// </div>
|
||||
// </>
|
||||
// ) : (
|
||||
// <div className={'text-disabled-text'}>Select values</div>
|
||||
// )}
|
||||
// </div>
|
||||
// {showValueModal ? (
|
||||
// <div
|
||||
// className={cn(
|
||||
// 'absolute left-0 mt-6 flex items-center gap-2 bg-white border shadow border-gray-light z-10',
|
||||
// {
|
||||
// 'grid-cols-2': filter.hasSource,
|
||||
// 'grid-cols-3': !filter.hasSource,
|
||||
// }
|
||||
// )}
|
||||
// style={{ minWidth: 200, minHeight: 100, top: '100%' }}
|
||||
// >
|
||||
// {filter.type === FilterType.DURATION
|
||||
// ? renderValueFiled(filter.value, 0)
|
||||
// : filter.value &&
|
||||
// filter.value.map((value: any, valueIndex: any) => (
|
||||
// <div key={valueIndex}>
|
||||
// {renderValueFiled(value, valueIndex)}
|
||||
// </div>
|
||||
// ))}
|
||||
// <div>
|
||||
// <Button>Apply</Button>
|
||||
// <Button>Cancel</Button>
|
||||
// </div>
|
||||
// </div>
|
||||
// ) : null}
|
||||
// </div>
|
||||
// );
|
||||
|
||||
export default observer(FilterValue);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
display: flex;
|
||||
align-items: stretch;
|
||||
padding: 0;
|
||||
background-color: $gray-lightest;
|
||||
background-color: white;
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
margin-left: auto;
|
||||
|
|
|
|||
|
|
@ -72,26 +72,28 @@ const dropdownStyles = {
|
|||
interface Props {
|
||||
placeholder?: string;
|
||||
value: string;
|
||||
onChange: (value: any) => void;
|
||||
onChange: (value: any, ind: number) => void;
|
||||
className?: string;
|
||||
options: any[];
|
||||
search?: boolean;
|
||||
showCloseButton?: boolean;
|
||||
showOrButton?: boolean;
|
||||
onRemoveValue?: () => void;
|
||||
onAddValue?: () => void;
|
||||
isMultilple?: boolean;
|
||||
onRemoveValue?: (ind: number) => void;
|
||||
onAddValue?: (ind: number) => void;
|
||||
isMultiple?: boolean;
|
||||
index: number;
|
||||
}
|
||||
function FilterValueDropdown(props: Props) {
|
||||
const {
|
||||
placeholder = 'Select',
|
||||
isMultilple = true,
|
||||
isMultiple = true,
|
||||
search = false,
|
||||
options,
|
||||
onChange,
|
||||
value,
|
||||
showCloseButton = true,
|
||||
showOrButton = true,
|
||||
index,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
|
|
@ -102,27 +104,54 @@ function FilterValueDropdown(props: Props) {
|
|||
options={options}
|
||||
name="issue_type"
|
||||
value={value ? options.find((item) => item.value === value) : null}
|
||||
onChange={(value: any) => onChange(value.value)}
|
||||
onChange={(value: any) => onChange(value.value, index)}
|
||||
placeholder={placeholder}
|
||||
styles={dropdownStyles}
|
||||
/>
|
||||
<div className={stl.right}>
|
||||
{showCloseButton && (
|
||||
<div onClick={props.onRemoveValue}>
|
||||
<div onClick={() => props.onRemoveValue?.(index)}>
|
||||
<Icon name="close" size="12" />
|
||||
</div>
|
||||
)}
|
||||
{showOrButton && (
|
||||
<div onClick={props.onAddValue} className="color-teal">
|
||||
<div onClick={() => props.onAddValue?.(index)} className="color-teal">
|
||||
<span className="px-1">or</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!showOrButton && isMultilple && <div className="ml-3">or</div>}
|
||||
{!showOrButton && isMultiple && <div className="ml-3">or</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default FilterValueDropdown;
|
||||
interface MainProps {
|
||||
placeholder?: string;
|
||||
value: string[];
|
||||
onChange: (value: any, ind: number) => void;
|
||||
className?: string;
|
||||
options: any[];
|
||||
search?: boolean;
|
||||
showCloseButton?: boolean;
|
||||
showOrButton?: boolean;
|
||||
onRemoveValue?: (ind: number) => void;
|
||||
onAddValue?: (ind: number) => void;
|
||||
isMultiple?: boolean;
|
||||
}
|
||||
|
||||
function FilterDropdownController(props: MainProps) {
|
||||
return props.value.map((value, index) => (
|
||||
<FilterValueDropdown
|
||||
{...props}
|
||||
key={index}
|
||||
value={value}
|
||||
index={index}
|
||||
showOrButton={index === props.value.length - 1}
|
||||
showCloseButton={props.value.length > 1}
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
||||
export default FilterDropdownController;
|
||||
|
|
|
|||
|
|
@ -26,19 +26,19 @@ interface Props<Value extends ValueObject> {
|
|||
}
|
||||
|
||||
export default function <Value extends ValueObject>({
|
||||
placeholder = 'Select',
|
||||
name = '',
|
||||
onChange,
|
||||
right = false,
|
||||
plain = false,
|
||||
options,
|
||||
isSearchable = false,
|
||||
components = {},
|
||||
styles = {},
|
||||
defaultValue = '',
|
||||
controlStyle = {},
|
||||
...rest
|
||||
}: Props<Value>) {
|
||||
placeholder = 'Select',
|
||||
name = '',
|
||||
onChange,
|
||||
right = false,
|
||||
plain = false,
|
||||
options,
|
||||
isSearchable = false,
|
||||
components = {},
|
||||
styles = {},
|
||||
defaultValue = '',
|
||||
controlStyle = {},
|
||||
...rest
|
||||
}: Props<Value>) {
|
||||
|
||||
const defaultSelected = Array.isArray(defaultValue) ?
|
||||
defaultValue.map((value) => options.find((option) => option.value === value)) :
|
||||
|
|
@ -79,7 +79,7 @@ export default function <Value extends ValueObject>({
|
|||
}),
|
||||
menuList: (provided: any, state: any) => ({
|
||||
...provided,
|
||||
padding: 0
|
||||
padding: 0,
|
||||
}),
|
||||
control: (provided: any) => {
|
||||
const obj = {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ export enum FilterCategory {
|
|||
RECORDING_ATTRIBUTES = 'Recording Attributes',
|
||||
TECHNICAL = 'Technical',
|
||||
USER = 'User Identification',
|
||||
METADATA = 'Session & User Metadata',
|
||||
METADATA = 'Metadata',
|
||||
PERFORMANCE = 'Performance',
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue