change(ui): rewrite session type and fix reducer

This commit is contained in:
sylenien 2023-01-02 13:04:21 +01:00
parent b2b1caf98e
commit c0785ec6fa
16 changed files with 132 additions and 178 deletions

View file

@ -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 (
<Loader loading={ loading } size="small">
<NoContent
title="No data available."
size="small"
show={ sessions.size === 0 }
>
{ sessions.map(({ sessionId, missedResources }) => (
<SessionLine
sessionId={ sessionId }
icon="file"
info={ missedResources.get(0).name }
subInfo="Missing File"
/>
))}
</NoContent>
</Loader>
);
}
}

View file

@ -1 +0,0 @@
export { default } from './LastPerformance';

View file

@ -21,7 +21,6 @@ function PlayerContent({ session, live, fullscreen, activeTab, setActiveTab }) {
const hasError = !!error
console.log(session, 'hi')
const sessionDays = countDaysFrom(session.startedAt);
return (
<div className="relative">

View file

@ -76,7 +76,6 @@ function WebPlayer(props: any) {
if (!contextValue.player || !session) return null;
console.log(session)
return (
<PlayerContext.Provider value={contextValue}>
<>

View file

@ -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;

View file

@ -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 : '';

View file

@ -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,

View file

@ -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,
});
}

View file

@ -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: ''
})
}
}
}

View file

@ -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: {

View file

@ -1,5 +0,0 @@
import CustomField from 'Types/customField';
export default CustomField.extend({
value: undefined,
});

View file

@ -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
});

View file

@ -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,
})
}
}

View file

@ -1,12 +0,0 @@
import Record from 'Types/Record';
export default Record({
time: undefined,
index: undefined,
action: {},
state: undefined,
diff: [],
duration: undefined,
});

View file

@ -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<Note | InjectedEvent>,
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;
}) || [];

View file

@ -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';
}
}