diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx index 7efac8418..448adf563 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx @@ -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) {
{metric.name}
- props.edit(metric)} /> + props.init(metric)} /> updateActiveState(metric.metricId, false)} />
@@ -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 }) => ( diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx index 74633b1cd..39e428732 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidgetPreview/CustomMetricWidgetPreview.tsx @@ -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({ chart: [{}] }) const [seriesMap, setSeriesMap] = useState([]); + 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) {
Preview
({ + // period: state.getIn(['dashboard', 'period']), +}), { remove, edit })(CustomMetricWidget); \ No newline at end of file diff --git a/frontend/app/components/Funnels/FunnelSaveModal/FunnelSaveModal.js b/frontend/app/components/Funnels/FunnelSaveModal/FunnelSaveModal.js index 53fec2048..3cfccb3ff 100644 --- a/frontend/app/components/Funnels/FunnelSaveModal/FunnelSaveModal.js +++ b/frontend/app/components/Funnels/FunnelSaveModal/FunnelSaveModal.js @@ -72,7 +72,7 @@ export default class FunnelSaveModal extends React.PureComponent { /> - +
Team Funnel
-
+ diff --git a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx index 2a029ad3f..c25786cb8 100644 --- a/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx +++ b/frontend/app/components/shared/CustomMetrics/CustomMetricForm/CustomMetricForm.tsx @@ -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; + 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); \ No newline at end of file +}), { editMetric, save, addSeries, remove, removeSeries })(CustomMetricForm); \ No newline at end of file diff --git a/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx b/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx index ccf3a1133..9393099e6 100644 --- a/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx +++ b/frontend/app/components/shared/CustomMetrics/CustomMetrics.tsx @@ -24,10 +24,10 @@ function CustomMetrics(props: Props) { } isDisplayed={ !!metric } - onClose={ () => props.init(null, false)} + onClose={ () => props.init(null, true)} content={ (!!metric) && (
- props.init(null, false)} /> + props.init(null, true)} />
)} /> diff --git a/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx b/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx index 5ef8d6006..dd1ef1a31 100644 --- a/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx +++ b/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx @@ -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); \ No newline at end of file +export default connect(null, { + edit, + updateSeries, + addSeriesFilterFilter, + editSeriesFilterFilter, + editSeriesFilter, + removeSeriesFilterFilter, +})(FilterSeries); \ No newline at end of file diff --git a/frontend/app/components/shared/SaveFilterButton/SaveFilterButton.tsx b/frontend/app/components/shared/SaveFilterButton/SaveFilterButton.tsx index 625b05047..51bed6e8c 100644 --- a/frontend/app/components/shared/SaveFilterButton/SaveFilterButton.tsx +++ b/frontend/app/components/shared/SaveFilterButton/SaveFilterButton.tsx @@ -14,16 +14,12 @@ function SaveFilterButton(props: Props) { const [showModal, setshowModal] = useState(false) return (
- { savedSearch ? ( + { savedSearch.exists() ? ( setshowModal(true)} primaryText label="UPDATE SEARCH" icon="zoom-in" /> ) : ( setshowModal(true)} primaryText label="SAVE SEARCH" icon="zoom-in" /> )} - - setshowModal(false)} - /> + { showModal && ( setshowModal(false)} /> )}
); } diff --git a/frontend/app/components/shared/SaveSearchModal/SaveSearchModal.tsx b/frontend/app/components/shared/SaveSearchModal/SaveSearchModal.tsx index 9545426c1..61f0ee71a 100644 --- a/frontend/app/components/shared/SaveSearchModal/SaveSearchModal.tsx +++ b/frontend/app/components/shared/SaveSearchModal/SaveSearchModal.tsx @@ -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; + save: (searchId) => Promise; show: boolean; closeHandler: () => void; savedSearch: any; remove: (filterId: number) => Promise; } 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" /> + + +
+ +
props.edit({ 'isPublic' : !savedSearch.isPublic }) }> + + Team Search +
+
+
- { savedSearch &&
Changes in filters will be updated.
} + { savedSearch.exists() &&
Changes in filters will be updated.
}
@@ -82,8 +100,9 @@ function SaveSearchModal(props: Props) { primary onClick={ onSave } loading={ loading } + disabled={!savedSearch.validate()} > - { savedSearch ? 'Update' : 'Create' } + { savedSearch.exists() ? 'Update' : 'Create' }
diff --git a/frontend/app/components/shared/SavedSearch/SavedSearch.tsx b/frontend/app/components/shared/SavedSearch/SavedSearch.tsx index cc156474c..2317fba65 100644 --- a/frontend/app/components/shared/SavedSearch/SavedSearch.tsx +++ b/frontend/app/components/shared/SavedSearch/SavedSearch.tsx @@ -36,7 +36,7 @@ function SavedSearch(props) { {`Search Saved (${list.size})`} - { savedSearch && ( + { savedSearch.exists() && (
Viewing: diff --git a/frontend/app/duck/customMetrics.js b/frontend/app/duck/customMetrics.js index e486e75b0..8d7b49deb 100644 --- a/frontend/app/duck/customMetrics.js +++ b/frontend/app/duck/customMetrics.js @@ -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, + }); } \ No newline at end of file diff --git a/frontend/app/duck/search.js b/frontend/app/duck/search.js index 027a03b88..e8472d868 100644 --- a/frontend/app/duck/search.js +++ b/frontend/app/duck/search.js @@ -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))); -} \ No newline at end of file +} + +export const editSavedSearch = instance => { + return { + type: EDIT_SAVED_SEARCH, + instance, + } +}; \ No newline at end of file diff --git a/frontend/app/types/customMetric.js b/frontend/app/types/customMetric.js index f80c045fd..0218b8f93 100644 --- a/frontend/app/types/customMetric.js +++ b/frontend/app/types/customMetric.js @@ -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; }); diff --git a/frontend/app/types/filter/newFilter.js b/frontend/app/types/filter/newFilter.js index 74b739918..91ebb92a7 100644 --- a/frontend/app/types/filter/newFilter.js +++ b/frontend/app/types/filter/newFilter.js @@ -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, diff --git a/frontend/app/types/filter/savedFilter.js b/frontend/app/types/filter/savedFilter.js index 83518f20d..3d9947fc6 100644 --- a/frontend/app/types/filter/savedFilter.js +++ b/frontend/app/types/filter/savedFilter.js @@ -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]}))