change(ui): rewrite session type and fix reducer
This commit is contained in:
parent
b2b1caf98e
commit
c0785ec6fa
16 changed files with 132 additions and 178 deletions
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
export { default } from './LastPerformance';
|
||||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ function WebPlayer(props: any) {
|
|||
|
||||
if (!contextValue.player || !session) return null;
|
||||
|
||||
console.log(session)
|
||||
return (
|
||||
<PlayerContext.Provider value={contextValue}>
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 : '';
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
49
frontend/app/types/session/activity.ts
Normal file
49
frontend/app/types/session/activity.ts
Normal 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: ''
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
import CustomField from 'Types/customField';
|
||||
|
||||
export default CustomField.extend({
|
||||
value: undefined,
|
||||
});
|
||||
|
|
@ -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
|
||||
});
|
||||
26
frontend/app/types/session/errorStack.ts
Normal file
26
frontend/app/types/session/errorStack.ts
Normal 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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
import Record from 'Types/Record';
|
||||
|
||||
export default Record({
|
||||
time: undefined,
|
||||
index: undefined,
|
||||
action: {},
|
||||
state: undefined,
|
||||
diff: [],
|
||||
duration: undefined,
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}) || [];
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue