Add searched events (#3361)
* add filtered events to search * removed consoles * changed styles to tailwind * changed styles to tailwind * fixed errors
This commit is contained in:
parent
5e0e5730ba
commit
9ed3cb1b7e
10 changed files with 156 additions and 45 deletions
|
|
@ -16,12 +16,14 @@ import { IFRAME } from 'App/constants/storageKeys';
|
||||||
import stl from './playerBlockHeader.module.css';
|
import stl from './playerBlockHeader.module.css';
|
||||||
import UserCard from './EventsBlock/UserCard';
|
import UserCard from './EventsBlock/UserCard';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { Switch } from 'antd';
|
||||||
|
|
||||||
const SESSIONS_ROUTE = sessionsRoute();
|
const SESSIONS_ROUTE = sessionsRoute();
|
||||||
|
|
||||||
function PlayerBlockHeader(props: any) {
|
function PlayerBlockHeader(props: any) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [hideBack, setHideBack] = React.useState(false);
|
const [hideBack, setHideBack] = React.useState(false);
|
||||||
|
const { uiPlayerStore } = useStore();
|
||||||
const { player, store } = React.useContext(PlayerContext);
|
const { player, store } = React.useContext(PlayerContext);
|
||||||
const { uxtestingStore, customFieldStore, projectsStore, sessionStore } =
|
const { uxtestingStore, customFieldStore, projectsStore, sessionStore } =
|
||||||
useStore();
|
useStore();
|
||||||
|
|
@ -123,9 +125,25 @@ function PlayerBlockHeader(props: any) {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{uiPlayerStore.showSearchEventsSwitchButton ? (
|
||||||
|
<div className="px-2 relative flex items-center border-r border-r-gray-lighter">
|
||||||
|
<Switch
|
||||||
|
checked={uiPlayerStore.showOnlySearchEvents}
|
||||||
|
onChange={uiPlayerStore.setShowOnlySearchEvents}
|
||||||
|
style={{
|
||||||
|
background: uiPlayerStore.showOnlySearchEvents
|
||||||
|
? '#f0a930'
|
||||||
|
: 'rgba(0, 0, 0, 0.25)',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span className="ml-2 whitespace-nowrap">
|
||||||
|
{t('Search Events Only')}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="px-2 relative border-l border-l-gray-lighter"
|
className="px-2 relative"
|
||||||
style={{ minWidth: activeTab === 'EXPORT' ? '360px' : '270px' }}
|
style={{ minWidth: activeTab === 'EXPORT' ? '360px' : '270px' }}
|
||||||
>
|
>
|
||||||
<Tabs
|
<Tabs
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,10 @@ const UXTTABS = {
|
||||||
|
|
||||||
let playerInst: IPlayerContext['player'] | undefined;
|
let playerInst: IPlayerContext['player'] | undefined;
|
||||||
|
|
||||||
|
const isDefaultEventsFilterSearch = (filters: FilterItem[]) => {
|
||||||
|
return filters.length === 1 && filters[0].key === 'location' && filters[0].value[0] === '';
|
||||||
|
}
|
||||||
|
|
||||||
function WebPlayer(props: any) {
|
function WebPlayer(props: any) {
|
||||||
const {
|
const {
|
||||||
notesStore,
|
notesStore,
|
||||||
|
|
@ -38,6 +42,7 @@ function WebPlayer(props: any) {
|
||||||
uxtestingStore,
|
uxtestingStore,
|
||||||
uiPlayerStore,
|
uiPlayerStore,
|
||||||
integrationsStore,
|
integrationsStore,
|
||||||
|
searchStore,
|
||||||
} = useStore();
|
} = useStore();
|
||||||
const devTools = sessionStore.devTools
|
const devTools = sessionStore.devTools
|
||||||
const session = sessionStore.current;
|
const session = sessionStore.current;
|
||||||
|
|
@ -57,6 +62,17 @@ function WebPlayer(props: any) {
|
||||||
const [fullView, setFullView] = useState(false);
|
const [fullView, setFullView] = useState(false);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
if (searchStore.instance.filters?.length && !isDefaultEventsFilterSearch(searchStore.instance.filters)) {
|
||||||
|
uiPlayerStore.setSearchEventsSwitchButton(true);
|
||||||
|
uiPlayerStore.setShowOnlySearchEvents(true);
|
||||||
|
} else {
|
||||||
|
uiPlayerStore.setSearchEventsSwitchButton(false);
|
||||||
|
uiPlayerStore.setShowOnlySearchEvents(false);
|
||||||
|
}
|
||||||
|
}, [searchStore.instance.filters]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
openedAt.current = Date.now();
|
||||||
const handleActivation = () => {
|
const handleActivation = () => {
|
||||||
if (!document.hidden) {
|
if (!document.hidden) {
|
||||||
setWindowActive(true);
|
setWindowActive(true);
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ function EventGroupWrapper(props) {
|
||||||
isLastInGroup,
|
isLastInGroup,
|
||||||
isSelected,
|
isSelected,
|
||||||
isCurrent,
|
isCurrent,
|
||||||
|
isSearched,
|
||||||
isEditing,
|
isEditing,
|
||||||
showSelection,
|
showSelection,
|
||||||
isFirst,
|
isFirst,
|
||||||
|
|
@ -99,7 +100,7 @@ function EventGroupWrapper(props) {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const shadowColor = props.isPrev
|
const shadowColor = isSearched ? '#F0A930' : props.isPrev
|
||||||
? '#A7BFFF'
|
? '#A7BFFF'
|
||||||
: props.isCurrent
|
: props.isCurrent
|
||||||
? '#394EFF'
|
? '#394EFF'
|
||||||
|
|
@ -127,7 +128,7 @@ function EventGroupWrapper(props) {
|
||||||
width: 10,
|
width: 10,
|
||||||
height: 10,
|
height: 10,
|
||||||
transform: 'rotate(45deg) translate(0, -50%)',
|
transform: 'rotate(45deg) translate(0, -50%)',
|
||||||
background: '#394EFF',
|
background: isSearched ? '#F0A930' : '#394EFF',
|
||||||
zIndex: 99,
|
zIndex: 99,
|
||||||
borderRadius: '.15rem',
|
borderRadius: '.15rem',
|
||||||
}}
|
}}
|
||||||
|
|
@ -169,6 +170,6 @@ function TabChange({ from, to, activeUrl, onClick }) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default observer(EventGroupWrapper);
|
export default observer(EventGroupWrapper);
|
||||||
|
|
@ -2,13 +2,13 @@ import { mergeEventLists, sortEvents } from 'Types/session';
|
||||||
import { TYPES } from 'Types/session/event';
|
import { TYPES } from 'Types/session/event';
|
||||||
import cn from 'classnames';
|
import cn from 'classnames';
|
||||||
import { observer } from 'mobx-react-lite';
|
import { observer } from 'mobx-react-lite';
|
||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { VList, VListHandle } from 'virtua';
|
import { VList, VListHandle } from 'virtua';
|
||||||
import { Button } from 'antd'
|
import { Button } from 'antd';
|
||||||
import { PlayerContext } from 'App/components/Session/playerContext';
|
import { PlayerContext } from 'App/components/Session/playerContext';
|
||||||
import { useStore } from 'App/mstore';
|
import { useStore } from 'App/mstore';
|
||||||
import { Icon } from 'UI';
|
import { Icon } from 'UI';
|
||||||
import { Search } from 'lucide-react'
|
import { Search } from 'lucide-react';
|
||||||
import EventGroupWrapper from './EventGroupWrapper';
|
import EventGroupWrapper from './EventGroupWrapper';
|
||||||
import EventSearch from './EventSearch/EventSearch';
|
import EventSearch from './EventSearch/EventSearch';
|
||||||
import styles from './eventsBlock.module.css';
|
import styles from './eventsBlock.module.css';
|
||||||
|
|
@ -25,7 +25,7 @@ const MODES = {
|
||||||
SELECT: 'select',
|
SELECT: 'select',
|
||||||
SEARCH: 'search',
|
SEARCH: 'search',
|
||||||
EXPORT: 'export',
|
EXPORT: 'export',
|
||||||
}
|
};
|
||||||
|
|
||||||
function EventsBlock(props: IProps) {
|
function EventsBlock(props: IProps) {
|
||||||
const defaultFramework = getDefaultFramework();
|
const defaultFramework = getDefaultFramework();
|
||||||
|
|
@ -47,6 +47,7 @@ function EventsBlock(props: IProps) {
|
||||||
const zoomStartTs = uiPlayerStore.timelineZoom.startTs;
|
const zoomStartTs = uiPlayerStore.timelineZoom.startTs;
|
||||||
const zoomEndTs = uiPlayerStore.timelineZoom.endTs;
|
const zoomEndTs = uiPlayerStore.timelineZoom.endTs;
|
||||||
const { store, player } = React.useContext(PlayerContext);
|
const { store, player } = React.useContext(PlayerContext);
|
||||||
|
const [currentTimeEventIndex, setCurrentTimeEventIndex] = React.useState(0);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
time,
|
time,
|
||||||
|
|
@ -94,8 +95,8 @@ function EventsBlock(props: IProps) {
|
||||||
? 'time' in e
|
? 'time' in e
|
||||||
? e.time >= zoomStartTs && e.time <= zoomEndTs
|
? e.time >= zoomStartTs && e.time <= zoomEndTs
|
||||||
: false
|
: false
|
||||||
: true,
|
: true
|
||||||
);
|
).filter((e: any) => !e.noteId && e.type !== 'TABCHANGE' && uiPlayerStore.showOnlySearchEvents ? e.isHighlighted : true);
|
||||||
}, [
|
}, [
|
||||||
filteredLength,
|
filteredLength,
|
||||||
notesWithEvtsLength,
|
notesWithEvtsLength,
|
||||||
|
|
@ -103,6 +104,7 @@ function EventsBlock(props: IProps) {
|
||||||
zoomEnabled,
|
zoomEnabled,
|
||||||
zoomStartTs,
|
zoomStartTs,
|
||||||
zoomEndTs,
|
zoomEndTs,
|
||||||
|
uiPlayerStore.showOnlySearchEvents
|
||||||
]);
|
]);
|
||||||
const findLastFitting = React.useCallback(
|
const findLastFitting = React.useCallback(
|
||||||
(time: number) => {
|
(time: number) => {
|
||||||
|
|
@ -126,7 +128,10 @@ function EventsBlock(props: IProps) {
|
||||||
},
|
},
|
||||||
[usedEvents, time, endTime],
|
[usedEvents, time, endTime],
|
||||||
);
|
);
|
||||||
const currentTimeEventIndex = findLastFitting(time);
|
|
||||||
|
useEffect(() => {
|
||||||
|
setCurrentTimeEventIndex(findLastFitting(time));
|
||||||
|
}, [])
|
||||||
|
|
||||||
const write = ({
|
const write = ({
|
||||||
target: { value },
|
target: { value },
|
||||||
|
|
@ -182,6 +187,8 @@ function EventsBlock(props: IProps) {
|
||||||
const isTabChange = 'type' in event && event.type === 'TABCHANGE';
|
const isTabChange = 'type' in event && event.type === 'TABCHANGE';
|
||||||
const isCurrent = index === currentTimeEventIndex;
|
const isCurrent = index === currentTimeEventIndex;
|
||||||
const isPrev = index < currentTimeEventIndex;
|
const isPrev = index < currentTimeEventIndex;
|
||||||
|
const isSearched = event.isHighlighted
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EventGroupWrapper
|
<EventGroupWrapper
|
||||||
query={query}
|
query={query}
|
||||||
|
|
@ -192,6 +199,7 @@ function EventsBlock(props: IProps) {
|
||||||
isLastEvent={isLastEvent}
|
isLastEvent={isLastEvent}
|
||||||
isLastInGroup={isLastInGroup}
|
isLastInGroup={isLastInGroup}
|
||||||
isCurrent={isCurrent}
|
isCurrent={isCurrent}
|
||||||
|
isSearched={isSearched}
|
||||||
showSelection={!playing}
|
showSelection={!playing}
|
||||||
isNote={isNote}
|
isNote={isNote}
|
||||||
isTabChange={isTabChange}
|
isTabChange={isTabChange}
|
||||||
|
|
@ -249,12 +257,14 @@ function EventsBlock(props: IProps) {
|
||||||
onClick={() => setMode(MODES.SEARCH)}
|
onClick={() => setMode(MODES.SEARCH)}
|
||||||
>
|
>
|
||||||
<Search size={14} />
|
<Search size={14} />
|
||||||
<div>{t('Search')} {usedEvents.length} {t('events')}</div>
|
<div>
|
||||||
|
{t('Search')} {usedEvents.length} {t('events')}
|
||||||
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
<Tooltip title={t('Close Panel')} placement='bottom' >
|
<Tooltip title={t('Close Panel')} placement="bottom">
|
||||||
<Button
|
<Button
|
||||||
className="ml-auto"
|
className="ml-auto"
|
||||||
type='text'
|
type="text"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setActiveTab('');
|
setActiveTab('');
|
||||||
}}
|
}}
|
||||||
|
|
@ -263,19 +273,23 @@ function EventsBlock(props: IProps) {
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{mode === MODES.SEARCH ?
|
{mode === MODES.SEARCH ? (
|
||||||
<div className={'flex items-center gap-2'}>
|
<div className={'flex items-center gap-2'}>
|
||||||
<EventSearch
|
<EventSearch
|
||||||
onChange={write}
|
onChange={write}
|
||||||
setActiveTab={setActiveTab}
|
setActiveTab={setActiveTab}
|
||||||
value={query}
|
value={query}
|
||||||
eventsText={
|
eventsText={
|
||||||
usedEvents.length ? `${usedEvents.length} ${t('Events')}` : `0 ${t('Events')}`
|
usedEvents.length
|
||||||
|
? `${usedEvents.length} ${t('Events')}`
|
||||||
|
: `0 ${t('Events')}`
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Button type={'text'} onClick={() => setMode(MODES.SELECT)}>{t('Cancel')}</Button>
|
<Button type={'text'} onClick={() => setMode(MODES.SELECT)}>
|
||||||
|
{t('Cancel')}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
: null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={cn('flex-1 pb-4', styles.eventsList)}
|
className={cn('flex-1 pb-4', styles.eventsList)}
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,26 @@ import {
|
||||||
MobilePlayerContext,
|
MobilePlayerContext,
|
||||||
} from 'Components/Session/playerContext';
|
} from 'Components/Session/playerContext';
|
||||||
import { observer } from 'mobx-react-lite';
|
import { observer } from 'mobx-react-lite';
|
||||||
import stl from './timeline.module.css';
|
|
||||||
import { getTimelinePosition } from './getTimelinePosition';
|
import { getTimelinePosition } from './getTimelinePosition';
|
||||||
|
import { useStore } from '@/mstore';
|
||||||
|
|
||||||
function EventsList() {
|
function EventsList() {
|
||||||
const { store } = useContext(PlayerContext);
|
const { store } = useContext(PlayerContext);
|
||||||
|
const { uiPlayerStore } = useStore();
|
||||||
|
|
||||||
const { eventCount, endTime } = store.get();
|
const { eventCount, endTime } = store.get();
|
||||||
const { tabStates } = store.get();
|
const { tabStates } = store.get();
|
||||||
const scale = 100 / endTime;
|
const scale = 100 / endTime;
|
||||||
const events = React.useMemo(
|
const events = React.useMemo(
|
||||||
() => Object.values(tabStates)[0]?.eventList.filter((e) => e.time) || [],
|
() => Object.values(tabStates)[0]?.eventList.filter((e) => {
|
||||||
[eventCount],
|
if (uiPlayerStore.showOnlySearchEvents) {
|
||||||
|
return e.time && (e as any).isHighlighted
|
||||||
|
} else {
|
||||||
|
return e.time
|
||||||
|
}
|
||||||
|
}) || [],
|
||||||
|
[eventCount, uiPlayerStore.showOnlySearchEvents],
|
||||||
);
|
);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const hasDuplicates = events.some(
|
const hasDuplicates = events.some(
|
||||||
(e, i) =>
|
(e, i) =>
|
||||||
|
|
@ -33,7 +39,7 @@ function EventsList() {
|
||||||
<div
|
<div
|
||||||
/* @ts-ignore TODO */
|
/* @ts-ignore TODO */
|
||||||
key={`${e.key}_${e.time}`}
|
key={`${e.key}_${e.time}`}
|
||||||
className={stl.event}
|
className={`absolute w-[2px] h-[10px] z-[3] pointer-events-none ${e.isHighlighted ? 'bg-[#f0a930]' : 'bg-[#394eff]'}`}
|
||||||
style={{ left: `${getTimelinePosition(e.time, scale)}%` }}
|
style={{ left: `${getTimelinePosition(e.time, scale)}%` }}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
@ -53,7 +59,7 @@ function MobileEventsList() {
|
||||||
<div
|
<div
|
||||||
/* @ts-ignore TODO */
|
/* @ts-ignore TODO */
|
||||||
key={`${e.key}_${e.time}`}
|
key={`${e.key}_${e.time}`}
|
||||||
className={stl.event}
|
className={`absolute w-[2px] h-[10px] z-[3] pointer-events-none ${e.isHighlighted ? 'bg-[#f0a930]' : 'bg-[#394eff]'}`}
|
||||||
style={{ left: `${getTimelinePosition(e.time, scale)}%` }}
|
style={{ left: `${getTimelinePosition(e.time, scale)}%` }}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
import FilterItem from '@/mstore/types/filterItem';
|
||||||
|
|
||||||
|
export const checkEventWithFilters = (event: Event, filters: FilterItem[]) => {
|
||||||
|
let result = false;
|
||||||
|
filters.forEach((filter) => {
|
||||||
|
if (filter.key.toUpperCase() === event.type.toUpperCase()) {
|
||||||
|
if (filter.operator) {
|
||||||
|
const operator = operators[filter.operator];
|
||||||
|
if (operator) {
|
||||||
|
result = !!operator(event.label, filter.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result
|
||||||
|
};
|
||||||
|
|
||||||
|
const operators = {
|
||||||
|
is: (val: string, target: string[]) => target.some((t) => val.includes(t)),
|
||||||
|
isAny: () => true,
|
||||||
|
isNot: (val: string, target: string[]) =>
|
||||||
|
!target.some((t) => val.includes(t)),
|
||||||
|
contains: (val: string, target: string[]) =>
|
||||||
|
target.some((t) => val.includes(t)),
|
||||||
|
notContains: (val: string, target: string[]) =>
|
||||||
|
!target.some((t) => val.includes(t)),
|
||||||
|
startsWith: (val: string, target: string[]) =>
|
||||||
|
target.some((t) => val.startsWith(t)),
|
||||||
|
endsWith: (val: string, target: string[]) =>
|
||||||
|
target.some((t) => val.endsWith(t)),
|
||||||
|
greaterThan: (val: number, target: number) => val > target,
|
||||||
|
greaterOrEqual: (val: number, target: number) => val >= target,
|
||||||
|
lessOrEqual: (val: number, target: number) => val <= target,
|
||||||
|
lessThan: (val: number, target: number) => val < target,
|
||||||
|
on: (val: string, target: string[]) => target.some((t) => val.includes(t)),
|
||||||
|
notOn: (val: string, target: string[]) =>
|
||||||
|
!target.some((t) => val.includes(t)),
|
||||||
|
onAny: () => true,
|
||||||
|
selectorIs: (val: string, target: string[]) => target.some((t) => val.includes(t)),
|
||||||
|
selectorIsAny: () => true,
|
||||||
|
selectorIsNot: (val: string, target: string[]) =>
|
||||||
|
!target.some((t) => val.includes(t)),
|
||||||
|
selectorContains: (val: string, target: string[]) =>
|
||||||
|
target.some((t) => val.includes(t)),
|
||||||
|
selectorNotContains: (val: string, target: string[]) =>
|
||||||
|
!target.some((t) => val.includes(t)),
|
||||||
|
selectorStartsWith: (val: string, target: string[]) =>
|
||||||
|
target.some((t) => val.startsWith(t)),
|
||||||
|
selectorEndsWith: (val: string, target: string[]) =>
|
||||||
|
target.some((t) => val.endsWith(t)),
|
||||||
|
};
|
||||||
|
|
@ -49,24 +49,6 @@
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.event {
|
|
||||||
position: absolute;
|
|
||||||
width: 2px;
|
|
||||||
height: 10px;
|
|
||||||
background: $main;
|
|
||||||
z-index: 3;
|
|
||||||
pointer-events: none;
|
|
||||||
/* top: 0; */
|
|
||||||
/* bottom: 0; */
|
|
||||||
/* &:hover {
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
margin-left: -6px;
|
|
||||||
z-index: 1;
|
|
||||||
};*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/* .event.click, .event.input {
|
/* .event.click, .event.input {
|
||||||
background: $green;
|
background: $green;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,8 @@ import { loadFile } from 'App/player/web/network/loadFiles';
|
||||||
import { LAST_7_DAYS } from 'Types/app/period';
|
import { LAST_7_DAYS } from 'Types/app/period';
|
||||||
import { filterMap } from 'App/mstore/searchStore';
|
import { filterMap } from 'App/mstore/searchStore';
|
||||||
import { getDateRangeFromValue } from 'App/dateRange';
|
import { getDateRangeFromValue } from 'App/dateRange';
|
||||||
import { clean as cleanParams } from '../api_client';
|
|
||||||
import { searchStore, searchStoreLive } from './index';
|
import { searchStore, searchStoreLive } from './index';
|
||||||
|
import { checkEventWithFilters } from '@/components/Session_/Player/Controls/checkEventWithFilters';
|
||||||
const range = getDateRangeFromValue(LAST_7_DAYS);
|
const range = getDateRangeFromValue(LAST_7_DAYS);
|
||||||
|
|
||||||
const defaultDateFilters = {
|
const defaultDateFilters = {
|
||||||
|
|
@ -342,7 +341,14 @@ export default class SessionStore {
|
||||||
const eventsData: Record<string, any[]> = {};
|
const eventsData: Record<string, any[]> = {};
|
||||||
try {
|
try {
|
||||||
const evData = await sessionService.getSessionEvents(sessionId);
|
const evData = await sessionService.getSessionEvents(sessionId);
|
||||||
Object.assign(eventsData, evData);
|
|
||||||
|
Object.assign(eventsData, {
|
||||||
|
...evData,
|
||||||
|
events: evData.events.map((e) => ({
|
||||||
|
...e,
|
||||||
|
isHighlighted: checkEventWithFilters(e, searchStore.instance.filters)
|
||||||
|
}))
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to fetch events', e);
|
console.error('Failed to fetch events', e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,8 @@ export const blockValues = [
|
||||||
|
|
||||||
export default class UiPlayerStore {
|
export default class UiPlayerStore {
|
||||||
fullscreen = false;
|
fullscreen = false;
|
||||||
|
showOnlySearchEvents = false;
|
||||||
|
showSearchEventsSwitchButton = false;
|
||||||
|
|
||||||
bottomBlock = 0;
|
bottomBlock = 0;
|
||||||
|
|
||||||
|
|
@ -145,4 +147,12 @@ export default class UiPlayerStore {
|
||||||
setZoomTab = (tab: 'overview' | 'journey' | 'issues' | 'errors') => {
|
setZoomTab = (tab: 'overview' | 'journey' | 'issues' | 'errors') => {
|
||||||
this.zoomTab = tab;
|
this.zoomTab = tab;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
setShowOnlySearchEvents = (show: boolean) => {
|
||||||
|
this.showOnlySearchEvents = show;
|
||||||
|
};
|
||||||
|
|
||||||
|
setSearchEventsSwitchButton = (show: boolean) => {
|
||||||
|
this.showSearchEventsSwitchButton = show;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ interface IEvent {
|
||||||
path: string;
|
path: string;
|
||||||
label: string;
|
label: string;
|
||||||
};
|
};
|
||||||
|
isHighlighted?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConsoleEvent extends IEvent {
|
interface ConsoleEvent extends IEvent {
|
||||||
|
|
@ -118,6 +119,8 @@ class Event {
|
||||||
|
|
||||||
messageId: IEvent['messageId'];
|
messageId: IEvent['messageId'];
|
||||||
|
|
||||||
|
isHighlighted: IEvent['isHighlighted'];
|
||||||
|
|
||||||
constructor(event: IEvent) {
|
constructor(event: IEvent) {
|
||||||
Object.assign(this, {
|
Object.assign(this, {
|
||||||
time: event.time,
|
time: event.time,
|
||||||
|
|
@ -125,6 +128,7 @@ class Event {
|
||||||
key: event.key,
|
key: event.key,
|
||||||
tabId: event.tabId,
|
tabId: event.tabId,
|
||||||
messageId: event.messageId,
|
messageId: event.messageId,
|
||||||
|
isHighlighted: event.isHighlighted,
|
||||||
target: {
|
target: {
|
||||||
path: event.target?.path || event.targetPath,
|
path: event.target?.path || event.targetPath,
|
||||||
label: event.target?.label,
|
label: event.target?.label,
|
||||||
|
|
@ -178,12 +182,15 @@ export class Click extends Event {
|
||||||
|
|
||||||
selector: string;
|
selector: string;
|
||||||
|
|
||||||
|
isHighlighted: boolean | undefined = false;
|
||||||
|
|
||||||
constructor(evt: ClickEvent, isClickRage?: boolean) {
|
constructor(evt: ClickEvent, isClickRage?: boolean) {
|
||||||
super(evt);
|
super(evt);
|
||||||
this.targetContent = evt.targetContent;
|
this.targetContent = evt.targetContent;
|
||||||
this.count = evt.count;
|
this.count = evt.count;
|
||||||
this.hesitation = evt.hesitation;
|
this.hesitation = evt.hesitation;
|
||||||
this.selector = evt.selector;
|
this.selector = evt.selector;
|
||||||
|
this.isHighlighted = evt.isHighlighted;
|
||||||
if (isClickRage) {
|
if (isClickRage) {
|
||||||
this.type = CLICKRAGE;
|
this.type = CLICKRAGE;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue