From c0785ec6fab423b7f1988f2819250100aed6da73 Mon Sep 17 00:00:00 2001 From: sylenien Date: Mon, 2 Jan 2023 13:04:21 +0100 Subject: [PATCH] change(ui): rewrite session type and fix reducer --- .../LastPerformance/LastPerformance.js | 28 ------ .../Widgets/LastPerformance/index.js | 1 - .../app/components/Session/PlayerContent.js | 1 - frontend/app/components/Session/WebPlayer.tsx | 1 - frontend/app/duck/assignments.js | 2 +- frontend/app/duck/issues.js | 2 +- .../app/duck/{sessions.js => sessions.ts} | 91 ++++++++----------- frontend/app/types/session/activity.js | 53 ----------- frontend/app/types/session/activity.ts | 49 ++++++++++ frontend/app/types/session/assignment.js | 2 +- frontend/app/types/session/customField.js | 5 - frontend/app/types/session/errorStack.js | 13 --- frontend/app/types/session/errorStack.ts | 26 ++++++ frontend/app/types/session/reduxAction.js | 12 --- frontend/app/types/session/session.ts | 20 ++-- frontend/app/types/session/stackEvent.ts | 4 +- 16 files changed, 132 insertions(+), 178 deletions(-) delete mode 100644 frontend/app/components/Dashboard/Widgets/LastPerformance/LastPerformance.js delete mode 100644 frontend/app/components/Dashboard/Widgets/LastPerformance/index.js rename frontend/app/duck/{sessions.js => sessions.ts} (85%) delete mode 100644 frontend/app/types/session/activity.js create mode 100644 frontend/app/types/session/activity.ts delete mode 100644 frontend/app/types/session/customField.js delete mode 100644 frontend/app/types/session/errorStack.js create mode 100644 frontend/app/types/session/errorStack.ts delete mode 100644 frontend/app/types/session/reduxAction.js diff --git a/frontend/app/components/Dashboard/Widgets/LastPerformance/LastPerformance.js b/frontend/app/components/Dashboard/Widgets/LastPerformance/LastPerformance.js deleted file mode 100644 index e44e556aa..000000000 --- a/frontend/app/components/Dashboard/Widgets/LastPerformance/LastPerformance.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import { Loader, NoContent } from 'UI'; -import { widgetHOC, SessionLine } from '../common'; - -@widgetHOC('sessionsPerformance', { fitContent: true }) -export default class LastFeedbacks extends React.PureComponent { - render() { - const { data: sessions, loading } = this.props; - return ( - - - { sessions.map(({ sessionId, missedResources }) => ( - - ))} - - - ); - } -} diff --git a/frontend/app/components/Dashboard/Widgets/LastPerformance/index.js b/frontend/app/components/Dashboard/Widgets/LastPerformance/index.js deleted file mode 100644 index 6563813c2..000000000 --- a/frontend/app/components/Dashboard/Widgets/LastPerformance/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './LastPerformance'; \ No newline at end of file diff --git a/frontend/app/components/Session/PlayerContent.js b/frontend/app/components/Session/PlayerContent.js index c7ccfc62b..64d896455 100644 --- a/frontend/app/components/Session/PlayerContent.js +++ b/frontend/app/components/Session/PlayerContent.js @@ -21,7 +21,6 @@ function PlayerContent({ session, live, fullscreen, activeTab, setActiveTab }) { const hasError = !!error - console.log(session, 'hi') const sessionDays = countDaysFrom(session.startedAt); return (
diff --git a/frontend/app/components/Session/WebPlayer.tsx b/frontend/app/components/Session/WebPlayer.tsx index de9e84036..997276a55 100644 --- a/frontend/app/components/Session/WebPlayer.tsx +++ b/frontend/app/components/Session/WebPlayer.tsx @@ -76,7 +76,6 @@ function WebPlayer(props: any) { if (!contextValue.player || !session) return null; - console.log(session) return ( <> diff --git a/frontend/app/duck/assignments.js b/frontend/app/duck/assignments.js index 3abb99fb7..ecb2ca45a 100644 --- a/frontend/app/duck/assignments.js +++ b/frontend/app/duck/assignments.js @@ -60,7 +60,7 @@ const reducer = (state = initialState, action = {}) => { return listUpdater(state, instance); case ADD_MESSAGE.SUCCESS: const user = users.filter(user => user.id === action.data.author).first(); - const activity = Activity({ type: 'message', user, ...action.data,}); + const activity = new Activity({ type: 'message', user, ...action.data,}); return state.updateIn([ 'activeIssue', 'activities' ], list => list.push(activity)); default: return state; diff --git a/frontend/app/duck/issues.js b/frontend/app/duck/issues.js index 6c2c70733..886025a16 100644 --- a/frontend/app/duck/issues.js +++ b/frontend/app/duck/issues.js @@ -58,7 +58,7 @@ const reducer = (state = initialState, action = {}) => { return state.set('activeIssue', Assignment()); case ADD_MESSAGE.SUCCESS: const user = users.filter(user => user.id === action.data.author).first(); - const activity = Activity({ type: 'message', user, ...action.data,}); + const activity = new Activity({ type: 'message', user, ...action.data,}); return state.updateIn([ 'activeIssue', 'activities' ], list => list.push(activity)); case INIT: action.instance.issueType = issueTypes.length > 0 ? issueTypes[0].id : ''; diff --git a/frontend/app/duck/sessions.js b/frontend/app/duck/sessions.ts similarity index 85% rename from frontend/app/duck/sessions.js rename to frontend/app/duck/sessions.ts index 6f015f510..7a4ebd29d 100644 --- a/frontend/app/duck/sessions.js +++ b/frontend/app/duck/sessions.ts @@ -9,7 +9,6 @@ import { LAST_7_DAYS } from 'Types/app/period'; import { getDateRangeFromValue } from 'App/dateRange'; const name = 'sessions'; -const INIT = 'sessions/INIT'; const FETCH_LIST = new RequestTypes('sessions/FETCH_LIST'); const FETCH_AUTOPLAY_LIST = new RequestTypes('sessions/FETCH_AUTOPLAY_LIST'); const FETCH = new RequestTypes('sessions/FETCH'); @@ -46,7 +45,7 @@ const defaultDateFilters = { endDate: range.end.unix() * 1000, }; -const initialState = Map({ +const initObj = { list: List(), sessionIds: [], current: new Session(), @@ -73,22 +72,20 @@ const initialState = Map({ lastPlayedSessionId: null, timeLineTooltip: { time: 0, offset: 0, isVisible: false, timeStr: '' }, createNoteTooltip: { time: 0, isVisible: false, isEdit: false, note: null }, -}); +} + +const initialState = Map(initObj); const reducer = (state = initialState, action = {}) => { switch (action.type) { - case INIT: - return state.set('current', Session(action.session)); - // case FETCH_LIST.REQUEST: - // return action.clear ? state.set('list', List()) : state; case FETCH_ERROR_STACK.SUCCESS: - return state.set('errorStack', List(action.data.trace).map(ErrorStack)).set('sourcemapUploaded', action.data.sourcemapUploaded); + return state.set('errorStack', List(action.data.trace).map(es => new ErrorStack(es))).set('sourcemapUploaded', action.data.sourcemapUploaded); case FETCH_LIVE_LIST.SUCCESS: - const liveList = List(action.data.sessions).map((s) => new Session({ ...s, live: true })); + const liveList = action.data.sessions.map((s) => new Session({ ...s, live: true })); return state.set('liveSessions', liveList); case FETCH_LIST.SUCCESS: const { sessions, total } = action.data; - const list = List(sessions).map(Session); + const list = sessions.map(s => new Session(s)); return state .set('list', list) @@ -126,8 +123,6 @@ const reducer = (state = initialState, action = {}) => { case FETCH.SUCCESS: { // TODO: more common.. or TEMP const events = action.filter.events; - // const filters = action.filter.filters; - const current = state.get('list').find(({ sessionId }) => sessionId === action.data.sessionId) || new Session(); const session = new Session(action.data); const matching = []; @@ -161,20 +156,27 @@ const reducer = (state = initialState, action = {}) => { .set('host', visitedEvents[0] && visitedEvents[0].host); } case FETCH_FAVORITE_LIST.SUCCESS: - return state.set('favoriteList', List(action.data).map(Session)); + return state.set('favoriteList', List(action.data).map(s => new Session(s))); case TOGGLE_FAVORITE.SUCCESS: { const id = action.sessionId; - const session = state.get('list').find(({ sessionId }) => sessionId === id); + let mutableState = state + const list = state.get('list') as unknown as Session[] + const sessionIdx = list.findIndex(({ sessionId }) => sessionId === id); + const session = list[sessionIdx] + const current = state.get('current') as unknown as Session; const wasInFavorite = state.get('favoriteList').findIndex(({ sessionId }) => sessionId === id) > -1; if (session && !wasInFavorite) { session.favorite = true + mutableState = mutableState.updateIn(['list', sessionIdx], () => session) } - return state - // TODO returns bool here??? - .update('current', (currentSession) => (currentSession.sessionId === id ? (currentSession.favorite = !wasInFavorite) : currentSession)) - .update('list', (list) => list.map((listSession) => (listSession.sessionId === id ? (listSession.favorite = !wasInFavorite) : listSession))) - .update('favoriteList', (list) => session ? + if (current.sessionId === id) { + mutableState = mutableState.update('current', + (s: Session) => ({ ...s, favorite: !wasInFavorite}) + ) + } + return mutableState + .update('favoriteList', (list: Session[]) => session ? wasInFavorite ? list.filter(({ sessionId }) => sessionId !== id) : list.push(session) : list ); } @@ -217,8 +219,16 @@ const reducer = (state = initialState, action = {}) => { case SET_EDIT_NOTE_TOOLTIP: return state.set('createNoteTooltip', action.noteTooltip); case FILTER_OUT_NOTE: - return state.updateIn(['current', 'notesWithEvents'], (list) => - list.filter(evt => !evt.noteId || evt.noteId !== action.noteId) + return state.updateIn(['current'], + (session: Session) => ({ + ...session, + notesWithEvents: session.notesWithEvents.filter(item => { + if ('noteId' in item) { + return item.noteId !== action.noteId + } + return true + }) + }) ) case ADD_NOTE: return state.updateIn(['current', 'notesWithEvents'], (list) => @@ -230,25 +240,21 @@ const reducer = (state = initialState, action = {}) => { }) ) case UPDATE_NOTE: - const index = state.getIn(['current', 'notesWithEvents']).findIndex(item => item.noteId === action.note.noteId) - return state.setIn(['current', 'notesWithEvents', index], action.note) + const noteIndex = state.getIn(['current']).notesWithEvents.findIndex(item => item.noteId === action.note.noteId) + return state.setIn(['current', 'notesWithEvents', noteIndex], action.note) case SET_SESSION_PATH: return state.set('sessionPath', action.path); case LAST_PLAYED_SESSION_ID: - return updateListItem(state, action.sessionId, { viewed: true }).set('lastPlayedSessionId', action.sessionId); + const sessionList = state.get('list') as unknown as Session[]; + const sIndex = sessionList.findIndex(({ sessionId }) => sessionId === action.sessionId); + if (sIndex === -1) return state; + + return state.updateIn(['list', sIndex], (session: Session) => ({ ...session, viewed: true })); default: return state; } }; -function updateListItem(state, sourceSessionId, instance) { - const list = state.get('list'); - const index = list.findIndex(({ sessionId }) => sessionId === sourceSessionId); - if (index === -1) return state; - - return state.updateIn(['list', index], (session) => session.merge(instance)); -} - export default withRequestState( { _: [FETCH, FETCH_LIST], @@ -261,13 +267,6 @@ export default withRequestState( reducer ); -function init(session) { - return { - type: INIT, - session, - }; -} - export const fetchList = (params = {}, force = false) => (dispatch) => { @@ -324,13 +323,6 @@ export function toggleFavorite(sessionId) { }; } -export function fetchFavoriteList() { - return { - types: FETCH_FAVORITE_LIST.toArray(), - call: (client) => client.get('/sessions/favorite'), - }; -} - export function fetchInsights(params) { return { types: FETCH_INSIGHTS.toArray(), @@ -361,13 +353,6 @@ export function sort(sortKey, sign = 1, listName = 'list') { }; } -export function redefineTarget(target) { - return { - type: REDEFINE_TARGET, - target, - }; -} - export const setAutoplayValues = (sessionId) => { return { type: SET_AUTOPLAY_VALUES, diff --git a/frontend/app/types/session/activity.js b/frontend/app/types/session/activity.js deleted file mode 100644 index bb9be45fa..000000000 --- a/frontend/app/types/session/activity.js +++ /dev/null @@ -1,53 +0,0 @@ -import Record from 'Types/Record'; -import { DateTime } from 'luxon'; - -const ASSIGN = 'assign'; -const MESSAGE = 'message'; -const OPEN = 'open'; -const CLOSE = 'close'; - -export const TYPES = { ASSIGN, MESSAGE, OPEN, CLOSE }; - -const Activity = Record({ - id: undefined, - type: '', - author: '', - // thread_id: undefined, - createdAt: undefined, - // assigned_to: undefined, - // user_id: undefined, - message: '', - user: '' -}) - -// const Assign = Activity.extend({ -// type: ASSIGN, -// }) - -// const Message = Activity.extend({ -// type: MESSAGE, -// }) - -// const Open = Activity.extend({ -// type: OPEN, -// }) - -// const Close = Activity.extend({ -// type: CLOSE, -// }) - -// const Open = Activity.extend({ -// type: OPEN, -// }) - -export default function(activity = {}) { - // if (activity.type === ASSIGN) return Assign(activity); - // if (activity.type === MESSAGE) return Message(activity); - // if (activity.type === OPEN) return Open(activity); - // if (activity.type === CLOSE) return Close(activity); - return Activity({ - ...activity, - createdAt: activity.createdAt ? DateTime.fromMillis(activity.createdAt, {}).toUTC() : undefined, - }); -} - diff --git a/frontend/app/types/session/activity.ts b/frontend/app/types/session/activity.ts new file mode 100644 index 000000000..97e5e2a5c --- /dev/null +++ b/frontend/app/types/session/activity.ts @@ -0,0 +1,49 @@ +import { DateTime } from 'luxon'; + +const ASSIGN = 'assign'; +const MESSAGE = 'message'; +const OPEN = 'open'; +const CLOSE = 'close'; + +export const TYPES = { ASSIGN, MESSAGE, OPEN, CLOSE } as const; + + +type TypeKeys = keyof typeof TYPES +type TypeValues = typeof TYPES[TypeKeys] + + +export interface IActivity { + id: string; + type: TypeValues; + author: string; + createdAt: number; + message: string; + user: string; +} + +export default class Activity { + id: IActivity["id"]; + type: IActivity["type"]; + author: IActivity["author"]; + createdAt?: DateTime; + message: IActivity["message"]; + user: IActivity["user"]; + + constructor(activity?: IActivity) { + if (activity) { + Object.assign(this, { + ...activity, + createdAt: activity.createdAt ? DateTime.fromMillis(activity.createdAt, {}).toUTC() : undefined, + }) + } else { + Object.assign(this, { + id: undefined, + type: '', + author: '', + createdAt: undefined, + message: '', + user: '' + }) + } + } +} diff --git a/frontend/app/types/session/assignment.js b/frontend/app/types/session/assignment.js index 0c599c85c..ee3e790a6 100644 --- a/frontend/app/types/session/assignment.js +++ b/frontend/app/types/session/assignment.js @@ -27,7 +27,7 @@ export default Record({ if (assignment.users) { activity.user = assignment.users.filter(user => user.id === activity.author).first(); } - return Activity(activity) + return new Activity(activity) }) : List() }), methods: { diff --git a/frontend/app/types/session/customField.js b/frontend/app/types/session/customField.js deleted file mode 100644 index 79f26b914..000000000 --- a/frontend/app/types/session/customField.js +++ /dev/null @@ -1,5 +0,0 @@ -import CustomField from 'Types/customField'; - -export default CustomField.extend({ - value: undefined, -}); \ No newline at end of file diff --git a/frontend/app/types/session/errorStack.js b/frontend/app/types/session/errorStack.js deleted file mode 100644 index b92610229..000000000 --- a/frontend/app/types/session/errorStack.js +++ /dev/null @@ -1,13 +0,0 @@ -import Record from 'Types/Record'; - -export default Record({ - // url: undefined, - absPath: undefined, - filename: undefined, - // args: [], - function: undefined, - lineNo: undefined, - colNo: undefined, - offset: 0, - context: undefined -}); diff --git a/frontend/app/types/session/errorStack.ts b/frontend/app/types/session/errorStack.ts new file mode 100644 index 000000000..c0fac6e83 --- /dev/null +++ b/frontend/app/types/session/errorStack.ts @@ -0,0 +1,26 @@ +interface IErrorStack { + absPath?: string, + filename?: string, + function?: string, + lineNo?: number, + colNo?: number, + offset?: number, + context?: string +} + +export default class ErrorStack { + absPath: IErrorStack["absPath"] + filename: IErrorStack["filename"] + function: IErrorStack["function"] + lineNo: IErrorStack["lineNo"] + colNo: IErrorStack["colNo"] + offset: IErrorStack["offset"] + context:IErrorStack["context"] + + constructor(es: IErrorStack) { + Object.assign(this, { + ...es, + offset: es.offset || 0, + }) + } +} \ No newline at end of file diff --git a/frontend/app/types/session/reduxAction.js b/frontend/app/types/session/reduxAction.js deleted file mode 100644 index e03ab9ce9..000000000 --- a/frontend/app/types/session/reduxAction.js +++ /dev/null @@ -1,12 +0,0 @@ -import Record from 'Types/Record'; - -export default Record({ - time: undefined, - index: undefined, - action: {}, - state: undefined, - diff: [], - duration: undefined, -}); - - diff --git a/frontend/app/types/session/session.ts b/frontend/app/types/session/session.ts index 298ec4fa0..337a7864a 100644 --- a/frontend/app/types/session/session.ts +++ b/frontend/app/types/session/session.ts @@ -38,7 +38,10 @@ export interface ISession { filterId?: string, domURL: string[], devtoolsURL: string[], - mobsUrl: string[], // @depricated + /** + * @deprecated + */ + mobsUrl: string[], userBrowser: string, userBrowserVersion: string, userCountry: string, @@ -71,7 +74,7 @@ export interface ISession { isCallActive?: boolean, agentToken: string, notes: Note[], - notesWithEvents: Note[] | InjectedEvent[], + notesWithEvents: Array, fileKey: string, platform: string, projectId: string, @@ -103,6 +106,7 @@ const emptyValues = { metadata: {}, startedAt: 0, } + export default class Session { sessionId: ISession["sessionId"] pageTitle: ISession["pageTitle"] @@ -116,13 +120,15 @@ export default class Session { events: ISession["events"] stackEvents: ISession["stackEvents"] resources: ISession["resources"] - missedResources: ISession["missedResources"] metadata: ISession["metadata"] favorite: ISession["favorite"] filterId?: ISession["filterId"] domURL: ISession["domURL"] devtoolsURL: ISession["devtoolsURL"] - mobsUrl: ISession["mobsUrl"] // @depricated + /** + * @deprecated + */ + mobsUrl: ISession["mobsUrl"] userBrowser: ISession["userBrowser"] userBrowserVersion: ISession["userBrowserVersion"] userCountry: ISession["userCountry"] @@ -222,8 +228,10 @@ export default class Session { const rawNotes = notes; const notesWithEvents = [...rawEvents, ...rawNotes].sort((a, b) => { - const aTs = a.time || a.timestamp; - const bTs = b.time || b.timestamp; + // @ts-ignore just in case + const aTs = a.timestamp || a.time; + // @ts-ignore + const bTs = b.timestamp || b.time; return aTs - bTs; }) || []; diff --git a/frontend/app/types/session/stackEvent.ts b/frontend/app/types/session/stackEvent.ts index d1c4b7b09..89dc1a7cc 100644 --- a/frontend/app/types/session/stackEvent.ts +++ b/frontend/app/types/session/stackEvent.ts @@ -11,7 +11,7 @@ export const SUMOLOGIC = 'sumologic'; export const typeList = [ OPENREPLAY, SENTRY, DATADOG, STACKDRIVER, ROLLBAR, BUGSNAG, CLOUDWATCH, ELASTICSEARCH, SUMOLOGIC ]; -export function isRed(event) { +export function isRed(event: StackEvent) { if (!event.payload) return false; switch(event.source) { case SENTRY: @@ -31,7 +31,7 @@ export function isRed(event) { case SUMOLOGIC: return false; default: - return event.level==='error'; + return event.level === 'error'; } }