diff --git a/frontend/app/components/BugFinder/BugFinder.js b/frontend/app/components/BugFinder/BugFinder.js
index 24952ac61..93ee7cd68 100644
--- a/frontend/app/components/BugFinder/BugFinder.js
+++ b/frontend/app/components/BugFinder/BugFinder.js
@@ -26,6 +26,7 @@ import TrackerUpdateMessage from 'Shared/TrackerUpdateMessage';
import LiveSessionList from './LiveSessionList'
import SessionSearch from 'Shared/SessionSearch';
import MainSearchBar from 'Shared/MainSearchBar';
+import LiveSearchBar from 'Shared/LiveSearchBar';
import { clearSearch } from 'Duck/search';
const weakEqual = (val1, val2) => {
@@ -168,15 +169,28 @@ export default class BugFinder extends React.PureComponent {
-
-
-
-
- { activeTab.type !== 'live' &&
}
- { activeTab.type === 'live' &&
}
+
+ {/* Recorde Sessions */}
+ { activeTab.type !== 'live' && (
+ <>
+
+
+
+
+ { activeTab.type !== 'live' &&
}
+ >
+ )}
+
+ {/* Live Sessions */}
+ { activeTab.type === 'live' && (
+ <>
+
+
+
+
+ { activeTab.type === 'live' &&
}
+ >
+ )}
setActiveSeries(value);
+ 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 filteredSessions = activeSeries === 'all' ? list.reduce((a, b) => a.concat(b.sessions), []) : list.filter(item => item.seriesId === activeSeries).reduce((a, b) => a.concat(b.sessions), []);
- const startTime = new DateTime(activeWidget.startTimestamp).toFormat('LLL dd, yyyy HH:mm a');
- const endTime = new DateTime(activeWidget.endTimestamp).toFormat('LLL dd, yyyy HH:mm a');
+ 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 (
Series */}
-
- { filteredSessions.map(session => ) }
-
+
+
+ { filteredSessions.map(session => ) }
+
+
)}
/>
@@ -94,7 +111,7 @@ function SessionListModal(props: Props) {
}
export default connect(state => ({
- loading: state.getIn(['customMetrics', 'sessionListRequest', 'loading']),
+ loading: state.getIn(['customMetrics', 'fetchSessionList', 'loading']),
list: state.getIn(['customMetrics', 'sessionList']),
// activeWidget: state.getIn(['customMetrics', 'activeWidget']),
}), { fetchSessionList, setActiveWidget })(SessionListModal);
diff --git a/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx b/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx
index bc7c6917d..ab5e76157 100644
--- a/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx
+++ b/frontend/app/components/shared/Filters/FilterModal/FilterModal.tsx
@@ -4,7 +4,6 @@ import { connect } from 'react-redux';
import cn from 'classnames';
import stl from './FilterModal.css';
import { filtersMap, getMetaDataFilter } from 'Types/filter/newFilter';
-// import { FilterKey, FilterType } from 'Types/filter/filterType';
interface Props {
filters: any,
@@ -25,7 +24,6 @@ function FilterModal(props: Props) {
fetchingFilterSearchList,
searchQuery = '',
} = props;
- // const hasFilerSearchList = filterSearchList && Object.keys(filterSearchList).length > 0;
const hasSearchQuery = searchQuery && searchQuery.length > 0;
const showSearchList = isMainSearch && searchQuery.length > 0;
diff --git a/frontend/app/components/shared/LiveSearchBar/LiveSearchBar.tsx b/frontend/app/components/shared/LiveSearchBar/LiveSearchBar.tsx
new file mode 100644
index 000000000..afe300c31
--- /dev/null
+++ b/frontend/app/components/shared/LiveSearchBar/LiveSearchBar.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import SessionSearchField from 'Shared/SessionSearchField';
+import SavedSearch from 'Shared/SavedSearch';
+import { Button, Popup } from 'UI';
+import { clearSearch } from 'Duck/search';
+import { connect } from 'react-redux';
+
+interface Props {
+ clearSearch: () => void;
+ appliedFilter: any;
+}
+const LiveSearchBar = (props: Props) => {
+ const { appliedFilter } = props;
+ const hasFilters = appliedFilter && appliedFilter.filters && appliedFilter.filters.size > 0;
+ return (
+
+
+
+
+
+
props.clearSearch()}
+ >
+ Clear
+
+ }
+ content={'Clear Steps'}
+ size="tiny"
+ inverted
+ position="top right"
+ />
+
+
+ )
+}
+export default connect(state => ({
+ appliedFilter: state.getIn(['search', 'instance']),
+}), { clearSearch })(LiveSearchBar);
\ No newline at end of file
diff --git a/frontend/app/components/shared/LiveSearchBar/index.ts b/frontend/app/components/shared/LiveSearchBar/index.ts
new file mode 100644
index 000000000..32cdf44ce
--- /dev/null
+++ b/frontend/app/components/shared/LiveSearchBar/index.ts
@@ -0,0 +1 @@
+export { default } from './LiveSearchBar';
\ No newline at end of file
diff --git a/frontend/app/components/shared/SessionSearchField/SessionSearchField.tsx b/frontend/app/components/shared/SessionSearchField/SessionSearchField.tsx
index b4b619f04..c8741ec9d 100644
--- a/frontend/app/components/shared/SessionSearchField/SessionSearchField.tsx
+++ b/frontend/app/components/shared/SessionSearchField/SessionSearchField.tsx
@@ -1,26 +1,18 @@
-import React, { useRef, useState } from 'react';
+import React, { useState } from 'react';
import { connect } from 'react-redux';
import stl from './SessionSearchField.css';
import { Input } from 'UI';
import FilterModal from 'Shared/Filters/FilterModal';
-// import { fetchList as fetchFilterSearch } from 'Duck/events';
import { fetchFilterSearch } from 'Duck/search';
import { debounce } from 'App/utils';
-import { edit as editFilter } from 'Duck/search';
-import {
- addEvent, applyFilter, moveEvent, clearEvents,
- addCustomFilter, addAttribute, setActiveFlow, setFilterOption
-} from 'Duck/filters';
+import { edit as editFilter, addFilterByKeyAndValue } from 'Duck/search';
interface Props {
- // setSearchQuery: (query: string) => void;
fetchFilterSearch: (query: any) => void;
- // searchQuery: string;
- appliedFilter: any;
editFilter: typeof editFilter;
+ addFilterByKeyAndValue: (key: string, value: string) => void;
}
function SessionSearchField(props: Props) {
- const { appliedFilter } = props;
const debounceFetchFilterSearch = debounce(props.fetchFilterSearch, 1000)
const [showModal, setShowModal] = useState(false)
const [searchQuery, setSearchQuery] = useState('')
@@ -31,12 +23,7 @@ function SessionSearchField(props: Props) {
}
const onAddFilter = (filter) => {
- filter.value = filter.value ? filter.value : [""]
- const newFilters = appliedFilter.filters.concat(filter);
- props.editFilter({
- ...appliedFilter.filter,
- filters: newFilters,
- });
+ props.addFilterByKeyAndValue(filter.key, filter.value)
}
return (
@@ -46,10 +33,7 @@ function SessionSearchField(props: Props) {
className={stl.searchField}
onFocus={ () => setShowModal(true) }
onBlur={ () => setTimeout(setShowModal, 200, false) }
- // ref={ this.inputRef }
onChange={ onSearchChange }
- // onKeyUp={this.onKeyUp}
- // value={props.searchQuery}
icon="search"
iconPosition="left"
placeholder={ 'Search sessions using any captured event (click, input, page, error...)'}
@@ -72,14 +56,4 @@ function SessionSearchField(props: Props) {
);
}
-export default connect(state => ({
- events: state.getIn([ 'filters', 'appliedFilter', 'events' ]),
- // searchQuery: state.getIn([ 'filters', 'searchQuery' ]),
- appliedFilterKeys: state.getIn([ 'filters', 'appliedFilter', 'filters' ])
- .map(({type}) => type).toJS(),
- searchedEvents: state.getIn([ 'events', 'list' ]),
- loading: state.getIn([ 'events', 'loading' ]),
- strict: state.getIn([ 'filters', 'appliedFilter', 'strict' ]),
- blink: state.getIn([ 'funnels', 'blink' ]),
- appliedFilter: state.getIn(['search', 'instance']),
-}), { fetchFilterSearch, editFilter })(SessionSearchField);
\ No newline at end of file
+export default connect(null, { fetchFilterSearch, editFilter, addFilterByKeyAndValue })(SessionSearchField);
\ No newline at end of file
diff --git a/frontend/app/components/ui/SegmentSelection/SegmentSelection.js b/frontend/app/components/ui/SegmentSelection/SegmentSelection.js
index 44219c1ec..a862394ee 100644
--- a/frontend/app/components/ui/SegmentSelection/SegmentSelection.js
+++ b/frontend/app/components/ui/SegmentSelection/SegmentSelection.js
@@ -20,9 +20,9 @@ class SegmentSelection extends React.Component {
>
{ list.map(item => (
!item.disabled && this.setActiveItem(item) }
diff --git a/frontend/app/types/dashboard/helper.js b/frontend/app/types/dashboard/helper.js
index b19b787e3..05e50d757 100644
--- a/frontend/app/types/dashboard/helper.js
+++ b/frontend/app/types/dashboard/helper.js
@@ -43,7 +43,7 @@ export const getChartFormatter = period => (data = []) =>
export const getStartAndEndTimestampsByDensity = (current, start, end, density) => {
const diff = end - start;
- const step = diff / density;
+ const step = Math.floor(diff / density);
const currentIndex = Math.floor((current - start) / step);
const startTimestamp = parseInt(start + currentIndex * step);
const endTimestamp = parseInt(startTimestamp + step);
diff --git a/frontend/app/types/session/issue.js b/frontend/app/types/session/issue.js
index 87878b6bb..31214ae3e 100644
--- a/frontend/app/types/session/issue.js
+++ b/frontend/app/types/session/issue.js
@@ -6,8 +6,8 @@ export const issues_types = List([
{ 'type': 'js_exception', 'visible': true, 'order': 0, 'name': 'Errors', 'icon': 'funnel/exclamation-circle' },
{ 'type': 'bad_request', 'visible': true, 'order': 1, 'name': 'Bad Requests', 'icon': 'funnel/file-medical-alt' },
{ 'type': 'missing_resource', 'visible': true, 'order': 2, 'name': 'Missing Images', 'icon': 'funnel/image' },
- { 'type': 'click_rage', 'visible': true, 'order': 3, 'name': 'Click Rage', 'icon': 'funnel/dizzy' },
- { 'type': 'dead_click', 'visible': true, 'order': 4, 'name': 'Dead Clicks', 'icon': 'funnel/emoji-angry' },
+ { 'type': 'click_rage', 'visible': true, 'order': 3, 'name': 'Click Rage', 'icon': 'funnel/emoji-angry' },
+ { 'type': 'dead_click', 'visible': true, 'order': 4, 'name': 'Dead Clicks', 'icon': 'funnel/dizzy' },
{ 'type': 'memory', 'visible': true, 'order': 5, 'name': 'High Memory', 'icon': 'funnel/sd-card' },
{ 'type': 'cpu', 'visible': true, 'order': 6, 'name': 'High CPU', 'icon': 'funnel/cpu' },
{ 'type': 'crash', 'visible': true, 'order': 7, 'name': 'Crashes', 'icon': 'funnel/file-earmark-break' },