feat(ui) - custom metrics fixes

This commit is contained in:
Shekar Siri 2022-02-08 14:40:41 +01:00
parent be0efc443c
commit ec2eff546a
14 changed files with 216 additions and 163 deletions

View file

@ -7,8 +7,7 @@ import { LineChart, Line, Legend } from 'recharts';
import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period';
import stl from './CustomMetricWidget.css';
import { getChartFormatter, getStartAndEndTimestampsByDensity } from 'Types/dashboard/helper';
import { edit, remove, setAlertMetricId, setActiveWidget, updateActiveState } from 'Duck/customMetrics';
import { confirm } from 'UI/Confirmation';
import { init, edit, remove, setAlertMetricId, setActiveWidget, updateActiveState } from 'Duck/customMetrics';
import APIClient from 'App/api_client';
import { setShowAlerts } from 'Duck/dashboard';
@ -35,6 +34,7 @@ interface Props {
setShowAlerts: (showAlerts) => void;
setAlertMetricId: (id) => void;
onAlertClick: (e) => void;
init: (metric) => void;
edit: (setDefault?) => void;
setActiveWidget: (widget) => void;
updateActiveState: (metricId, state) => void;
@ -74,16 +74,6 @@ function CustomMetricWidget(props: Props) {
}).finally(() => setLoading(false));
}, [period])
const deleteHandler = async () => {
if (await confirm({
header: 'Custom Metric',
confirmButton: 'Delete',
confirmation: `Are you sure you want to delete ${metric.name}`
})) {
props.remove(metric.metricId)
}
}
const clickHandler = (event, index) => {
const timestamp = event.activePayload[0].payload.timestamp;
const { startTimestamp, endTimestamp } = getStartAndEndTimestampsByDensity(timestamp, period.start, period.end, params.density);
@ -100,7 +90,7 @@ function CustomMetricWidget(props: Props) {
<div className="font-medium">{metric.name}</div>
<div className="ml-auto flex items-center">
<WidgetIcon className="cursor-pointer mr-6" icon="bell-plus" tooltip="Set Alert" onClick={props.onAlertClick} />
<WidgetIcon className="cursor-pointer mr-6" icon="pencil" tooltip="Edit Metric" onClick={() => props.edit(metric)} />
<WidgetIcon className="cursor-pointer mr-6" icon="pencil" tooltip="Edit Metric" onClick={() => props.init(metric)} />
<WidgetIcon className="cursor-pointer" icon="close" tooltip="Hide Metric" onClick={() => updateActiveState(metric.metricId, false)} />
</div>
</div>
@ -164,7 +154,15 @@ function CustomMetricWidget(props: Props) {
export default connect(state => ({
period: state.getIn(['dashboard', 'period']),
}), { remove, setShowAlerts, setAlertMetricId, edit, setActiveWidget, updateActiveState })(CustomMetricWidget);
}), {
remove,
setShowAlerts,
setAlertMetricId,
edit,
setActiveWidget,
updateActiveState,
init,
})(CustomMetricWidget);
const WidgetIcon = ({ className = '', tooltip = '', icon, onClick }) => (

View file

@ -4,7 +4,7 @@ import { Loader, NoContent, Icon } from 'UI';
import { widgetHOC, Styles } from '../../common';
import { ResponsiveContainer, AreaChart, XAxis, YAxis, CartesianGrid, Area, Tooltip } from 'recharts';
import { LineChart, Line, Legend } from 'recharts';
import { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period';
import Period, { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period';
import stl from './CustomMetricWidgetPreview.css';
import { getChartFormatter } from 'Types/dashboard/helper';
import { remove } from 'Duck/customMetrics';
@ -25,26 +25,23 @@ const customParams = rangeName => {
return params
}
interface Period {
rangeName: string;
}
interface Props {
metric: any;
// loading?: boolean;
data?: any;
showSync?: boolean;
compare?: boolean;
period?: Period;
// period?: any;
onClickEdit?: (e) => void;
remove: (id) => void;
edit: (metric) => void;
}
function CustomMetricWidget(props: Props) {
const { metric, showSync, compare, period = { rangeName: LAST_24_HOURS} } = props;
const { metric, showSync, compare } = props;
const [loading, setLoading] = useState(false)
const [data, setData] = useState<any>({ chart: [{}] })
const [seriesMap, setSeriesMap] = useState<any>([]);
const [period, setPeriod] = useState(Period({ rangeName: metric.rangeName, startDate: metric.startDate, endDate: metric.endDate }));
const colors = compare ? Styles.compareColors : Styles.colors;
const params = customParams(period.rangeName)
@ -70,13 +67,15 @@ function CustomMetricWidget(props: Props) {
}, []);
setSeriesMap(namesMap);
setData(getChartFormatter(period)(data));
}
}).finally(() => setLoading(false));
}, [metric])
const onDateChange = (changedDates) => {
props.edit({ ...changedDates });
setPeriod({ ...changedDates, rangeName: changedDates.rangeValue })
props.edit({ ...changedDates, rangeName: changedDates.rangeValue });
}
return (
@ -85,7 +84,7 @@ function CustomMetricWidget(props: Props) {
<div className="mr-auto font-medium">Preview</div>
<div>
<DateRange
rangeValue={metric.rangeValue}
rangeValue={metric.rangeName}
startDate={metric.startDate}
endDate={metric.endDate}
onDateChange={onDateChange}
@ -154,4 +153,6 @@ function CustomMetricWidget(props: Props) {
);
}
export default connect(null, { remove, edit })(CustomMetricWidget);
export default connect(state => ({
// period: state.getIn(['dashboard', 'period']),
}), { remove, edit })(CustomMetricWidget);

View file

@ -72,7 +72,7 @@ export default class FunnelSaveModal extends React.PureComponent {
/>
</Form.Field>
<Form.Field>
<Form.Field>
<div className="flex items-center">
<Checkbox
name="isPublic"
@ -86,7 +86,7 @@ export default class FunnelSaveModal extends React.PureComponent {
<Icon name="user-friends" size="16" />
<span className="ml-2"> Team Funnel</span>
</div>
</div>
</div>
</Form.Field>
</Form>
</Modal.Content>

View file

@ -2,7 +2,7 @@ import React from 'react';
import { Form, SegmentSelection, Button, IconButton } from 'UI';
import FilterSeries from '../FilterSeries';
import { connect } from 'react-redux';
import { edit as editMetric, save, addSeries, remove } from 'Duck/customMetrics';
import { edit as editMetric, save, addSeries, removeSeries, remove } from 'Duck/customMetrics';
import CustomMetricWidgetPreview from 'App/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview';
import { confirm } from 'UI/Confirmation';
import { toast } from 'react-toastify';
@ -16,6 +16,7 @@ interface Props {
addSeries: (series?) => void;
onClose: () => void;
remove: (id) => Promise<void>;
removeSeries: (seriesIndex) => void;
}
function CustomMetricForm(props: Props) {
@ -23,30 +24,10 @@ function CustomMetricForm(props: Props) {
const addSeries = () => {
props.addSeries();
const newSeries = {
name: `Series ${metric.series.size + 1}`,
type: '',
// series: [],
filter: {
type: '',
value: '',
filters: [],
},
};
props.editMetric({
...metric,
series: metric.series.concat(newSeries),
});
}
const removeSeries = (index) => {
const newSeries = metric.series.filter((_series, i) => {
return i !== index;
});
props.editMetric({
...metric,
series: newSeries,
});
props.removeSeries(index);
}
const write = ({ target: { value, name } }) => props.editMetric({ ...metric, [ name ]: value })
@ -159,4 +140,4 @@ function CustomMetricForm(props: Props) {
export default connect(state => ({
metric: state.getIn(['customMetrics', 'instance']),
loading: state.getIn(['customMetrics', 'saveRequest', 'loading']),
}), { editMetric, save, addSeries, remove })(CustomMetricForm);
}), { editMetric, save, addSeries, remove, removeSeries })(CustomMetricForm);

View file

@ -24,10 +24,10 @@ function CustomMetrics(props: Props) {
</div>
}
isDisplayed={ !!metric }
onClose={ () => props.init(null, false)}
onClose={ () => props.init(null, true)}
content={ (!!metric) && (
<div style={{ backgroundColor: '#f6f6f6' }}>
<CustomMetricForm metric={metric} onClose={() => props.init(null, false)} />
<CustomMetricForm metric={metric} onClose={() => props.init(null, true)} />
</div>
)}
/>

View file

@ -1,6 +1,13 @@
import React, { useState } from 'react';
import FilterList from 'Shared/Filters/FilterList';
import { edit, updateSeries } from 'Duck/customMetrics';
import {
edit,
updateSeries,
addSeriesFilterFilter,
removeSeriesFilterFilter,
editSeriesFilterFilter,
editSeriesFilter,
} from 'Duck/customMetrics';
import { connect } from 'react-redux';
import { IconButton, Icon } from 'UI';
import FilterSelection from '../../Filters/FilterSelection';
@ -14,6 +21,10 @@ interface Props {
updateSeries: typeof updateSeries;
onRemoveSeries: (seriesIndex) => void;
canDelete?: boolean;
addSeriesFilterFilter: typeof addSeriesFilterFilter;
editSeriesFilterFilter: typeof editSeriesFilterFilter;
editSeriesFilter: typeof editSeriesFilter;
removeSeriesFilterFilter: typeof removeSeriesFilterFilter;
}
function FilterSeries(props: Props) {
@ -23,56 +34,20 @@ function FilterSeries(props: Props) {
const onAddFilter = (filter) => {
filter.value = [""]
const newFilters = series.filter.filters.concat(filter);
props.updateSeries(seriesIndex, {
...series,
filter: {
...series.filter,
filters: newFilters,
}
});
props.addSeriesFilterFilter(seriesIndex, filter);
}
const onUpdateFilter = (filterIndex, filter) => {
const newFilters = series.filter.filters.map((_filter, i) => {
if (i === filterIndex) {
return filter;
} else {
return _filter;
}
});
props.updateSeries(seriesIndex, {
...series,
filter: {
...series.filter,
filters: newFilters,
}
});
props.editSeriesFilterFilter(seriesIndex, filterIndex, filter);
}
const onChangeEventsOrder = (e, { name, value }) => {
props.updateSeries(seriesIndex, {
...series,
filter: {
...series.filter,
eventsOrder: value,
}
});
props.editSeriesFilter(seriesIndex, { eventsOrder: value });
}
const onRemoveFilter = (filterIndex) => {
const newFilters = series.filter.filters.filter((_filter, i) => {
return i !== filterIndex;
});
props.updateSeries(seriesIndex, {
...series,
filter: {
...series.filter,
filters: newFilters,
}
});
props.removeSeriesFilterFilter(seriesIndex, filterIndex);
}
return (
@ -121,4 +96,11 @@ function FilterSeries(props: Props) {
);
}
export default connect(null, { edit, updateSeries })(FilterSeries);
export default connect(null, {
edit,
updateSeries,
addSeriesFilterFilter,
editSeriesFilterFilter,
editSeriesFilter,
removeSeriesFilterFilter,
})(FilterSeries);

View file

@ -14,16 +14,12 @@ function SaveFilterButton(props: Props) {
const [showModal, setshowModal] = useState(false)
return (
<div>
{ savedSearch ? (
{ savedSearch.exists() ? (
<IconButton className="mr-2" onClick={() => setshowModal(true)} primaryText label="UPDATE SEARCH" icon="zoom-in" />
) : (
<IconButton className="mr-2" onClick={() => setshowModal(true)} primaryText label="SAVE SEARCH" icon="zoom-in" />
)}
<SaveSearchModal
show={showModal}
closeHandler={() => setshowModal(false)}
/>
{ showModal && ( <SaveSearchModal show={showModal} closeHandler={() => setshowModal(false)} /> )}
</div>
);
}

View file

@ -1,6 +1,6 @@
import React, { useState } from 'react';
import { connect } from 'react-redux';
import { edit, save, remove } from 'Duck/search';
import { editSavedSearch as edit, save, remove } from 'Duck/search';
import { Button, Modal, Form, Icon, Checkbox } from 'UI';
import { confirm } from 'UI/Confirmation';
import stl from './SaveSearchModal.css';
@ -9,25 +9,25 @@ interface Props {
filter: any;
loading: boolean;
edit: (filter: any) => void;
save: (searchId, name, filter: any) => Promise<void>;
save: (searchId) => Promise<void>;
show: boolean;
closeHandler: () => void;
savedSearch: any;
remove: (filterId: number) => Promise<void>;
}
function SaveSearchModal(props: Props) {
const [name, setName] = useState(props.savedSearch ? props.savedSearch.name : '');
const { savedSearch, filter, loading, show, closeHandler } = props;
const [name, setName] = useState(savedSearch ? savedSearch.name : '');
const onNameChange = ({ target: { value } }) => {
// props.edit({ name: value });
setName(value);
props.edit({ name: value });
// setName(value);
};
const onSave = () => {
const { filter, closeHandler } = props;
if (name.trim() === '') return;
props.save(savedSearch ? savedSearch.searchId : null, name, filter).then(function() {
// if (name.trim() === '') return;
props.save(savedSearch.exists() ? savedSearch.searchId : null).then(function() {
// this.props.fetchFunnelsList();
closeHandler();
});
@ -37,13 +37,15 @@ function SaveSearchModal(props: Props) {
if (await confirm({
header: 'Confirm',
confirmButton: 'Yes, Delete',
confirmation: `Are you sure you want to permanently delete this alert?`
confirmation: `Are you sure you want to permanently delete this Saved serch?`,
})) {
props.remove(savedSearch.searchId).then(() => {
closeHandler();
});
}
}
const onChangeOption = (e, { checked, name }) => props.edit({ [ name ]: checked })
return (
@ -68,13 +70,29 @@ function SaveSearchModal(props: Props) {
autoFocus={ true }
// className={ stl.name }
name="name"
value={ name }
value={ savedSearch.name }
onChange={ onNameChange }
placeholder="Title"
/>
</Form.Field>
<Form.Field>
<div className="flex items-center">
<Checkbox
name="isPublic"
className="font-medium mr-3"
type="checkbox"
checked={ savedSearch.isPublic }
onClick={ onChangeOption }
/>
<div className="flex items-center cursor-pointer" onClick={ () => props.edit({ 'isPublic' : !savedSearch.isPublic }) }>
<Icon name="user-friends" size="16" />
<span className="ml-2"> Team Search</span>
</div>
</div>
</Form.Field>
</Form>
{ savedSearch && <div className="mt-2">Changes in filters will be updated.</div> }
{ savedSearch.exists() && <div className="mt-2">Changes in filters will be updated.</div> }
</Modal.Content>
<Modal.Actions className="flex items-center px-6">
<div className="mr-auto">
@ -82,8 +100,9 @@ function SaveSearchModal(props: Props) {
primary
onClick={ onSave }
loading={ loading }
disabled={!savedSearch.validate()}
>
{ savedSearch ? 'Update' : 'Create' }
{ savedSearch.exists() ? 'Update' : 'Create' }
</Button>
<Button className={ stl.cancelButton } marginRight onClick={ closeHandler }>{ 'Cancel' }</Button>
</div>

View file

@ -36,7 +36,7 @@ function SavedSearch(props) {
<span className="mr-2">{`Search Saved (${list.size})`}</span>
<Icon name="ellipsis-v" color="teal" size="14" />
</Button>
{ savedSearch && (
{ savedSearch.exists() && (
<div className="flex items-center ml-2">
<Icon name="search" size="14" />
<span className="color-gray-medium px-1">Viewing:</span>

View file

@ -13,6 +13,15 @@ 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`;
@ -51,21 +60,35 @@ const initialState = Map({
// Metric - Series - [] - filters
function reducer(state = initialState, action = {}) {
switch (action.type) {
case EDIT:
const instance = state.get('instance')
if (instance) {
return state.mergeIn([ 'instance' ], action.instance);
} else {
return state.set('instance', action.instance);
}
// 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:
console.log('update series', action.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);
// return state.mergeIn([ 'instance' ], action.data);
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):
@ -73,8 +96,6 @@ function reducer(state = initialState, action = {}) {
case success(FETCH_LIST):
const { data } = action;
return state.set("list", List(data.map(CustomMetric)));
// case success(UPDATE_ACTIVE_STATE):
// return updateItemInList(updateInstance(state, action.data), action.data);
case success(FETCH_SESSION_LIST):
return state.set("sessionList", List(action.data.map(item => ({ ...item, sessions: item.sessions.map(Session) }))));
case SET_ACTIVE_WIDGET:
@ -131,27 +152,36 @@ export function setAlertMetricId(id) {
};
}
export const addSeries = (series) => (dispatch, getState) => {
const instance = getState().getIn([ 'customMetrics', 'instance' ])
const _series = series || new FilterSeries({
name: 'New',
export const addSeries = (series = null) => (dispatch, getState) => {
const instance = getState().getIn([ 'customMetrics', 'instance' ]);
const seriesIndex = instance.series.size;
const newSeries = series || {
name: `Series ${seriesIndex + 1}`,
filter: new Filter({ filters: [], eventsOrder: 'and' }),
});
return dispatch({
type: EDIT,
instance: {
series: instance.series.push(_series)
},
};
dispatch({
type: ADD_SERIES,
series: newSeries,
});
}
export const init = (instnace = null, setDefault = true) => (dispatch, getState) => {
export const removeSeries = (index) => (dispatch, getState) => {
dispatch({
type: INIT,
instance: instnace ? instnace : (setDefault ? defaultInstance : null),
type: REMOVE_SERIES,
index,
});
}
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),
@ -160,7 +190,7 @@ export const fetchSessionList = (params) => (dispatch, getState) => {
}
export const setActiveWidget = (widget) => (dispatch, getState) => {
dispatch({
return dispatch({
type: SET_ACTIVE_WIDGET,
widget,
});
@ -174,4 +204,37 @@ export const updateActiveState = (metricId, state) => (dispatch, getState) => {
}).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,
});
}

View file

@ -19,6 +19,7 @@ const FETCH_FILTER_SEARCH = fetchListType(`${name}/FILTER_SEARCH`);
const FETCH = fetchType(name);
const SAVE = saveType(name);
const EDIT = editType(name);
const EDIT_SAVED_SEARCH = editType(`${name}/SAVED_SEARCH`);
const REMOVE = removeType(name);
const ADD_FILTER = `${name}/ADD_FILTER`;
const APPLY_SAVED_SEARCH = `${name}/APPLY_SAVED_SEARCH`;
@ -41,7 +42,7 @@ const initialState = Map({
list: List(),
alertMetricId: null,
instance: new Filter({ filters: [] }),
savedSearch: null,
savedSearch: new SavedFilter({}),
filterSearchList: {},
});
@ -76,6 +77,8 @@ function reducer(state = initialState, action = {}) {
return state.set('filterSearchList', groupedList);
case APPLY_SAVED_SEARCH:
return state.set('savedSearch', action.filter);
case EDIT_SAVED_SEARCH:
return state.mergeIn([ 'savedSearch' ], action.instance);
}
return state;
}
@ -150,16 +153,17 @@ export function fetch(id) {
}
}
export function save(id, name, instance) {
instance = instance instanceof SavedFilter ? instance : new SavedFilter(instance);
return {
export const save = (id) => (dispatch, getState) => {
// export function save(id) {
const filter = getState().getIn([ 'search', 'instance']).toData();
filter.filters = filter.filters.map(filterMap);
const instance = getState().getIn([ 'search', 'savedSearch']).toData();
// instance = instance instanceof SavedFilter ? instance : new SavedFilter(instance);
return dispatch({
types: SAVE.array,
call: client => client.post(!id ? '/saved_search' : `/saved_search/${id}`, {
name: name,
filter: instance.toSaveData(),
}),
instance,
};
call: client => client.post(!id ? '/saved_search' : `/saved_search/${id}`, { ...instance, filter })
});
}
export function fetchList() {
@ -185,7 +189,7 @@ export function fetchFilterSearch(params) {
}
export const clearSearch = () => (dispatch, getState) => {
dispatch(applySavedSearch(null));
dispatch(applySavedSearch(new SavedFilter({})));
dispatch(edit(new Filter({ filters: [] })));
return dispatch({
type: CLEAR_SEARCH,
@ -197,4 +201,11 @@ export const addFilter = (filter) => (dispatch, getState) => {
const instance = getState().getIn([ 'search', 'instance']);
const filters = instance.filters.push(filter);
return dispatch(edit(instance.set('filters', filters)));
}
}
export const editSavedSearch = instance => {
return {
type: EDIT_SAVED_SEARCH,
instance,
}
};

View file

@ -2,6 +2,8 @@ import Record from 'Types/Record';
import { List } from 'immutable';
import Filter from 'Types/filter';
import { validateName } from 'App/validate';
import Period, { LAST_24_HOURS, LAST_30_MINUTES, YESTERDAY, LAST_7_DAYS } from 'Types/app/period';
import { filterMap } from 'Duck/search';
export const FilterSeries = Record({
seriesId: undefined,
@ -31,6 +33,7 @@ export default Record({
startDate: '',
endDate: '',
active: true,
rangeName: LAST_7_DAYS,
}, {
idKey: 'metricId',
methods: {
@ -42,16 +45,9 @@ export default Record({
const js = this.toJS();
js.series = js.series.map(series => {
series.filter.filters = series.filter.filters.map(filter => {
filter.type = filter.key
delete filter.operatorOptions
delete filter.icon
delete filter.key
delete filter._key
return filter;
});
delete series._key
delete series.key
series.filter.filters = series.filter.filters.map(filterMap);
// delete series._key
// delete series.key
return series;
});

View file

@ -93,8 +93,9 @@ export default Record({
options: [],
}, {
keyKey: "_key",
fromJS: ({ value, type, ...filter }) => {
const _filter = filtersMap[type]
fromJS: ({ value, key, type, ...filter }) => {
// const _filter = filtersMap[key] || filtersMap[type] || {};
const _filter = filtersMap[type];
return {
...filter,
..._filter,

View file

@ -1,6 +1,7 @@
import Record from 'Types/Record';
import Filter from './filter';
import { List } from 'immutable';
import { notEmptyString, validateName } from 'App/validate';
export default Record({
searchId: undefined,
@ -10,10 +11,14 @@ export default Record({
filter: Filter(),
createdAt: undefined,
count: 0,
watchdogs: List()
watchdogs: List(),
isPublic: true,
}, {
idKey: 'searchId',
methods: {
validate() {
return notEmptyString(this.name);
},
toData() {
const js = this.toJS();
js.filter.filters = js.filter.filters.map(f => ({...f, value: Array.isArray(f.value) ? f.value : [f.value]}))