From e6d46c3ea1be90da8fd0b7838b428bad7f27bccf Mon Sep 17 00:00:00 2001 From: sylenien Date: Tue, 3 Jan 2023 12:57:09 +0100 Subject: [PATCH] change(ui): start session mobx store --- frontend/app/duck/sessions.ts | 3 +- frontend/app/mstore/sessionStore.ts | 119 ++++++++++++++++++++++- frontend/app/services/SessionService.ts | 27 ++++- frontend/app/types/session/errorStack.ts | 2 +- 4 files changed, 143 insertions(+), 8 deletions(-) diff --git a/frontend/app/duck/sessions.ts b/frontend/app/duck/sessions.ts index f434faccc..3fd035974 100644 --- a/frontend/app/duck/sessions.ts +++ b/frontend/app/duck/sessions.ts @@ -93,14 +93,13 @@ const reducer = (state = initialState, action: IAction) => { const { sessions, total } = action.data; const list = sessions.map(s => new Session(s)); - console.log(sessions, list, action) return state .set('list', list) .set('sessionIds', list.map(({ sessionId }) => sessionId)) .set('favoriteList', list.filter(({ favorite }) => favorite)) .set('total', total); case FETCH_AUTOPLAY_LIST.SUCCESS: - let sessionIds = state.get('sessionIds'); + let sessionIds = state.get('sessionIds') as []; sessionIds = sessionIds.concat(action.data.map(i => i.sessionId + '')) return state.set('sessionIds', sessionIds.filter((i, index) => sessionIds.indexOf(i) === index )) case SET_AUTOPLAY_VALUES: { diff --git a/frontend/app/mstore/sessionStore.ts b/frontend/app/mstore/sessionStore.ts index 553f742b2..ef8d1312e 100644 --- a/frontend/app/mstore/sessionStore.ts +++ b/frontend/app/mstore/sessionStore.ts @@ -1,8 +1,13 @@ import { makeAutoObservable, observable, action } from 'mobx'; import { sessionService } from 'App/services'; import { filterMap } from 'Duck/search'; -import Session from './types/session'; +import Session from 'Types/session'; import Record, { LAST_7_DAYS } from 'Types/app/period'; +import Watchdog from "Types/watchdog"; +import ErrorStack from 'Types/session/errorStack'; +import { Location, InjectedEvent } from 'Types/session/event' +import { getDateRangeFromValue } from "App/dateRange"; +import { getRE, setSessionFilter, getSessionFilter, compareJsonObjects, cleanSessionFilters } from 'App/utils'; class UserFilter { endDate: number = new Date().getTime(); @@ -76,10 +81,47 @@ class DevTools { } } +const range = getDateRangeFromValue(LAST_7_DAYS); +const defaultDateFilters = { + url: '', + rangeValue: LAST_7_DAYS, + startDate: range.start.unix() * 1000, + endDate: range.end.unix() * 1000, +}; + export default class SessionStore { userFilter: UserFilter = new UserFilter(); devTools: DevTools = new DevTools(); + list: Session[] = [] + sessionIds: string[] = [] + current = new Session() + total = 0 + keyMap = {} + wdTypeCount = {} + favoriteList: Session[] = [] + activeTab = Watchdog({ name: 'All', type: 'all' }) + timezone = 'local' + errorStack: ErrorStack[] = [] + eventsIndex = [] + sourcemapUploaded = true + filteredEvents: InjectedEvent[] | null = null + eventsQuery = '' + showChatWindow = false + liveSessions: Session[] = [] + visitedEvents = [] + insights = [] + insightFilters = defaultDateFilters + host = '' + funnelPage = {} + timelinePointer = null + sessionPath = {} + lastPlayedSessionId: string + timeLineTooltip = { time: 0, offset: 0, isVisible: false, timeStr: '' } + createNoteTooltip = { time: 0, isVisible: false, isEdit: false, note: null } + previousId = '' + nextId = '' + constructor() { makeAutoObservable(this, { userFilter: observable, @@ -106,4 +148,79 @@ export default class SessionStore { }); }); } + + async fetchLiveSessions(params = {}) { + try { + const data = await sessionService.getLiveSessions(params); + this.liveSessions = data.map(session => new Session({ ...session, live: true })); + } catch (e) { + console.error(e) + } + } + + async fetchSessions(params = {}, force = false) { + try { + if (!force) { + const oldFilters = getSessionFilter(); + if (compareJsonObjects(oldFilters, cleanSessionFilters(params))) { + return; + } + } + setSessionFilter(cleanSessionFilters(params)); + const data = await sessionService.getSessions(params); + const list = data.sessions.map(s => new Session(s)) + + this.list = list; + this.total = data.total; + this.sessionIds = data.sessions.map(s => s.sessionId); + this.favoriteList = list.filter(s => s.favorite); + } catch(e) { + console.error(e) + } + } + + async fetchErrorStack(sessionId: string, errorId: string) { + try { + const data = await sessionService.getErrorStack(sessionId, errorId); + this.errorStack = data.trace.map(es => new ErrorStack(es)) + } catch (e) { + console.error(e) + } + } + + async fetchAutoplayList(params = {}) { + try { + setSessionFilter(cleanSessionFilters(params)); + const data = await sessionService.getAutoplayList(params); + const list = [...this.sessionIds, ...data.map(s => s.sessionId)] + this.sessionIds = list.filter((id, ind) => list.indexOf(id) === ind); + } catch(e) { + console.error(e) + } + } + + setAutoplayValues() { + const currentId = this.current.sessionId + const currentIndex = this.sessionIds.indexOf(currentId) + + this.previousId = this.sessionIds[currentIndex - 1] + this.nextId = this.sessionIds[currentIndex + 1] + } + + setEventQuery(filter: { query: string }) { + const events = this.current.events + const query = filter.query; + const searchRe = getRE(query, 'i') + + const filteredEvents = query ? events.filter( + (e) => searchRe.test(e.url) + || searchRe.test(e.value) + || searchRe.test(e.label) + || searchRe.test(e.type) + || (e.type === 'LOCATION' && searchRe.test('visited')) + ) : null; + + this.filteredEvents = filteredEvents + this.eventsQuery = query + } } diff --git a/frontend/app/services/SessionService.ts b/frontend/app/services/SessionService.ts index 6f59b3805..60e2a1958 100644 --- a/frontend/app/services/SessionService.ts +++ b/frontend/app/services/SessionService.ts @@ -1,4 +1,7 @@ import APIClient from 'App/api_client'; +import { ISession } from 'Types/session/session'; +import { IErrorStack } from 'Types/session/errorStack'; +import { clean as cleanParams } from 'App/api_client'; export default class SettingsService { private client: APIClient; @@ -22,7 +25,7 @@ export default class SettingsService { .then((response) => response.data || 0); } - getSessions(filter: any) { + getSessions(filter: any): Promise<{ sessions: ISession[], total: number }> { return this.client .post('/sessions/search', filter) .then(r => r.json()) @@ -30,7 +33,7 @@ export default class SettingsService { .catch(e => Promise.reject(e)) } - getSessionInfo(sessionId: string, isLive?: boolean): Promise> { + getSessionInfo(sessionId: string, isLive?: boolean): Promise { return this.client .get(isLive ? `/assist/sessions/${sessionId}` : `/sessions/${sessionId}`) .then((r) => r.json()) @@ -38,11 +41,27 @@ export default class SettingsService { .catch(console.error); } - getLiveSessions(filter: any) { + getLiveSessions(filter: any): Promise<{ sessions: ISession[] }> { return this.client - .post('/assist/sessions', filter) + .post('/assist/sessions', cleanParams(filter)) .then(r => r.json()) .then((response) => response.data || []) .catch(e => Promise.reject(e)) } + + getErrorStack(sessionId: string, errorId: string): Promise<{ trace: IErrorStack[] }> { + return this.client + .get(`/sessions/${sessionId}/errors/${errorId}/sourcemaps`) + .then(r => r.json()) + .then(j => j.data || {}) + .catch(e => Promise.reject(e)) + } + + getAutoplayList(params = {}): Promise<{ sessionId: string}[]> { + return this.client + .post('/sessions/search/ids', cleanParams(params)) + .then(r => r.json()) + .then(j => j.data || []) + .catch(e => Promise.reject(e)) + } } diff --git a/frontend/app/types/session/errorStack.ts b/frontend/app/types/session/errorStack.ts index 59e63d16f..912c102c7 100644 --- a/frontend/app/types/session/errorStack.ts +++ b/frontend/app/types/session/errorStack.ts @@ -1,4 +1,4 @@ -interface IErrorStack { +export interface IErrorStack { absPath?: string, filename?: string, function?: string,