fix(ui) - search rename and save fixes

This commit is contained in:
Shekar Siri 2022-06-29 14:45:39 +02:00
parent f0ea5fd63d
commit a99ba301c6
4 changed files with 386 additions and 380 deletions

View file

@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React from 'react';
import { connect } from 'react-redux';
import { editSavedSearch as edit, save, remove } from 'Duck/search';
import { Button, Modal, Form, Icon, Checkbox, Input } from 'UI';
@ -8,128 +8,119 @@ import cn from 'classnames';
import { toast } from 'react-toastify';
interface Props {
filter: any;
loading: boolean;
edit: (filter: any) => void;
save: (searchId) => Promise<void>;
show: boolean;
closeHandler: () => void;
savedSearch: any;
remove: (filterId: number) => Promise<void>;
userId: number;
filter: any;
loading: boolean;
edit: (filter: any) => void;
save: (searchId: any, rename: boolean) => Promise<void>;
show: boolean;
closeHandler: () => void;
savedSearch: any;
remove: (filterId: number) => Promise<void>;
userId: number;
rename: boolean;
}
function SaveSearchModal(props: Props) {
const { savedSearch, filter, loading, show, closeHandler } = props;
const [name, setName] = useState(savedSearch ? savedSearch.name : '');
const { savedSearch, loading, show, closeHandler, rename = false } = props;
const onNameChange = ({ target: { value } }) => {
props.edit({ name: value });
// setName(value);
};
const onNameChange = ({ target: { value } }: any) => {
props.edit({ name: value });
};
const onSave = () => {
const { filter, closeHandler } = props;
// if (name.trim() === '') return;
props.save(savedSearch.exists() ? savedSearch.searchId : null)
.then(() => {
// this.props.fetchFunnelsList();
toast.success(`${savedSearch.exists() ? 'Updated' : 'Saved'} Successfully`);
closeHandler();
})
.catch(e => {
toast.error('Something went wrong, please try again');
});
}
const onSave = () => {
const { closeHandler } = props;
const onDelete = async () => {
if (await confirm({
header: 'Confirm',
confirmButton: 'Yes, delete',
confirmation: `Are you sure you want to permanently delete this Saved search?`,
})) {
props.remove(savedSearch.searchId).then(() => {
closeHandler();
});
}
}
props
.save(savedSearch.exists() ? savedSearch.searchId : null, rename)
.then(() => {
toast.success(`${savedSearch.exists() ? 'Updated' : 'Saved'} Successfully`);
closeHandler();
})
.catch((e) => {
toast.error('Something went wrong, please try again');
});
};
const onChangeOption = ({ target: { checked, name }}: any) => props.edit({ [ name ]: checked })
const onDelete = async () => {
if (
await confirm({
header: 'Confirm',
confirmButton: 'Yes, delete',
confirmation: `Are you sure you want to permanently delete this Saved search?`,
})
) {
props.remove(savedSearch.searchId).then(() => {
closeHandler();
});
}
};
const onChangeOption = ({ target: { checked, name } }: any) => props.edit({ [name]: checked });
return (
<Modal size="small" open={ show } onClose={closeHandler}>
<Modal.Header className={ stl.modalHeader }>
<div>{ 'Save Search' }</div>
<Icon
role="button"
tabIndex="-1"
color="gray-dark"
size="18"
name="close"
onClick={ closeHandler }
/>
</Modal.Header>
return (
<Modal size="small" open={show} onClose={closeHandler}>
<Modal.Header className={stl.modalHeader}>
<div>{'Save Search'}</div>
<Icon role="button" tabIndex="-1" color="gray-dark" size="18" name="close" onClick={closeHandler} />
</Modal.Header>
<Modal.Content>
<Form onSubmit={onSave}>
<Form.Field>
<label>{'Title:'}</label>
<Input
autoFocus={ true }
// className={ stl.name }
name="name"
value={ savedSearch.name }
onChange={ onNameChange }
placeholder="Title"
/>
</Form.Field>
<Modal.Content>
<Form onSubmit={onSave}>
<Form.Field>
<label>{'Title:'}</label>
<Input
autoFocus={true}
// className={ stl.name }
name="name"
value={savedSearch.name}
onChange={onNameChange}
placeholder="Title"
/>
</Form.Field>
<Form.Field>
<div className={cn("flex items-center", { 'disabled': savedSearch.exists() && savedSearch.userId !== props.userId })}>
<Checkbox
name="isPublic"
className="font-medium mr-3"
type="checkbox"
checked={ savedSearch.isPublic }
onClick={ onChangeOption }
/>
<div
className="flex items-center cursor-pointer select-none"
onClick={ () => props.edit({ 'isPublic' : !savedSearch.isPublic }) }
>
<Icon name="user-friends" size="16" />
<span className="ml-2"> Team Visible</span>
</div>
</div>
</Form.Field>
</Form>
{ savedSearch.exists() && <div className="mt-4">Changes in filters will be updated.</div> }
</Modal.Content>
<Modal.Footer className="flex items-center px-6">
<div className="mr-auto flex items-center">
<Button
variant="primary"
onClick={ onSave }
loading={ loading }
disabled={!savedSearch.validate()}
className="mr-2"
>
{ savedSearch.exists() ? 'Update' : 'Create' }
</Button>
<Button onClick={ closeHandler }>{ 'Cancel' }</Button>
</div>
{ savedSearch && <Button variant="text" onClick={ onDelete }>
<Icon name="trash" size="18" />
</Button> }
</Modal.Footer>
</Modal>
);
<Form.Field>
<div className={cn('flex items-center', { disabled: savedSearch.exists() && savedSearch.userId !== props.userId })}>
<Checkbox
name="isPublic"
className="font-medium mr-3"
type="checkbox"
checked={savedSearch.isPublic}
onClick={onChangeOption}
/>
<div
className="flex items-center cursor-pointer select-none"
onClick={() => props.edit({ isPublic: !savedSearch.isPublic })}
>
<Icon name="user-friends" size="16" />
<span className="ml-2"> Team Visible</span>
</div>
</div>
</Form.Field>
</Form>
{/* {savedSearch.exists() && <div className="mt-4">Changes in filters will be updated.</div>} */}
</Modal.Content>
<Modal.Footer className="flex items-center px-6">
<div className="mr-auto flex items-center">
<Button variant="primary" onClick={onSave} loading={loading} disabled={!savedSearch.validate()} className="mr-2">
{savedSearch.exists() ? 'Update' : 'Create'}
</Button>
<Button onClick={closeHandler}>{'Cancel'}</Button>
</div>
{savedSearch && (
<Button variant="text" onClick={onDelete}>
<Icon name="trash" size="18" />
</Button>
)}
</Modal.Footer>
</Modal>
);
}
export default connect(state => ({
userId: state.getIn([ 'user', 'account', 'id' ]),
savedSearch: state.getIn([ 'search', 'savedSearch' ]),
filter: state.getIn(['search', 'instance']),
loading: state.getIn([ 'search', 'saveRequest', 'loading' ]) ||
state.getIn([ 'search', 'updateRequest', 'loading' ]),
}), { edit, save, remove })(SaveSearchModal);
export default connect(
(state: any) => ({
userId: state.getIn(['user', 'account', 'id']),
savedSearch: state.getIn(['search', 'savedSearch']),
filter: state.getIn(['search', 'instance']),
loading: state.getIn(['search', 'saveRequest', 'loading']) || state.getIn(['search', 'updateRequest', 'loading']),
}),
{ edit, save, remove }
)(SaveSearchModal);

View file

@ -1,15 +1,14 @@
import React, { MouseEvent, useState } from 'react'
import React, { MouseEvent, useState } from 'react';
import cn from 'classnames';
import { Icon, Input } from 'UI';
import { List } from 'immutable';
import { confirm, Popup } from 'UI';
import { applySavedSearch, remove, editSavedSearch } from 'Duck/search'
import { applySavedSearch, remove, editSavedSearch } from 'Duck/search';
import { connect } from 'react-redux';
import { useModal } from 'App/components/Modal';
import { SavedSearch } from 'Types/ts/search'
import SaveSearchModal from 'Shared/SaveSearchModal'
import stl from './savedSearchModal.module.css'
import { SavedSearch } from 'Types/ts/search';
import SaveSearchModal from 'Shared/SaveSearchModal';
import stl from './savedSearchModal.module.css';
interface ITooltipIcon {
title: string;
@ -18,15 +17,12 @@ interface ITooltipIcon {
}
function TooltipIcon(props: ITooltipIcon) {
return (
<div onClick={(e) => props.onClick(e)} >
<Popup
content={props.title}
hideOnClick={true}
>
<div onClick={(e) => props.onClick(e)}>
<Popup content={props.title} hideOnClick={true}>
<Icon size="16" name={props.name} color="main" />
</Popup>
</div>
)
);
}
interface Props {
@ -37,51 +33,55 @@ interface Props {
}
function SavedSearchModal(props: Props) {
const { hideModal } = useModal();
const [showModal, setshowModal] = useState(false)
const [filterQuery, setFilterQuery] = useState('')
const [showModal, setshowModal] = useState(false);
const [filterQuery, setFilterQuery] = useState('');
const onClick = (item: SavedSearch, e) => {
e.stopPropagation();
props.applySavedSearch(item);
hideModal();
}
};
const onDelete = async (item: SavedSearch, e: MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
const confirmation = await confirm({
header: 'Confirm',
confirmButton: 'Yes, delete',
confirmation: 'Are you sure you want to permanently delete this search?'
})
confirmation: 'Are you sure you want to permanently delete this search?',
});
if (confirmation) {
props.remove(item.searchId)
props.remove(item.searchId);
}
}
};
const onEdit = (item: SavedSearch, e: MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
props.editSavedSearch(item);
setTimeout(() => setshowModal(true), 0);
}
};
const shownItems = props.list.filter(item => item.name.includes(filterQuery))
const shownItems = props.list.filter((item) => item.name.includes(filterQuery));
return (
<div className="bg-white box-shadow h-screen" style={{ width: '450px' }}>
<div className="p-6">
<h1 className="text-2xl">Saved Search <span className="color-gray-medium">{props.list.size}</span></h1>
<h1 className="text-2xl">
Saved Search <span className="color-gray-medium">{props.list.size}</span>
</h1>
</div>
{props.list.size > 1 && (
<div className="mb-6 w-full px-4">
<Input
// className="w-full"
// iconPosition="left"
icon="search"
onChange={({ target: { value }}: any) => setFilterQuery(value)}
onChange={({ target: { value } }: any) => setFilterQuery(value)}
placeholder="Filter by name"
/>
</div>
)}
{shownItems.map(item => (
<div key={item.key} className={cn("p-4 cursor-pointer border-b flex items-center group hover:bg-active-blue", item.isPublic && 'pb-10')} onClick={(e) => onClick(item, e)}>
{shownItems.map((item) => (
<div
key={item.key}
className={cn('p-4 cursor-pointer border-b flex items-center group hover:bg-active-blue', item.isPublic && 'pb-10')}
onClick={(e) => onClick(item, e)}
>
<Icon name="search" color="gray-medium" size="16" />
<div className="ml-4">
<div className="text-lg">{item.name} </div>
@ -102,9 +102,9 @@ function SavedSearchModal(props: Props) {
</div>
</div>
))}
{ showModal && ( <SaveSearchModal show closeHandler={() => setshowModal(false)} /> )}
{showModal && <SaveSearchModal show closeHandler={() => setshowModal(false)} rename={true} />}
</div>
)
);
}
export default connect(state => ({ list: state.getIn([ 'search', 'list' ]) }), { applySavedSearch, remove, editSavedSearch })(SavedSearchModal)
export default connect((state: any) => ({ list: state.getIn(['search', 'list']) }), { applySavedSearch, remove, editSavedSearch })(SavedSearchModal);

View file

@ -4,27 +4,38 @@ import { Icon } from 'UI';
interface Props {
wrapperClassName?: string;
className: string;
className?: string;
icon?: string;
leadingButton?: React.ReactNode;
type?: string;
rows?: number;
[x:string]: any;
[x: string]: any;
}
function Input(props: Props) {
const { className, leadingButton = "", wrapperClassName = "", icon = "", type="text", rows=4, ...rest } = props;
const { className = '', leadingButton = '', wrapperClassName = '', icon = '', type = 'text', rows = 4, ...rest } = props;
return (
<div className={cn({ "relative" : icon || leadingButton }, wrapperClassName)}>
<div className={cn({ relative: icon || leadingButton }, wrapperClassName)}>
{icon && <Icon name={icon} className="absolute top-0 bottom-0 my-auto ml-4" size="14" />}
{ type === 'textarea' ? (
<textarea rows={rows} style={{ resize: 'none' }} maxLength={500} className={ cn("p-2 border border-gray-light bg-white w-full rounded", className, { 'pl-10' : icon }) } {...rest} />
{type === 'textarea' ? (
<textarea
rows={rows}
style={{ resize: 'none' }}
maxLength={500}
className={cn('p-2 border border-gray-light bg-white w-full rounded', className, { 'pl-10': icon })}
{...rest}
/>
) : (
<input type={type} style={{ height: '36px'}} className={ cn("p-2 border border-gray-light bg-white w-full rounded", className, { 'pl-10' : icon }) } {...rest} />
<input
type={type}
style={{ height: '36px' }}
className={cn('p-2 border border-gray-light bg-white w-full rounded', className, { 'pl-10': icon })}
{...rest}
/>
)}
{ leadingButton && <div className="absolute top-0 bottom-0 right-0">{ leadingButton }</div> }
{leadingButton && <div className="absolute top-0 bottom-0 right-0">{leadingButton}</div>}
</div>
);
}
export default Input;
export default Input;

View file

@ -1,20 +1,20 @@
import { List, Map } from 'immutable';
import { fetchListType, fetchType, saveType, removeType, editType, createRemove } from './funcTools/crud';
import { List, Map } from 'immutable';
import { fetchListType, fetchType, saveType, removeType, editType } from './funcTools/crud';
import { createRequestReducer, ROOT_KEY } from './funcTools/request';
import { array, request, success, failure, createListUpdater, mergeReducers } from './funcTools/tools';
import { array, success, createListUpdater, mergeReducers } from './funcTools/tools';
import Filter from 'Types/filter';
import SavedFilter from 'Types/filter/savedFilter';
import { errors as errorsRoute, isRoute } from "App/routes";
import { errors as errorsRoute, isRoute } from 'App/routes';
import { fetchList as fetchSessionList } from './sessions';
import { fetchList as fetchErrorsList } from './errors';
import { FilterCategory, FilterKey, IssueType } from 'Types/filter/filterType';
import { filtersMap, liveFiltersMap, generateFilterOptions, generateLiveFilterOptions } from 'Types/filter/newFilter';
import { DURATION_FILTER } from 'App/constants/storageKeys'
import { FilterCategory, FilterKey } from 'Types/filter/filterType';
import { filtersMap, liveFiltersMap, generateFilterOptions } from 'Types/filter/newFilter';
import { DURATION_FILTER } from 'App/constants/storageKeys';
const ERRORS_ROUTE = errorsRoute();
const name = "search";
const idKey = "searchId";
const name = 'search';
const idKey = 'searchId';
const FETCH_LIST = fetchListType(name);
const FETCH_FILTER_SEARCH = fetchListType(`${name}/FILTER_SEARCH`);
@ -23,7 +23,6 @@ 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`;
const CLEAR_SEARCH = `${name}/CLEAR_SEARCH`;
const UPDATE = `${name}/UPDATE`;
@ -36,145 +35,145 @@ const SET_SCROLL_POSITION = `${name}/SET_SCROLL_POSITION`;
const REFRESH_FILTER_OPTIONS = 'filters/REFRESH_FILTER_OPTIONS';
function chartWrapper(chart = []) {
return chart.map(point => ({ ...point, count: Math.max(point.count, 0) }));
return chart.map((point) => ({ ...point, count: Math.max(point.count, 0) }));
}
const savedSearchIdKey = 'searchId'
const savedSearchIdKey = 'searchId';
const updateItemInList = createListUpdater(savedSearchIdKey);
const updateInstance = (state, instance) => state.getIn([ "savedSearch", savedSearchIdKey ]) === instance[savedSearchIdKey]
? state.mergeIn([ "savedSearch" ], SavedFilter(instance))
: state;
const updateInstance = (state, instance) =>
state.getIn(['savedSearch', savedSearchIdKey]) === instance[savedSearchIdKey] ? state.mergeIn(['savedSearch'], SavedFilter(instance)) : state;
const initialState = Map({
filterList: generateFilterOptions(filtersMap),
filterListLive: generateFilterOptions(liveFiltersMap),
list: List(),
alertMetricId: null,
instance: new Filter({ filters: [] }),
savedSearch: new SavedFilter({}),
filterSearchList: {},
currentPage: 1,
activeTab: {name: 'All', type: 'all' },
scrollY: 0,
filterList: generateFilterOptions(filtersMap),
filterListLive: generateFilterOptions(liveFiltersMap),
list: List(),
alertMetricId: null,
instance: new Filter({ filters: [] }),
savedSearch: new SavedFilter({}),
filterSearchList: {},
currentPage: 1,
activeTab: { name: 'All', type: 'all' },
scrollY: 0,
});
// Metric - Series - [] - filters
function reducer(state = initialState, action = {}) {
switch (action.type) {
case REFRESH_FILTER_OPTIONS:
return state.set('filterList', generateFilterOptions(filtersMap))
.set('filterListLive', generateFilterOptions(liveFiltersMap));
case EDIT:
return state.mergeIn(['instance'], action.instance).set('currentPage', 1);
case APPLY:
return action.fromUrl
? state.set('instance', Filter(action.filter))
: state.mergeIn(['instance'], action.filter).set('currentPage', 1);
case success(FETCH):
return state.set("instance", action.data);
case success(FETCH_LIST):
const { data } = action;
return state.set("list", List(data.map(SavedFilter)).sortBy(i => i.searchId));
case success(FETCH_FILTER_SEARCH):
const groupedList = action.data.reduce((acc, item) => {
const { projectId, type, value } = item;
const key = type;
if (!acc[key]) {
acc[key] = [];
}
acc[key].push({ projectId, value });
return acc;
}, {});
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);
case UPDATE_CURRENT_PAGE:
return state.set('currentPage', action.page);
case SET_ACTIVE_TAB:
return state.set('activeTab', action.tab).set('currentPage', 1);
case SET_SCROLL_POSITION:
return state.set('scrollY', action.scrollPosition);
}
return state;
switch (action.type) {
case REFRESH_FILTER_OPTIONS:
return state.set('filterList', generateFilterOptions(filtersMap)).set('filterListLive', generateFilterOptions(liveFiltersMap));
case EDIT:
return state.mergeIn(['instance'], action.instance).set('currentPage', 1);
case APPLY:
return action.fromUrl ? state.set('instance', Filter(action.filter)) : state.mergeIn(['instance'], action.filter).set('currentPage', 1);
case success(FETCH):
return state.set('instance', action.data);
case success(FETCH_LIST):
const { data } = action;
return state.set(
'list',
List(data.map(SavedFilter)).sortBy((i) => i.searchId)
);
case success(FETCH_FILTER_SEARCH):
const groupedList = action.data.reduce((acc, item) => {
const { projectId, type, value } = item;
const key = type;
if (!acc[key]) {
acc[key] = [];
}
acc[key].push({ projectId, value });
return acc;
}, {});
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);
case UPDATE_CURRENT_PAGE:
return state.set('currentPage', action.page);
case SET_ACTIVE_TAB:
return state.set('activeTab', action.tab).set('currentPage', 1);
case SET_SCROLL_POSITION:
return state.set('scrollY', action.scrollPosition);
}
return state;
}
export default mergeReducers(
reducer,
createRequestReducer({
[ ROOT_KEY ]: FETCH_LIST,
fetch: FETCH,
fetchFilterSearch: FETCH_FILTER_SEARCH
}),
reducer,
createRequestReducer({
[ROOT_KEY]: FETCH_LIST,
fetch: FETCH,
fetchFilterSearch: FETCH_FILTER_SEARCH,
})
);
const checkValues = (key, value) => {
if (key === FilterKey.DURATION) {
return value[0] === '' || value[0] === null ? [0, value[1]] : value;
}
return value.filter(i => i !== '' && i !== null);
}
if (key === FilterKey.DURATION) {
return value[0] === '' || value[0] === null ? [0, value[1]] : value;
}
return value.filter((i) => i !== '' && i !== null);
};
export const checkFilterValue = (value) => {
return Array.isArray(value) ? (value.length === 0 ? [""] : value) : [value];
}
return Array.isArray(value) ? (value.length === 0 ? [''] : value) : [value];
};
export const filterMap = ({category, value, key, operator, sourceOperator, source, custom, isEvent, filters, sort, order }) => ({
value: checkValues(key, value),
custom,
type: category === FilterCategory.METADATA ? FilterKey.METADATA : key,
operator,
source: category === FilterCategory.METADATA ? key : source,
sourceOperator,
isEvent,
filters: filters ? filters.map(filterMap) : [],
export const filterMap = ({ category, value, key, operator, sourceOperator, source, custom, isEvent, filters, sort, order }) => ({
value: checkValues(key, value),
custom,
type: category === FilterCategory.METADATA ? FilterKey.METADATA : key,
operator,
source: category === FilterCategory.METADATA ? key : source,
sourceOperator,
isEvent,
filters: filters ? filters.map(filterMap) : [],
});
export const reduceThenFetchResource = actionCreator => (...args) => (dispatch, getState) => {
dispatch(actionCreator(...args));
const filter = getState().getIn([ 'search', 'instance']).toData();
const activeTab = getState().getIn([ 'search', 'activeTab']);
if (activeTab.type !== 'all' && activeTab.type !== 'bookmark') {
const tmpFilter = filtersMap[FilterKey.ISSUE];
tmpFilter.value = [activeTab.type]
filter.filters = filter.filters.concat(tmpFilter)
}
export const reduceThenFetchResource =
(actionCreator) =>
(...args) =>
(dispatch, getState) => {
dispatch(actionCreator(...args));
const filter = getState().getIn(['search', 'instance']).toData();
if (activeTab.type === 'bookmark') {
filter.bookmarked = true
}
const activeTab = getState().getIn(['search', 'activeTab']);
if (activeTab.type !== 'all' && activeTab.type !== 'bookmark') {
const tmpFilter = filtersMap[FilterKey.ISSUE];
tmpFilter.value = [activeTab.type];
filter.filters = filter.filters.concat(tmpFilter);
}
filter.filters = filter.filters.map(filterMap);
filter.limit = 10;
filter.page = getState().getIn([ 'search', 'currentPage']);
if (activeTab.type === 'bookmark') {
filter.bookmarked = true;
}
// duration filter from local storage
if (!filter.filters.find(f => f.type === FilterKey.DURATION)) {
const durationFilter = JSON.parse(localStorage.getItem(DURATION_FILTER) || '{"count": 0}');
let durationValue = parseInt(durationFilter.count)
if (durationValue > 0) {
const value = [0];
durationValue = durationFilter.countType === 'min' ? durationValue * 60 * 1000 : durationValue * 1000;
if (durationFilter.operator === '<') {
value[0] = durationValue;
} else if (durationFilter.operator === '>') {
value[1] = durationValue;
}
filter.filters = filter.filters.concat({
type: FilterKey.DURATION,
operator: 'is',
value,
});
}
}
filter.filters = filter.filters.map(filterMap);
filter.limit = 10;
filter.page = getState().getIn(['search', 'currentPage']);
return isRoute(ERRORS_ROUTE, window.location.pathname)
? dispatch(fetchErrorsList(filter))
: dispatch(fetchSessionList(filter));
};
// duration filter from local storage
if (!filter.filters.find((f) => f.type === FilterKey.DURATION)) {
const durationFilter = JSON.parse(localStorage.getItem(DURATION_FILTER) || '{"count": 0}');
let durationValue = parseInt(durationFilter.count);
if (durationValue > 0) {
const value = [0];
durationValue = durationFilter.countType === 'min' ? durationValue * 60 * 1000 : durationValue * 1000;
if (durationFilter.operator === '<') {
value[0] = durationValue;
} else if (durationFilter.operator === '>') {
value[1] = durationValue;
}
filter.filters = filter.filters.concat({
type: FilterKey.DURATION,
operator: 'is',
value,
});
}
}
return isRoute(ERRORS_ROUTE, window.location.pathname) ? dispatch(fetchErrorsList(filter)) : dispatch(fetchSessionList(filter));
};
export const edit = reduceThenFetchResource((instance) => ({
type: EDIT,
@ -182,27 +181,27 @@ export const edit = reduceThenFetchResource((instance) => ({
}));
export const setActiveTab = reduceThenFetchResource((tab) => ({
type: SET_ACTIVE_TAB,
tab
type: SET_ACTIVE_TAB,
tab,
}));
export const remove = (id) => (dispatch, getState) => {
return dispatch({
types: REMOVE.array,
call: client => client.delete(`/saved_search/${id}`),
id,
}).then(() => {
dispatch(applySavedSearch(new SavedFilter({})));
dispatch(fetchList());
});
return dispatch({
types: REMOVE.array,
call: (client) => client.delete(`/saved_search/${id}`),
id,
}).then(() => {
dispatch(applySavedSearch(new SavedFilter({})));
dispatch(fetchList());
});
};
// export const remove = createRemove(name, (id) => `/saved_search/${id}`);
export const applyFilter = reduceThenFetchResource((filter, fromUrl=false) => ({
type: APPLY,
filter,
fromUrl,
export const applyFilter = reduceThenFetchResource((filter, fromUrl = false) => ({
type: APPLY,
filter,
fromUrl,
}));
export const updateCurrentPage = reduceThenFetchResource((page) => ({
@ -211,126 +210,131 @@ export const updateCurrentPage = reduceThenFetchResource((page) => ({
}));
export const applySavedSearch = (filter) => (dispatch, getState) => {
dispatch(edit({ filters: filter ? filter.filter.filters : [] }));
return dispatch({
type: APPLY_SAVED_SEARCH,
filter,
})
dispatch(edit({ filters: filter ? filter.filter.filters : [] }));
return dispatch({
type: APPLY_SAVED_SEARCH,
filter,
});
};
export const fetchSessions = (filter) => (dispatch, getState) => {
const _filter = filter ? filter : getState().getIn([ 'search', 'instance']);
return dispatch(applyFilter(_filter));
const _filter = filter ? filter : getState().getIn(['search', 'instance']);
return dispatch(applyFilter(_filter));
};
export const updateSeries = (index, series) => ({
type: UPDATE,
index,
series,
type: UPDATE,
index,
series,
});
export function fetch(id) {
return {
id,
types: array(FETCH),
call: c => c.get(`/errors/${id}`),
}
return {
id,
types: array(FETCH),
call: (c) => c.get(`/errors/${id}`),
};
}
export const save = (id) => (dispatch, getState) => {
const filter = getState().getIn([ 'search', 'instance']).toData();
filter.filters = filter.filters.map(filterMap);
const isNew = !id;
export const save = (id, rename = false) => (dispatch, getState) => {
const filter = getState().getIn(['search', 'instance']).toData();
// filter.filters = filter.filters.map(filterMap);
const isNew = !id;
const instance = getState().getIn([ 'search', 'savedSearch']).toData();
return dispatch({
types: SAVE.array,
call: client => client.post(isNew ? '/saved_search' : `/saved_search/${id}`, { ...instance, filter })
}).then(() => {
dispatch(fetchList()).then(() => {
if (isNew) {
const lastSavedSearch = getState().getIn([ 'search', 'list']).last();
dispatch(applySavedSearch(lastSavedSearch));
}
const instance = getState().getIn(['search', 'savedSearch']).toData();
const newInstance = rename ? instance : { ...instance, filter };
newInstance.filter.filters = newInstance.filter.filters.map(filterMap);
return dispatch({
types: SAVE.array,
call: (client) => client.post(isNew ? '/saved_search' : `/saved_search/${id}`, newInstance),
}).then(() => {
dispatch(fetchList()).then(() => {
if (isNew) {
const lastSavedSearch = getState().getIn(['search', 'list']).last();
dispatch(applySavedSearch(lastSavedSearch));
}
});
});
});
}
};
export function fetchList() {
return {
types: array(FETCH_LIST),
call: client => client.get(`/saved_search`),
};
return {
types: array(FETCH_LIST),
call: (client) => client.get(`/saved_search`),
};
}
export function setAlertMetricId(id) {
return {
type: SET_ALERT_METRIC_ID,
id,
};
return {
type: SET_ALERT_METRIC_ID,
id,
};
}
export function fetchFilterSearch(params) {
return {
types: FETCH_FILTER_SEARCH.array,
call: client => client.get('/events/search', params),
params,
};
return {
types: FETCH_FILTER_SEARCH.array,
call: (client) => client.get('/events/search', params),
params,
};
}
export const clearSearch = () => (dispatch, getState) => {
dispatch(applySavedSearch(new SavedFilter({})));
dispatch(edit(new Filter({ filters: [] })));
return dispatch({
type: CLEAR_SEARCH,
});
}
dispatch(applySavedSearch(new SavedFilter({})));
dispatch(edit(new Filter({ filters: [] })));
return dispatch({
type: CLEAR_SEARCH,
});
};
export const hasFilterApplied = (filters, filter) => {
return !filter.isEvent && filters.some(f => f.key === filter.key);
}
return !filter.isEvent && filters.some((f) => f.key === filter.key);
};
export const addFilter = (filter) => (dispatch, getState) => {
filter.value = checkFilterValue(filter.value);
filter.filters = filter.filters ? filter.filters.map(subFilter => ({
...subFilter,
value: checkFilterValue(subFilter.value),
})) : null;
const instance = getState().getIn([ 'search', 'instance']);
filter.value = checkFilterValue(filter.value);
filter.filters = filter.filters
? filter.filters.map((subFilter) => ({
...subFilter,
value: checkFilterValue(subFilter.value),
}))
: null;
const instance = getState().getIn(['search', 'instance']);
if (hasFilterApplied(instance.filters, filter)) {
} else {
const filters = instance.filters.push(filter);
return dispatch(edit(instance.set('filters', filters)));
}
}
if (hasFilterApplied(instance.filters, filter)) {
} else {
const filters = instance.filters.push(filter);
return dispatch(edit(instance.set('filters', filters)));
}
};
export const addFilterByKeyAndValue = (key, value, operator = undefined) => (dispatch, getState) => {
let defaultFilter = filtersMap[key];
defaultFilter.value = value;
if (operator) {
defaultFilter.operator = operator;
}
dispatch(addFilter(defaultFilter));
}
export const addFilterByKeyAndValue =
(key, value, operator = undefined) =>
(dispatch, getState) => {
let defaultFilter = filtersMap[key];
defaultFilter.value = value;
if (operator) {
defaultFilter.operator = operator;
}
dispatch(addFilter(defaultFilter));
};
export const editSavedSearch = instance => {
return {
type: EDIT_SAVED_SEARCH,
instance,
}
export const editSavedSearch = (instance) => {
return {
type: EDIT_SAVED_SEARCH,
instance,
};
};
export const refreshFilterOptions = () => {
return {
type: REFRESH_FILTER_OPTIONS
}
}
return {
type: REFRESH_FILTER_OPTIONS,
};
};
export const setScrollPosition = (scrollPosition) => {
return {
type: SET_SCROLL_POSITION,
scrollPosition,
}
}
return {
type: SET_SCROLL_POSITION,
scrollPosition,
};
};