change(ui): default filters and events order
This commit is contained in:
parent
03486d2f4f
commit
3fb41b63d3
6 changed files with 116 additions and 138 deletions
|
|
@ -4,6 +4,7 @@ import {CARD_LIST, CARD_CATEGORIES, CardType} from './ExampleCards';
|
|||
import {useStore} from 'App/mstore';
|
||||
import Option from './Option';
|
||||
import CardsLibrary from "Components/Dashboard/components/DashboardList/NewDashModal/CardsLibrary";
|
||||
import {FUNNEL} from "App/constants/card";
|
||||
|
||||
interface SelectCardProps {
|
||||
onClose: (refresh?: boolean) => void;
|
||||
|
|
@ -20,22 +21,33 @@ const SelectCard: React.FC<SelectCardProps> = (props: SelectCardProps) => {
|
|||
const dashboardId = window.location.pathname.split('/')[3];
|
||||
const [libraryQuery, setLibraryQuery] = React.useState<string>('');
|
||||
|
||||
|
||||
const handleCardSelection = (card: string) => {
|
||||
console.log('card', card);
|
||||
const selectedCard = CARD_LIST.find((c) => c.key === card) as CardType;
|
||||
metricStore.merge({
|
||||
|
||||
const cardData: any = {
|
||||
metricType: selectedCard.cardType,
|
||||
name: selectedCard.title,
|
||||
metricOf: selectedCard.metricOf,
|
||||
});
|
||||
};
|
||||
|
||||
if (selectedCard.cardType === FUNNEL) {
|
||||
cardData.series = []
|
||||
cardData.series.filter = []
|
||||
}
|
||||
|
||||
metricStore.merge(cardData);
|
||||
metricStore.instance.resetDefaults();
|
||||
onCard();
|
||||
};
|
||||
|
||||
const cardItems = useMemo(() => {
|
||||
return CARD_LIST.filter((card) => card.category === selected).map((card) => (
|
||||
<div key={card.key} className={card.width ? `col-span-${card.width}` : 'col-span-2'}>
|
||||
<card.example onCard={handleCardSelection} type={card.key} title={card.title} data={card.data} height={card.height}/>
|
||||
<card.example onCard={handleCardSelection}
|
||||
type={card.key}
|
||||
title={card.title}
|
||||
data={card.data}
|
||||
height={card.height}/>
|
||||
</div>
|
||||
));
|
||||
}, [selected]);
|
||||
|
|
@ -58,11 +70,6 @@ const SelectCard: React.FC<SelectCardProps> = (props: SelectCardProps) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
{/*<Header selectedCount={selectedCards.length}*/}
|
||||
{/* onAdd={onAddSelected}*/}
|
||||
{/* title={dashboardId ? (isLibrary ? "Add Card" : "Create Card") : "Select a template to create a card"}*/}
|
||||
{/*/>*/}
|
||||
|
||||
<Space className="items-center justify-between">
|
||||
<div className="text-xl leading-4 font-medium">
|
||||
{dashboardId ? (isLibrary ? "Add Card" : "Create Card") : "Select a template to create a card"}
|
||||
|
|
@ -77,7 +84,6 @@ const SelectCard: React.FC<SelectCardProps> = (props: SelectCardProps) => {
|
|||
|
||||
<Input.Search
|
||||
placeholder="Search"
|
||||
// onSearch={(value) => setLibraryQuery(value)}
|
||||
onChange={(value) => setLibraryQuery(value.target.value)}
|
||||
style={{width: 200}}
|
||||
/>
|
||||
|
|
@ -86,32 +92,17 @@ const SelectCard: React.FC<SelectCardProps> = (props: SelectCardProps) => {
|
|||
</Space>
|
||||
|
||||
{!isLibrary && <CategorySelector setSelected={setSelectedCategory} selected={selected}/>}
|
||||
{isLibrary ? <CardsLibrary query={libraryQuery} selectedList={selectedCards} category={selected}
|
||||
onCard={onCardClick}/> :
|
||||
|
||||
{isLibrary ?
|
||||
<CardsLibrary query={libraryQuery}
|
||||
selectedList={selectedCards}
|
||||
category={selected}
|
||||
onCard={onCardClick}/> :
|
||||
<ExampleCardsGrid items={cardItems}/>}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// interface HeaderProps {
|
||||
// selectedCount?: number,
|
||||
// onAdd?: () => void;
|
||||
// title?: string;
|
||||
// }
|
||||
//
|
||||
// const Header: React.FC<HeaderProps> = ({title = '', selectedCount = 0, onAdd = () => null}) => (
|
||||
// <div className="flex items-center justify-between">
|
||||
// <div className="text-lg leading-4 font-semibold">{title}</div>
|
||||
// <div className="text-sm text-gray-500">
|
||||
// {selectedCount > 0 ? (
|
||||
// <Button type="link" onClick={onAdd}>
|
||||
// Add {selectedCount} Selected
|
||||
// </Button>
|
||||
// ) : ''}
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
|
||||
interface CategorySelectorProps {
|
||||
setSelected?: React.Dispatch<React.SetStateAction<string>>;
|
||||
selected?: string;
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ function FilterSeries(props: Props) {
|
|||
}
|
||||
|
||||
const onChangeEventsOrder = (_: any, {name, value}: any) => {
|
||||
console.log(name, value)
|
||||
series.filter.updateKey(name, value);
|
||||
observeChanges();
|
||||
};
|
||||
|
|
@ -129,7 +130,7 @@ function FilterSeries(props: Props) {
|
|||
)}
|
||||
|
||||
{expandable && !expanded && (
|
||||
<Space className="justify-between w-full px-6 py-2">
|
||||
<Space className="justify-between w-full px-5 py-2">
|
||||
<FilterCountLabels filters={series.filter.filters} toggleExpand={() => setExpanded(!expanded)}/>
|
||||
<Button onClick={() => setExpanded(!expanded)}
|
||||
size="small"
|
||||
|
|
@ -162,7 +163,7 @@ function FilterSeries(props: Props) {
|
|||
)}
|
||||
</div>
|
||||
<div className="border-t h-12 flex items-center">
|
||||
<div className="-mx-4 px-6">
|
||||
<div className="-mx-4 px-5">
|
||||
<AddStepButton excludeFilterKeys={excludeFilterKeys} series={series}/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
import {observer} from "mobx-react-lite";
|
||||
import {Tooltip} from "UI";
|
||||
import {Segmented} from "antd";
|
||||
import React from "react";
|
||||
|
||||
const EventsOrder = observer((props: {
|
||||
onChange: (e: any, v: any) => void,
|
||||
filter: any,
|
||||
}) => {
|
||||
const {filter, onChange} = props;
|
||||
const eventsOrderSupport = filter.eventsOrderSupport;
|
||||
const options = [
|
||||
{
|
||||
name: 'eventsOrder',
|
||||
label: 'THEN',
|
||||
value: 'then',
|
||||
disabled: eventsOrderSupport && !eventsOrderSupport.includes('then'),
|
||||
},
|
||||
{
|
||||
name: 'eventsOrder',
|
||||
label: 'AND',
|
||||
value: 'and',
|
||||
disabled: eventsOrderSupport && !eventsOrderSupport.includes('and'),
|
||||
},
|
||||
{
|
||||
name: 'eventsOrder',
|
||||
label: 'OR',
|
||||
value: 'or',
|
||||
disabled: eventsOrderSupport && !eventsOrderSupport.includes('or'),
|
||||
},
|
||||
];
|
||||
|
||||
return <div className="flex items-center gap-2">
|
||||
<div
|
||||
className="color-gray-medium text-sm"
|
||||
style={{textDecoration: "underline dotted"}}
|
||||
>
|
||||
<Tooltip
|
||||
title={`Select the operator to be applied between events in your search.`}
|
||||
>
|
||||
<div>Events Order</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<Segmented
|
||||
size={"small"}
|
||||
className="text-sm"
|
||||
onChange={(v) => onChange(null, options.find((i) => i.value === v))}
|
||||
value={filter.eventsOrder}
|
||||
options={options}
|
||||
/>
|
||||
</div>;
|
||||
});
|
||||
|
||||
export default EventsOrder;
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
import {Segmented} from 'antd';
|
||||
import {Space} from 'antd';
|
||||
import {List} from 'immutable';
|
||||
import {GripHorizontal} from 'lucide-react';
|
||||
import {observer} from 'mobx-react-lite';
|
||||
import React, {useEffect} from 'react';
|
||||
|
||||
import {Tooltip} from 'UI';
|
||||
|
||||
import FilterItem from '../FilterItem';
|
||||
import EventsOrder from "Shared/Filters/FilterList/EventsOrder";
|
||||
|
||||
interface Props {
|
||||
filter?: any; // event/filter
|
||||
|
|
@ -38,7 +37,6 @@ function FilterList(props: Props) {
|
|||
} = props;
|
||||
|
||||
const filters = List(filter.filters);
|
||||
const eventsOrderSupport = filter.eventsOrderSupport;
|
||||
const hasEvents = filters.filter((i: any) => i.isEvent).size > 0;
|
||||
const hasFilters = filters.filter((i: any) => !i.isEvent).size > 0;
|
||||
|
||||
|
|
@ -111,25 +109,6 @@ function FilterList(props: Props) {
|
|||
[draggedInd, hoveredItem, filters, props.onFilterMove]
|
||||
);
|
||||
|
||||
const eventOrderItems = [
|
||||
{
|
||||
label: 'THEN',
|
||||
value: 'then',
|
||||
disabled: eventsOrderSupport && !eventsOrderSupport.includes('then'),
|
||||
|
||||
},
|
||||
{
|
||||
label: 'AND',
|
||||
value: 'and',
|
||||
disabled: eventsOrderSupport && !eventsOrderSupport.includes('and'),
|
||||
},
|
||||
{
|
||||
label: 'OR',
|
||||
value: 'or',
|
||||
disabled: eventsOrderSupport && !eventsOrderSupport.includes('or'),
|
||||
},
|
||||
];
|
||||
|
||||
const eventsNum = filters.filter((i: any) => i.isEvent).size
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
|
|
@ -137,37 +116,16 @@ function FilterList(props: Props) {
|
|||
<>
|
||||
<div className="flex items-center mb-2">
|
||||
<div className="text-sm color-gray-medium mr-auto">
|
||||
{filter.eventsHeader}
|
||||
{filter.eventsHeader || 'EVENTS'}
|
||||
</div>
|
||||
{!hideEventsOrder && (
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="color-gray-medium text-sm"
|
||||
style={{textDecoration: 'underline dotted'}}
|
||||
>
|
||||
<Tooltip
|
||||
title={`Select the operator to be applied between events in your search.`}
|
||||
>
|
||||
<div>Events Order</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<Segmented
|
||||
size={'small'}
|
||||
onChange={(v) =>
|
||||
props.onChangeEventsOrder(
|
||||
null,
|
||||
eventOrderItems.find((i) => i.value === v)
|
||||
)
|
||||
}
|
||||
value={filter.eventsOrder}
|
||||
options={eventOrderItems}
|
||||
/>
|
||||
{actions && actions.map((action, index) => (
|
||||
<div key={index}>{action}</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<Space>
|
||||
{!hideEventsOrder && <EventsOrder filter={filter}
|
||||
onChange={props.onChangeEventsOrder}/>}
|
||||
{actions && actions.map((action, index) => (
|
||||
<div key={index}>{action}</div>
|
||||
))}
|
||||
</Space>
|
||||
</div>
|
||||
<div className={'flex flex-col'}>
|
||||
{filters.map((filter: any, filterIndex: number) =>
|
||||
|
|
@ -263,50 +221,3 @@ function FilterList(props: Props) {
|
|||
}
|
||||
|
||||
export default observer(FilterList);
|
||||
|
||||
|
||||
function EventsOrder(props: {
|
||||
onChange: (e: any, v: any) => void,
|
||||
filter: any,
|
||||
eventsOrderSupport: any
|
||||
}) {
|
||||
const {filter, eventsOrderSupport, onChange} = props;
|
||||
const options = [
|
||||
{
|
||||
label: 'THEN',
|
||||
value: 'then',
|
||||
disabled: eventsOrderSupport && !eventsOrderSupport.includes('then'),
|
||||
},
|
||||
{
|
||||
label: 'AND',
|
||||
value: 'and',
|
||||
disabled: eventsOrderSupport && !eventsOrderSupport.includes('and'),
|
||||
},
|
||||
{
|
||||
label: 'OR',
|
||||
value: 'or',
|
||||
disabled: eventsOrderSupport && !eventsOrderSupport.includes('or'),
|
||||
},
|
||||
];
|
||||
|
||||
return <div className="flex items-center gap-2">
|
||||
<div
|
||||
className="color-gray-medium text-sm"
|
||||
style={{textDecoration: "underline dotted"}}
|
||||
>
|
||||
<Tooltip
|
||||
title={`Select the operator to be applied between events in your search.`}
|
||||
>
|
||||
<div>Events Order</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<Segmented
|
||||
size={"small"}
|
||||
// onChange={props.onChange}
|
||||
onChange={(v) => onChange(null, options.find((i) => i.value === v))}
|
||||
value={filter.eventsOrder}
|
||||
options={options}
|
||||
/>
|
||||
</div>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
import { makeAutoObservable, runInAction, observable, action } from "mobx"
|
||||
import {makeAutoObservable, runInAction, observable, action} from "mobx"
|
||||
import FilterItem from "./filterItem"
|
||||
import { filtersMap, conditionalFiltersMap } from 'Types/filter/newFilter';
|
||||
import {filtersMap, conditionalFiltersMap} from 'Types/filter/newFilter';
|
||||
import {FilterKey} from "Types/filter/filterType";
|
||||
|
||||
export default class Filter {
|
||||
public static get ID_KEY():string { return "filterId" }
|
||||
public static get ID_KEY(): string {
|
||||
return "filterId"
|
||||
}
|
||||
|
||||
filterId: string = ''
|
||||
name: string = ''
|
||||
filters: FilterItem[] = []
|
||||
|
|
@ -70,7 +74,7 @@ export default class Filter {
|
|||
fromJson(json: any) {
|
||||
this.name = json.name
|
||||
this.filters = json.filters.map((i: Record<string, any>) =>
|
||||
new FilterItem(undefined, this.isConditional, this.isMobile).fromJson(i)
|
||||
new FilterItem(undefined, this.isConditional, this.isMobile).fromJson(i)
|
||||
);
|
||||
this.eventsOrder = json.eventsOrder
|
||||
return this
|
||||
|
|
@ -79,7 +83,7 @@ export default class Filter {
|
|||
fromData(data) {
|
||||
this.name = data.name
|
||||
this.filters = data.filters.map((i: Record<string, any>) =>
|
||||
new FilterItem(undefined, this.isConditional, this.isMobile).fromData(i)
|
||||
new FilterItem(undefined, this.isConditional, this.isMobile).fromData(i)
|
||||
)
|
||||
this.eventsOrder = data.eventsOrder
|
||||
return this
|
||||
|
|
@ -121,4 +125,10 @@ export default class Filter {
|
|||
removeExcludeFilter(index: number) {
|
||||
this.excludes.splice(index, 1)
|
||||
}
|
||||
|
||||
addFunnelDefaultFilters() {
|
||||
this.filters = []
|
||||
this.addFilter({...filtersMap[FilterKey.CLICK], value: [''], operator: 'onAny'})
|
||||
this.addFilter({...filtersMap[FilterKey.CLICK], value: [''], operator: 'onAny'})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -265,6 +265,16 @@ export default class Widget {
|
|||
});
|
||||
}
|
||||
|
||||
resetDefaults() {
|
||||
if (this.metricType === FUNNEL) {
|
||||
this.series = [];
|
||||
this.series.push(new FilterSeries());
|
||||
this.series[0].filter.addFunnelDefaultFilters();
|
||||
this.series[0].filter.eventsOrder = 'then';
|
||||
this.series[0].filter.eventsOrderSupport = ['then'];
|
||||
}
|
||||
}
|
||||
|
||||
exists() {
|
||||
return this.metricId !== undefined;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue