change(ui): customMetrics cleanup
This commit is contained in:
parent
d4d836ad24
commit
f2e103ad08
8 changed files with 2 additions and 755 deletions
|
|
@ -1,17 +0,0 @@
|
|||
import React from 'react';
|
||||
import { IconButton } from 'UI';
|
||||
import { connect } from 'react-redux';
|
||||
import { edit, init } from 'Duck/customMetrics';
|
||||
|
||||
interface Props {
|
||||
init: (instance?, setDefault?) => void;
|
||||
}
|
||||
function CustomMetrics(props: Props) {
|
||||
return (
|
||||
<div className="self-start">
|
||||
<IconButton plain outline icon="plus" label="CREATE METRIC" onClick={() => props.init()} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, { edit, init })(CustomMetrics);
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
.wrapper {
|
||||
padding: 20px;
|
||||
background-color: #f6f6f6;
|
||||
min-height: calc(100vh - 59px);
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
display: flex !important;
|
||||
padding: 4px 6px;
|
||||
border-radius: 3px;
|
||||
color: $gray-darkest;
|
||||
font-weight: 500;
|
||||
&:hover {
|
||||
background-color: $gray-light;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdownTrigger {
|
||||
padding: 4px 8px;
|
||||
border-radius: 3px;
|
||||
&:hover {
|
||||
background-color: $gray-light;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdownIcon {
|
||||
margin-top: 2px;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { SlideModal, NoContent, Dropdown, Icon, TimezoneDropdown, Loader } from 'UI';
|
||||
import SessionItem from 'Shared/SessionItem';
|
||||
import stl from './SessionListModal.module.css';
|
||||
import { connect } from 'react-redux';
|
||||
import { fetchSessionList, setActiveWidget } from 'Duck/customMetrics';
|
||||
import { DateTime } from 'luxon';
|
||||
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
|
||||
interface Props {
|
||||
loading: boolean;
|
||||
list: any;
|
||||
fetchSessionList: (params) => void;
|
||||
activeWidget: any;
|
||||
setActiveWidget: (widget) => void;
|
||||
}
|
||||
function SessionListModal(props: Props) {
|
||||
const { activeWidget, loading, list } = props;
|
||||
const [seriesOptions, setSeriesOptions] = useState([
|
||||
{ text: 'All', value: 'all' },
|
||||
]);
|
||||
const [activeSeries, setActiveSeries] = useState('all');
|
||||
useEffect(() => {
|
||||
if (!activeWidget || !activeWidget.widget) return;
|
||||
props.fetchSessionList({
|
||||
metricId: activeWidget.widget.metricId,
|
||||
startDate: activeWidget.startTimestamp,
|
||||
endDate: activeWidget.endTimestamp,
|
||||
filters: activeWidget.filters || [],
|
||||
});
|
||||
}, [activeWidget]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!list) return;
|
||||
const seriesOptions = list.map(item => ({
|
||||
text: item.seriesName,
|
||||
value: item.seriesId,
|
||||
}));
|
||||
setSeriesOptions([
|
||||
{ text: 'All', value: 'all' },
|
||||
...seriesOptions,
|
||||
]);
|
||||
}, [list]);
|
||||
|
||||
const getListSessionsBySeries = (seriesId) => {
|
||||
const arr: any = []
|
||||
list.forEach(element => {
|
||||
if (seriesId === 'all') {
|
||||
const sessionIds = arr.map(i => i.sessionId);
|
||||
arr.push(...element.sessions.filter(i => !sessionIds.includes(i.sessionId)));
|
||||
} else {
|
||||
if (element.seriesId === seriesId) {
|
||||
arr.push(...element.sessions)
|
||||
}
|
||||
}
|
||||
});
|
||||
return arr;
|
||||
}
|
||||
|
||||
const writeOption = (e, { name, value }) => setActiveSeries(value);
|
||||
const filteredSessions = getListSessionsBySeries(activeSeries);
|
||||
const startTime = DateTime.fromMillis(activeWidget.startTimestamp).toFormat('LLL dd, yyyy HH:mm a');
|
||||
const endTime = DateTime.fromMillis(activeWidget.endTimestamp).toFormat('LLL dd, yyyy HH:mm a');
|
||||
|
||||
return (
|
||||
<SlideModal
|
||||
title={ activeWidget && (
|
||||
<div className="flex items-center">
|
||||
<div className="mr-auto">{ activeWidget.widget.name } </div>
|
||||
</div>
|
||||
)}
|
||||
isDisplayed={ !!activeWidget }
|
||||
onClose={ () => props.setActiveWidget(null)}
|
||||
content={ activeWidget && (
|
||||
<div className={ stl.wrapper }>
|
||||
<div className="mb-6 flex items-center">
|
||||
<div className="mr-auto">Showing all sessions between <span className="font-medium">{startTime}</span> and <span className="font-medium">{endTime}</span> </div>
|
||||
<div className="flex items-center ml-6">
|
||||
<div className="flex items-center">
|
||||
<span className="mr-2 color-gray-medium">Timezone</span>
|
||||
<TimezoneDropdown />
|
||||
</div>
|
||||
{ activeWidget.widget.metricType !== 'table' && (
|
||||
<div className="flex items-center ml-6">
|
||||
<span className="mr-2 color-gray-medium">Series</span>
|
||||
<Dropdown
|
||||
className={stl.dropdown}
|
||||
direction="left"
|
||||
options={ seriesOptions }
|
||||
name="change"
|
||||
value={ activeSeries }
|
||||
onChange={ writeOption }
|
||||
id="change-dropdown"
|
||||
// icon={null}
|
||||
icon={ <Icon name="chevron-down" color="gray-dark" size="14" className={stl.dropdownIcon} /> }
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* <span className="mr-2 color-gray-medium">Series</span> */}
|
||||
</div>
|
||||
</div>
|
||||
<Loader loading={loading}>
|
||||
<NoContent
|
||||
show={ !loading && (filteredSessions.length === 0 )}
|
||||
title={
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<AnimatedSVG name={ICONS.NO_RESULTS} size={60} />
|
||||
<div className="mt-6 text-2xl">No recordings found!</div>
|
||||
</div>
|
||||
}
|
||||
// animatedIcon="no-results"
|
||||
>
|
||||
{ filteredSessions.map(session => <SessionItem key={ session.sessionId } session={ session } />) }
|
||||
</NoContent>
|
||||
</Loader>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(state => ({
|
||||
loading: state.getIn(['customMetrics', 'fetchSessionList', 'loading']),
|
||||
list: state.getIn(['customMetrics', 'sessionList']),
|
||||
// activeWidget: state.getIn(['customMetrics', 'activeWidget']),
|
||||
}), { fetchSessionList, setActiveWidget })(SessionListModal);
|
||||
|
|
@ -1 +0,0 @@
|
|||
export { default } from './SessionListModal';
|
||||
|
|
@ -1 +0,0 @@
|
|||
export { default } from './CustomMetrics';
|
||||
|
|
@ -1,203 +0,0 @@
|
|||
import { List, Map } from 'immutable';
|
||||
import CustomMetric, { FilterSeries } from 'Types/customMetric'
|
||||
import { fetchListType, fetchType, saveType, removeType, editType, createRemove, createEdit } from './funcTools/crud';
|
||||
import { createRequestReducer, ROOT_KEY } from './funcTools/request';
|
||||
import { array, success, createListUpdater, mergeReducers } from './funcTools/tools';
|
||||
import Filter from 'Types/filter';
|
||||
import Session from 'Types/session';
|
||||
|
||||
const name = "custom_metric";
|
||||
const idKey = "metricId";
|
||||
|
||||
const FETCH_LIST = fetchListType(name);
|
||||
const FETCH_SESSION_LIST = fetchListType(`${name}/FETCH_SESSION_LIST`);
|
||||
const FETCH = fetchType(name);
|
||||
const SAVE = saveType(name);
|
||||
|
||||
const ADD_SERIES = `${name}/ADD_SERIES`;
|
||||
const REMOVE_SERIES = `${name}/REMOVE_SERIES`;
|
||||
|
||||
const ADD_SERIES_FILTER_FILTER = `${name}/ADD_SERIES_FILTER_FILTER`;
|
||||
const REMOVE_SERIES_FILTER_FILTER = `${name}/REMOVE_SERIES_FILTER_FILTER`;
|
||||
|
||||
const EDIT_SERIES_FILTER = `${name}/EDIT_SERIES_FILTER`;
|
||||
const EDIT_SERIES_FILTER_FILTER = `${name}/EDIT_SERIES_FILTER_FILTER`;
|
||||
const UPDATE_ACTIVE_STATE = saveType(`${name}/UPDATE_ACTIVE_STATE`);
|
||||
const EDIT = editType(name);
|
||||
const INIT = `${name}/INIT`;
|
||||
const SET_ACTIVE_WIDGET = `${name}/SET_ACTIVE_WIDGET`;
|
||||
const REMOVE = removeType(name);
|
||||
const UPDATE_SERIES = `${name}/UPDATE_SERIES`;
|
||||
|
||||
const updateItemInList = createListUpdater(idKey);
|
||||
const updateInstance = (state, instance) => state.getIn([ "instance", idKey ]) === instance[ idKey ]
|
||||
? state.mergeIn([ "instance" ], instance)
|
||||
: state;
|
||||
|
||||
const defaultInstance = CustomMetric({
|
||||
name: 'New',
|
||||
series: List([
|
||||
{
|
||||
name: 'Series 1',
|
||||
filter: new Filter({ filters: List(), eventsOrder: 'then' }),
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
const initialState = Map({
|
||||
list: List(),
|
||||
sessionList: List(),
|
||||
alertMetricId: null,
|
||||
instance: null,
|
||||
activeWidget: null,
|
||||
});
|
||||
|
||||
// Metric - Series - [] - filters
|
||||
function reducer(state = initialState, action = {}) {
|
||||
switch (action.type) {
|
||||
// Custom Metric
|
||||
case INIT:
|
||||
return state.set('instance', action.instance);
|
||||
case EDIT:
|
||||
return state.mergeIn([ 'instance' ], action.instance);
|
||||
case ADD_SERIES:
|
||||
const series = new FilterSeries(action.series);
|
||||
return state.updateIn([ 'instance', 'series' ], list => list.push(series));
|
||||
case REMOVE_SERIES:
|
||||
return state.updateIn([ 'instance', 'series' ], list => list.delete(action.index));
|
||||
case UPDATE_SERIES:
|
||||
return state.mergeIn(['instance', 'series', action.index], action.series);
|
||||
|
||||
// Custom Metric - Series - Filters
|
||||
case EDIT_SERIES_FILTER:
|
||||
return state.mergeIn(['instance', 'series', action.seriesIndex, 'filter'], action.filter);
|
||||
|
||||
// Custom Metric - Series - Filter - Filters
|
||||
case EDIT_SERIES_FILTER_FILTER:
|
||||
return state.updateIn([ 'instance', 'series', action.seriesIndex, 'filter', 'filters' ], filters => filters.set(action.filterIndex, action.filter));
|
||||
case ADD_SERIES_FILTER_FILTER:
|
||||
return state.updateIn([ 'instance', 'series', action.seriesIndex, 'filter', 'filters' ], filters => filters.push(action.filter));
|
||||
case REMOVE_SERIES_FILTER_FILTER:
|
||||
return state.updateIn([ 'instance', 'series', action.seriesIndex, 'filter', 'filters' ], filters => filters.delete(action.index));
|
||||
|
||||
|
||||
|
||||
case success(SAVE):
|
||||
return updateItemInList(updateInstance(state, action.data), action.data);
|
||||
case success(REMOVE):
|
||||
return state.update('list', list => list.filter(item => item.metricId !== action.id));
|
||||
case success(FETCH):
|
||||
return state.set("instance", CustomMetric(action.data));
|
||||
case success(FETCH_LIST):
|
||||
const { data } = action;
|
||||
return state.set("list", List(data.map(CustomMetric)));
|
||||
case success(FETCH_SESSION_LIST):
|
||||
return state.set("sessionList", List(action.data.map(item => ({ ...item, sessions: item.sessions.map(s => new Session(s)) }))));
|
||||
case SET_ACTIVE_WIDGET:
|
||||
return state.set("activeWidget", action.widget).set('sessionList', List());
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
export default mergeReducers(
|
||||
reducer,
|
||||
createRequestReducer({
|
||||
[ ROOT_KEY ]: FETCH_LIST,
|
||||
fetch: FETCH,
|
||||
save: SAVE,
|
||||
fetchSessionList: FETCH_SESSION_LIST,
|
||||
}),
|
||||
);
|
||||
|
||||
export const edit = createEdit(name);
|
||||
export const remove = createRemove(name);
|
||||
|
||||
export function fetch(id) {
|
||||
return {
|
||||
id,
|
||||
types: array(FETCH),
|
||||
call: c => c.get(`/errors/${id}`),
|
||||
}
|
||||
}
|
||||
|
||||
export const save = (instance) => (dispatch, getState) => {
|
||||
return dispatch({
|
||||
types: SAVE.array,
|
||||
call: client => client.post( `/${ instance.exists() ? name + 's/' + instance[idKey] : name + 's'}`, instance.toSaveData()),
|
||||
}).then(() => {
|
||||
dispatch(fetchList());
|
||||
});
|
||||
};
|
||||
|
||||
export function fetchList() {
|
||||
return {
|
||||
types: array(FETCH_LIST),
|
||||
call: client => client.get(`/${name}s`),
|
||||
};
|
||||
}
|
||||
|
||||
export const init = (instance = null, forceNull = false) => (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: INIT,
|
||||
instance: forceNull ? null : (instance || defaultInstance),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const fetchSessionList = (params) => (dispatch, getState) => {
|
||||
dispatch({
|
||||
types: array(FETCH_SESSION_LIST),
|
||||
call: client => client.post(`/custom_metrics/${params.metricId}/sessions`, { ...params }),
|
||||
});
|
||||
}
|
||||
|
||||
export const setActiveWidget = (widget) => (dispatch, getState) => {
|
||||
return dispatch({
|
||||
type: SET_ACTIVE_WIDGET,
|
||||
widget,
|
||||
});
|
||||
}
|
||||
|
||||
export const updateActiveState = (metricId, state) => (dispatch, getState) => {
|
||||
return dispatch({
|
||||
types: UPDATE_ACTIVE_STATE.array,
|
||||
call: client => client.post(`/custom_metrics/${metricId}/status`, { active: state }),
|
||||
metricId
|
||||
}).then(() => {
|
||||
dispatch(fetchList());
|
||||
});
|
||||
}
|
||||
|
||||
export const editSeriesFilter = (seriesIndex, filter) => (dispatch, getState) => {
|
||||
return dispatch({
|
||||
type: EDIT_SERIES_FILTER,
|
||||
seriesIndex,
|
||||
filter,
|
||||
});
|
||||
}
|
||||
|
||||
export const addSeriesFilterFilter = (seriesIndex, filter) => (dispatch, getState) => {
|
||||
return dispatch({
|
||||
type: ADD_SERIES_FILTER_FILTER,
|
||||
seriesIndex,
|
||||
filter,
|
||||
});
|
||||
}
|
||||
|
||||
export const removeSeriesFilterFilter = (seriesIndex, filterIndex) => (dispatch, getState) => {
|
||||
return dispatch({
|
||||
type: REMOVE_SERIES_FILTER_FILTER,
|
||||
seriesIndex,
|
||||
index: filterIndex,
|
||||
});
|
||||
}
|
||||
|
||||
export const editSeriesFilterFilter = (seriesIndex, filterIndex, filter) => (dispatch, getState) => {
|
||||
return dispatch({
|
||||
type: EDIT_SERIES_FILTER_FILTER,
|
||||
seriesIndex,
|
||||
filterIndex,
|
||||
filter,
|
||||
});
|
||||
}
|
||||
|
|
@ -1,375 +0,0 @@
|
|||
import { List, Map, Set } from 'immutable';
|
||||
import { errors as errorsRoute } from "App/routes";
|
||||
import Filter from 'Types/filter';
|
||||
import SavedFilter from 'Types/filter/savedFilter';
|
||||
import Event from 'Types/filter/event';
|
||||
import CustomFilter from 'Types/filter/customFilter';
|
||||
import withRequestState, { RequestTypes } from './requestStateCreator';
|
||||
import { fetch as fetchFunnel, fetchInsights, fetchIssuesFiltered, fetchSessionsFiltered } from './funnels';
|
||||
|
||||
const ERRORS_ROUTE = errorsRoute();
|
||||
|
||||
const FETCH_LIST = new RequestTypes('funnelFilters/FETCH_LIST');
|
||||
const FETCH_FILTER_OPTIONS = new RequestTypes('funnelFilters/FETCH_FILTER_OPTIONS');
|
||||
const SET_FILTER_OPTIONS = 'funnelFilters/SET_FILTER_OPTIONS';
|
||||
const SAVE = new RequestTypes('funnelFilters/SAVE');
|
||||
const REMOVE = new RequestTypes('funnelFilters/REMOVE');
|
||||
|
||||
const RESET = 'funnelFilters/RESET';
|
||||
const SET_SEARCH_QUERY = 'funnelFilters/SET_SEARCH_QUERY';
|
||||
const SET_ACTIVE = 'funnelFilters/SET_ACTIVE';
|
||||
const SET_ACTIVE_KEY = 'funnelFilters/SET_ACTIVE_KEY';
|
||||
const APPLY = 'funnelFilters/APPLY';
|
||||
const ADD_CUSTOM_FILTER = 'funnelFilters/ADD_CUSTOM_FILTER';
|
||||
const REMOVE_CUSTOM_FILTER = 'funnelFilters/REMOVE_CUSTOM_FILTER';
|
||||
const RESET_KEY = 'funnelFilters/RESET_KEY';
|
||||
const ADD_EVENT = 'funnelFilters/ADD_EVENT';
|
||||
const EDIT_EVENT = 'funnelFilters/EDIT_EVENT';
|
||||
const REMOVE_EVENT = 'funnelFilters/REMOVE_EVENT';
|
||||
const MOVE_EVENT = 'funnelFilters/MOVE_EVENT';
|
||||
const CLEAR_EVENTS = 'funnelFilters/CLEAR_EVENTS';
|
||||
const TOGGLE_FILTER_MODAL = 'funnelFilters/TOGGLE_FILTER_MODAL';
|
||||
const ADD_ATTRIBUTE = 'funnelFilters/ADD_ATTRIBUTE';
|
||||
const EDIT_ATTRIBUTE = 'funnelFilters/EDIT_ATTRIBUTE';
|
||||
const REMOVE_ATTRIBUTE = 'funnelFilters/REMOVE_ATTRIBUTE';
|
||||
const SET_ACTIVE_FLOW = 'funnelFilters/SET_ACTIVE_FLOW';
|
||||
|
||||
const SET_INITIAL_FILTER = 'funnelFilters/SET_INITIAL_FILTER';
|
||||
|
||||
const initialState = Map({
|
||||
activeFilter: null,
|
||||
list: List(),
|
||||
appliedFilter: Filter(),
|
||||
activeFilterKey: null,
|
||||
saveModalOpen: false,
|
||||
customFilters: Map(),
|
||||
searchQuery: '',
|
||||
activeFlow: null,
|
||||
filterOptions: Map({
|
||||
USEROS: Set(),
|
||||
USERBROWSER: Set(),
|
||||
USERDEVICE: Set(),
|
||||
REFERRER: Set(),
|
||||
USERCOUNTRY: Set(),
|
||||
}),
|
||||
});
|
||||
|
||||
let hasFilterOptions = false;
|
||||
|
||||
const updateList = (state, instance) => state.update('list', (list) => {
|
||||
const index = list.findIndex(item => item.filterId === instance.filterId);
|
||||
return (index >= 0
|
||||
? list.mergeIn([ index ], instance)
|
||||
: list.push(instance)
|
||||
);
|
||||
});
|
||||
|
||||
const reducer = (state = initialState, action = {}) => {
|
||||
let optionsMap = null;
|
||||
switch (action.type) {
|
||||
case FETCH_FILTER_OPTIONS.SUCCESS:
|
||||
// return state.mergeIn(['filterOptions', action.key], fromJS(action.data).map(item => ({text: item, value: item})));
|
||||
optionsMap = state.getIn(['filterOptions', action.key]).map(i => i.value).toJS();
|
||||
return state.mergeIn(['filterOptions', action.key], Set(action.data.filter(i => !optionsMap.includes(i.value))));
|
||||
case SET_FILTER_OPTIONS:
|
||||
// optionsMap = state.getIn(['filterOptions', action.key]);
|
||||
// optionsMap = optionsMap ? optionsMap.map(i => i.value).toJS() : []
|
||||
// return state.mergeIn(['filterOptions', action.key], Set(action.filterOption.filter(i => !optionsMap.includes(i.value))));
|
||||
const tmp = {}
|
||||
let _state = state;
|
||||
action.filters.forEach(f => {
|
||||
if (f.type && f.value && f.value.length > 0) {
|
||||
tmp[f.type] = tmp[f.type] ? tmp[f.type].concat(f.value) : f.value
|
||||
}
|
||||
})
|
||||
Object.keys(tmp).forEach(f => {
|
||||
const options = List(tmp[f]).map(i => ({type: i, value: i})) // TODO should get the unique items
|
||||
_state = _state.mergeIn(['filterOptions', f], options);
|
||||
})
|
||||
|
||||
return _state;
|
||||
case FETCH_LIST.SUCCESS:
|
||||
return state;
|
||||
case SAVE.SUCCESS:
|
||||
return updateList(state, SavedFilter(action.data))
|
||||
.set('saveModalOpen', false);
|
||||
case REMOVE.SUCCESS:
|
||||
return state.update(
|
||||
'list',
|
||||
list => list
|
||||
.filter(filter => filter.filterId !== action.id),
|
||||
).set('activeFilter', null);
|
||||
case SET_ACTIVE:
|
||||
return state.set('activeFilter', action.filter);
|
||||
case SET_ACTIVE_FLOW:
|
||||
return state.set('activeFlow', action.flow);
|
||||
case SET_ACTIVE_KEY:
|
||||
return state.set('activeFilterKey', action.filterKey);
|
||||
case APPLY:
|
||||
return action.fromUrl
|
||||
? state.set('appliedFilter',
|
||||
Filter(action.filter)
|
||||
// .set('events', state.getIn([ 'appliedFilter', 'events' ]))
|
||||
)
|
||||
: state.mergeIn(['instance', 'filter'], action.filter);
|
||||
case ADD_CUSTOM_FILTER:
|
||||
return state.update('customFilters', vars => vars.set(action.filter, action.value));
|
||||
case REMOVE_CUSTOM_FILTER:
|
||||
return state.update('customFilters', vars => vars.remove(action.filterKey));
|
||||
case RESET_KEY:
|
||||
if (action.key === 'rangeValue') {
|
||||
return state
|
||||
.removeIn([ 'appliedFilter', 'rangeValue' ])
|
||||
.removeIn([ 'appliedFilter', 'startDate' ])
|
||||
.removeIn([ 'appliedFilter', 'endDate' ]);
|
||||
} else if (action.key === 'duration') {
|
||||
return state
|
||||
.removeIn([ 'appliedFilter', 'minDuration' ])
|
||||
.removeIn([ 'appliedFilter', 'maxDuration' ]);
|
||||
}
|
||||
return state.removeIn([ 'appliedFilter', action.key ]);
|
||||
case ADD_EVENT:
|
||||
const eventValue = action.event.value;
|
||||
const event = Event(action.event).set('value', eventValue);
|
||||
if (action.index >= 0) // replacing an event
|
||||
return state.setIn([ 'appliedFilter', 'events', action.index ], event)
|
||||
else
|
||||
return state.updateIn([ 'appliedFilter', 'events' ], list => action.single
|
||||
? List([ event ])
|
||||
: list.push(event));
|
||||
case REMOVE_EVENT:
|
||||
return state.removeIn([ 'appliedFilter', 'events', action.index ]);
|
||||
case EDIT_EVENT:
|
||||
return state.mergeIn([ 'appliedFilter', 'events', action.index], action.filter);
|
||||
case TOGGLE_FILTER_MODAL:
|
||||
return state.set('saveModalOpen', action.show);
|
||||
case MOVE_EVENT:
|
||||
const { fromI, toI } = action;
|
||||
return state
|
||||
.updateIn([ 'appliedFilter', 'events' ], list =>
|
||||
list.remove(fromI).insert(toI, list.get(fromI)));
|
||||
case CLEAR_EVENTS:
|
||||
return state.setIn([ 'appliedFilter', 'events' ], List())
|
||||
.setIn([ 'appliedFilter', 'filters' ], List())
|
||||
.set('searchQuery', '');
|
||||
|
||||
case ADD_ATTRIBUTE:
|
||||
const filter = CustomFilter(action.filter);
|
||||
|
||||
if (action.index >= 0) // replacing the filter
|
||||
return state.setIn([ 'appliedFilter', 'filters', action.index], filter);
|
||||
else
|
||||
return state.updateIn([ 'appliedFilter', 'filters'], filters => filters.push(filter));
|
||||
case EDIT_ATTRIBUTE:
|
||||
return state.setIn([ 'appliedFilter', 'filters', action.index, action.key ], action.value );
|
||||
case REMOVE_ATTRIBUTE:
|
||||
return state.removeIn([ 'appliedFilter', 'filters', action.index ]);
|
||||
case SET_SEARCH_QUERY:
|
||||
return state.set('searchQuery', action.query);
|
||||
case RESET:
|
||||
return state.set('appliedFilter', Filter({}))
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default withRequestState({
|
||||
_: [ REMOVE ],
|
||||
fetchListRequest: FETCH_LIST,
|
||||
saveRequest: SAVE,
|
||||
fetchFilterOptions: FETCH_FILTER_OPTIONS,
|
||||
}, reducer);
|
||||
|
||||
const eventMap = ({value, type, key, operator, source, custom}) => ({value, type, key, operator, source, custom});
|
||||
const filterMap = ({value, type, key, operator, source, custom }) => ({value: Array.isArray(value) ? value: [value], custom, type, key, operator, source});
|
||||
const reduceThenFetchResource = actionCreator => (...args) => (dispatch, getState) => {
|
||||
const action = actionCreator(...args);
|
||||
dispatch(action);
|
||||
const appliedFilters = getState().getIn([ 'funnelFilters', 'appliedFilter' ]);
|
||||
const filter = appliedFilters
|
||||
.update('events', list => list.map(event => event.set('value', event.value || '*')).map(eventMap))
|
||||
.toJS();
|
||||
|
||||
filter.filters = getState().getIn([ 'funnelFilters', 'appliedFilter', 'filters' ])
|
||||
.map(filterMap).toJS();
|
||||
|
||||
if (action.funnelId) {
|
||||
dispatch(fetchFunnel(action.funnelId))
|
||||
dispatch(fetchInsights(action.funnelId, filter))
|
||||
dispatch(fetchIssuesFiltered(action.funnelId, filter))
|
||||
dispatch(fetchSessionsFiltered(action.funnelId, filter))
|
||||
}
|
||||
}
|
||||
|
||||
export function editAttribute(index, key, value) {
|
||||
return {
|
||||
type: EDIT_ATTRIBUTE,
|
||||
index,
|
||||
key,
|
||||
value,
|
||||
};
|
||||
}
|
||||
|
||||
export function addAttribute(filter, index) {
|
||||
return {
|
||||
type: ADD_ATTRIBUTE,
|
||||
filter,
|
||||
index
|
||||
};
|
||||
}
|
||||
|
||||
export function removeAttribute(index) {
|
||||
return {
|
||||
type: REMOVE_ATTRIBUTE,
|
||||
index,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchList(range) {
|
||||
return {
|
||||
types: FETCH_LIST.toArray(),
|
||||
call: client => client.get(`/funnels`),
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchFilterOptions(filter, q) {
|
||||
return {
|
||||
types: FETCH_FILTER_OPTIONS.toArray(),
|
||||
call: client => client.get('/sessions/filters/search', { q, type: filter.type }),
|
||||
key: filter.key
|
||||
};
|
||||
}
|
||||
|
||||
export function setFilterOptions(filters) {
|
||||
return {
|
||||
type: SET_FILTER_OPTIONS,
|
||||
filters
|
||||
}
|
||||
}
|
||||
|
||||
export function save(instance) {
|
||||
return {
|
||||
types: SAVE.toArray(),
|
||||
call: client => client.post('/filters', instance.toData()),
|
||||
instance,
|
||||
};
|
||||
}
|
||||
|
||||
export function remove(id) {
|
||||
return {
|
||||
types: REMOVE.toArray(),
|
||||
call: client => client.delete(`/filters/${ id }`),
|
||||
id,
|
||||
};
|
||||
}
|
||||
|
||||
export function setActive(filter) {
|
||||
return {
|
||||
type: SET_ACTIVE,
|
||||
filter,
|
||||
};
|
||||
}
|
||||
|
||||
export function setActiveFlow(flow) {
|
||||
return {
|
||||
type: SET_ACTIVE_FLOW,
|
||||
flow,
|
||||
};
|
||||
}
|
||||
|
||||
export function setActiveKey(filterKey) {
|
||||
return {
|
||||
type: SET_ACTIVE_KEY,
|
||||
filterKey,
|
||||
};
|
||||
}
|
||||
|
||||
export const addCustomFilter = reduceThenFetchResource((filter, value) => ({
|
||||
type: ADD_CUSTOM_FILTER,
|
||||
filter,
|
||||
value,
|
||||
}));
|
||||
|
||||
export const removeCustomFilter = reduceThenFetchResource(filterKey => ({
|
||||
type: REMOVE_CUSTOM_FILTER,
|
||||
filterKey,
|
||||
}));
|
||||
|
||||
export const applyFilter = reduceThenFetchResource((filter, funnelId, fromUrl=false) => ({
|
||||
type: APPLY,
|
||||
filter,
|
||||
funnelId,
|
||||
fromUrl,
|
||||
}));
|
||||
|
||||
export const setInitialFilters = () => (dispatch, getState) => {
|
||||
return dispatch({
|
||||
type: APPLY,
|
||||
filter: getState().getIn(['funnels', 'instance', 'filter'])
|
||||
})
|
||||
}
|
||||
|
||||
export const applySavedFilter = reduceThenFetchResource((filter, fromUrl=false) => ({
|
||||
type: APPLY,
|
||||
filter,
|
||||
fromUrl,
|
||||
}));
|
||||
|
||||
export const resetFilterKey = reduceThenFetchResource(key => ({
|
||||
type: RESET_KEY,
|
||||
key,
|
||||
}));
|
||||
|
||||
export const clearEvents = reduceThenFetchResource(() => ({
|
||||
type: CLEAR_EVENTS,
|
||||
}));
|
||||
|
||||
export function addEvent(event, single = false, index) {
|
||||
return {
|
||||
type: ADD_EVENT,
|
||||
event,
|
||||
single,
|
||||
index
|
||||
};
|
||||
}
|
||||
|
||||
export const removeEvent = reduceThenFetchResource((index, funnelId) => ({
|
||||
type: REMOVE_EVENT,
|
||||
index,
|
||||
funnelId
|
||||
}));
|
||||
|
||||
export function moveEvent(fromI, toI) {
|
||||
return {
|
||||
type: MOVE_EVENT,
|
||||
fromI,
|
||||
toI,
|
||||
};
|
||||
}
|
||||
|
||||
export const editEvent = reduceThenFetchResource((index, filter, funnelId) => ({
|
||||
type: EDIT_EVENT,
|
||||
index,
|
||||
filter,
|
||||
funnelId
|
||||
}))
|
||||
|
||||
export function toggleFilterModal(show) {
|
||||
return {
|
||||
type: TOGGLE_FILTER_MODAL,
|
||||
show,
|
||||
};
|
||||
}
|
||||
|
||||
export function setSearchQuery(query) {
|
||||
return {
|
||||
type: SET_SEARCH_QUERY,
|
||||
query
|
||||
}
|
||||
}
|
||||
|
||||
export function resetFunnelFilters() {
|
||||
return {
|
||||
type: RESET
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,6 @@ import site from './site';
|
|||
import customFields from './customField';
|
||||
import integrations from './integrations';
|
||||
import errors from './errors';
|
||||
import customMetrics from './customMetrics';
|
||||
import search from './search';
|
||||
import liveSearch from './liveSearch';
|
||||
|
||||
|
|
@ -20,13 +19,12 @@ const rootReducer = combineReducers({
|
|||
site,
|
||||
customFields,
|
||||
errors,
|
||||
customMetrics,
|
||||
search,
|
||||
liveSearch,
|
||||
...integrations,
|
||||
...sources,
|
||||
...sources
|
||||
});
|
||||
|
||||
export type RootStore = ReturnType<typeof rootReducer>
|
||||
|
||||
export default rootReducer
|
||||
export default rootReducer;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue