change(ui): widget types
This commit is contained in:
parent
e6d46c3ea1
commit
c2d9a9768a
34 changed files with 483 additions and 274 deletions
|
|
@ -124,7 +124,7 @@ const reducer = (state = initialState, action: IAction) => {
|
|||
return state.set('filteredEvents', filteredEvents).set('eventsQuery', query);
|
||||
}
|
||||
case FETCH.SUCCESS: {
|
||||
// TODO: more common.. or TEMP
|
||||
// TODO: more common.. or TEMP filters', 'appliedFilter
|
||||
const events = action.filter.events;
|
||||
const session = new Session(action.data);
|
||||
|
||||
|
|
@ -191,17 +191,10 @@ const reducer = (state = initialState, action: IAction) => {
|
|||
};
|
||||
return state.update('list', (list: Session[]) => list.sort(comparator)).update('favoriteList', (list: Session[]) => list.sort(comparator));
|
||||
}
|
||||
case REDEFINE_TARGET: {
|
||||
// TODO: update for list
|
||||
const { label, path } = action.target;
|
||||
return state.updateIn(['current', 'events'], (list) =>
|
||||
list.map((event) => (event.target && event.target.path === path ? event.setIn(['target', 'label'], label) : event))
|
||||
);
|
||||
}
|
||||
case SET_ACTIVE_TAB:
|
||||
const allList = action.tab.type === 'all' ? state.get('list') : state.get('list').filter((s) => s.issueTypes.includes(action.tab.type));
|
||||
|
||||
return state.set('activeTab', action.tab).set('sessionIds', allList.map(({ sessionId }) => sessionId).toJS());
|
||||
return state.set('activeTab', action.tab).set('sessionIds', allList.map(({ sessionId }) => sessionId));
|
||||
case SET_TIMEZONE:
|
||||
return state.set('timezone', action.timezone);
|
||||
case TOGGLE_CHAT_WINDOW:
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ 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';
|
||||
import store from 'App/store'
|
||||
import { Note } from "App/services/NotesService";
|
||||
|
||||
class UserFilter {
|
||||
endDate: number = new Date().getTime();
|
||||
|
|
@ -110,12 +112,13 @@ export default class SessionStore {
|
|||
showChatWindow = false
|
||||
liveSessions: Session[] = []
|
||||
visitedEvents = []
|
||||
insights = []
|
||||
insights: any[] = []
|
||||
insightFilters = defaultDateFilters
|
||||
host = ''
|
||||
funnelPage = {}
|
||||
timelinePointer = null
|
||||
sessionPath = {}
|
||||
/** @Deprecated */
|
||||
timelinePointer = {}
|
||||
sessionPath = {}
|
||||
lastPlayedSessionId: string
|
||||
timeLineTooltip = { time: 0, offset: 0, isVisible: false, timeStr: '' }
|
||||
createNoteTooltip = { time: 0, isVisible: false, isEdit: false, note: null }
|
||||
|
|
@ -174,7 +177,43 @@ export default class SessionStore {
|
|||
this.total = data.total;
|
||||
this.sessionIds = data.sessions.map(s => s.sessionId);
|
||||
this.favoriteList = list.filter(s => s.favorite);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
async fetchSessionInfo(sessionId: string, isLive = false) {
|
||||
try {
|
||||
const { events } = store.getState().getIn(['filters', 'appliedFilter']);
|
||||
const data = await sessionService.getSessionInfo(sessionId, isLive)
|
||||
const session = new Session(data)
|
||||
|
||||
const matching: number[] = [];
|
||||
const visitedEvents: Location[] = [];
|
||||
const tmpMap: Set<string> = new Set();
|
||||
|
||||
session.events.forEach((event) => {
|
||||
if (event.type === 'LOCATION' && !tmpMap.has(event.url)) {
|
||||
tmpMap.add(event.url);
|
||||
visitedEvents.push(event);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
(events as {}[]).forEach(({ key, operator, value }: any) => {
|
||||
session.events.forEach((e, index) => {
|
||||
if (key === e.type) {
|
||||
const val = e.type === 'LOCATION' ? e.url : e.value;
|
||||
if (operator === 'is' && value === val) {
|
||||
matching.push(index);
|
||||
}
|
||||
if (operator === 'contains' && val.includes(value)) {
|
||||
matching.push(index);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
|
@ -194,7 +233,7 @@ export default class SessionStore {
|
|||
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) {
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
|
@ -221,6 +260,147 @@ export default class SessionStore {
|
|||
) : null;
|
||||
|
||||
this.filteredEvents = filteredEvents
|
||||
this.eventsQuery = query
|
||||
this.eventsQuery = query
|
||||
}
|
||||
|
||||
async toggleFavorite(id: string) {
|
||||
try {
|
||||
const r = await sessionService.toggleFavorite(id)
|
||||
if (r.success) {
|
||||
const list = this.list;
|
||||
const current = this.current;
|
||||
const sessionIdx = list.findIndex(({ sessionId }) => sessionId === id);
|
||||
const session = list[sessionIdx]
|
||||
const wasInFavorite = this.favoriteList.findIndex(({ sessionId }) => sessionId === id) > -1;
|
||||
|
||||
if (session && !wasInFavorite) {
|
||||
session.favorite = true
|
||||
this.list[sessionIdx] = session
|
||||
}
|
||||
if (current.sessionId === id) {
|
||||
this.current.favorite = !wasInFavorite
|
||||
}
|
||||
|
||||
if (session) {
|
||||
if (wasInFavorite) {
|
||||
this.favoriteList = this.favoriteList.filter(({ sessionId }) => sessionId !== id)
|
||||
} else {
|
||||
this.favoriteList.push(session)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.error(r)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
sortSessions(sortKey: string, sign: number) {
|
||||
const comparator = (s1: Session, s2: Session) => {
|
||||
// @ts-ignore
|
||||
let diff = s1[sortKey] - s2[sortKey];
|
||||
diff = diff === 0 ? s1.startedAt - s2.startedAt : diff;
|
||||
return sign * diff;
|
||||
};
|
||||
|
||||
this.list = this.list.sort(comparator)
|
||||
this.favoriteList = this.favoriteList.sort(comparator)
|
||||
return;
|
||||
}
|
||||
|
||||
setActiveTab(tab: { type: string }) {
|
||||
const list = tab.type === 'all'
|
||||
? this.list : this.list.filter(s => s.issueTypes.includes(tab.type))
|
||||
|
||||
// @ts-ignore
|
||||
this.activeTab = tab
|
||||
this.sessionIds = list.map(s => s.sessionId)
|
||||
}
|
||||
|
||||
setTimezone(tz: string) {
|
||||
this.timezone = tz;
|
||||
}
|
||||
|
||||
toggleChatWindow(isActive: boolean) {
|
||||
this.showChatWindow = isActive
|
||||
}
|
||||
|
||||
async fetchInsights(filters = {}) {
|
||||
try {
|
||||
const data = await sessionService.getClickMap(filters)
|
||||
|
||||
this.insights = data
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
setFunnelPage(page = {}) {
|
||||
this.funnelPage = page || false
|
||||
}
|
||||
|
||||
/* @deprecated */
|
||||
setTimelinePointer(pointer: {}) {
|
||||
this.timelinePointer = pointer
|
||||
}
|
||||
|
||||
setTimelineTooltip(tp: { time: number, offset: number, isVisible: boolean, timeStr: string }) {
|
||||
this.timeLineTooltip = tp
|
||||
}
|
||||
|
||||
setEditNoteTooltip(tp: { time: number, isVisible: boolean, isEdit: boolean, note: any }) {
|
||||
this.createNoteTooltip = tp
|
||||
}
|
||||
|
||||
filterOutNote(noteId: string) {
|
||||
const current = this.current
|
||||
|
||||
current.notesWithEvents = current.notesWithEvents.filter(n => {
|
||||
if ('noteId' in item) {
|
||||
return item.noteId !== noteId
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
this.current = current
|
||||
}
|
||||
|
||||
addNote(note: Note) {
|
||||
const current = this.current
|
||||
|
||||
current.notesWithEvents.push(note)
|
||||
current.notesWithEvents.sort((a,b) => {
|
||||
const aTs = a.time || a.timestamp
|
||||
const bTs = b.time || b.timestamp
|
||||
|
||||
return aTs - bTs
|
||||
})
|
||||
|
||||
this.current = current
|
||||
}
|
||||
|
||||
updateNote(note: Note) {
|
||||
const noteIndex = this.current.notesWithEvents.findIndex(item => {
|
||||
if ('noteId' in item) {
|
||||
return item.noteId === note.noteId
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
this.current.notesWithEvents[noteIndex] = note
|
||||
}
|
||||
|
||||
setSessionPath(path = {}) {
|
||||
this.sessionPath = path
|
||||
}
|
||||
|
||||
setLastPlayed(sessionId: string) {
|
||||
const list = this.list
|
||||
const sIndex = list.findIndex((s) => s.sessionId === sessionId)
|
||||
if (sIndex !== -1) {
|
||||
this.list[sIndex].viewed = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,11 +57,25 @@ export default class SettingsService {
|
|||
.catch(e => Promise.reject(e))
|
||||
}
|
||||
|
||||
getAutoplayList(params = {}): Promise<{ sessionId: string}[]> {
|
||||
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))
|
||||
}
|
||||
|
||||
toggleFavorite(sessionId: string): Promise<any> {
|
||||
return this.client
|
||||
.get(`/sessions/${sessionId}/favorite`)
|
||||
.catch(Promise.reject)
|
||||
}
|
||||
|
||||
getClickMap(params = {}): Promise<any[]> {
|
||||
return this.client
|
||||
.post('/heatmaps/url', params)
|
||||
.then(r => r.json())
|
||||
.then(j => j.data || [])
|
||||
.catch(Promise.reject)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
import Record from 'Types/Record';
|
||||
|
||||
export default Record({
|
||||
method: '',
|
||||
urlHostpath: '',
|
||||
allRequests: '',
|
||||
'4xx': '',
|
||||
'5xx': ''
|
||||
}, {
|
||||
// fromJS: pm => ({
|
||||
// ...pm,
|
||||
// }),
|
||||
});
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import { Record } from 'immutable';
|
||||
|
||||
const DomBuildingTime = Record({
|
||||
avg: undefined,
|
||||
chart: [],
|
||||
});
|
||||
|
||||
|
||||
function fromJS(data = {}) {
|
||||
if (data instanceof DomBuildingTime) return data;
|
||||
return new DomBuildingTime(data);
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
|
|
@ -1,30 +1,9 @@
|
|||
export const getDayStartAndEndTimestamps = (date) => {
|
||||
const start = moment(date).startOf('day').valueOf();
|
||||
const end = moment(date).endOf('day').valueOf();
|
||||
return { start, end };
|
||||
};
|
||||
|
||||
// const getPerformanceDensity = (period) => {
|
||||
// switch (period) {
|
||||
// case HALF_AN_HOUR:
|
||||
// return 30;
|
||||
// case WEEK:
|
||||
// return 84;
|
||||
// case MONTH:
|
||||
// return 90;
|
||||
// case DAY:
|
||||
// return 48;
|
||||
// default:
|
||||
// return 48;
|
||||
// }
|
||||
// };
|
||||
|
||||
const DAY = 1000 * 60 * 60 * 24;
|
||||
const WEEK = DAY * 8;
|
||||
|
||||
const startWithZero = num => (num < 10 ? `0${ num }` : `${ num }`);
|
||||
const startWithZero = (num: number) => (num < 10 ? `0${ num }` : `${ num }`);
|
||||
const weekdays = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ];
|
||||
// const months = [ "January", "February" ];
|
||||
|
||||
export const getTimeString = (ts, period) => {
|
||||
const date = new Date(ts);
|
||||
const diff = period.endTimestamp - period.startTimestamp;
|
||||
|
|
@ -41,11 +20,11 @@ export const getTimeString = (ts, period) => {
|
|||
export const getChartFormatter = period => (data = []) =>
|
||||
data.map(({ timestamp, ...rest }) => ({ time: getTimeString(timestamp, period), ...rest, timestamp }));
|
||||
|
||||
export const getStartAndEndTimestampsByDensity = (current, start, end, density) => {
|
||||
export const getStartAndEndTimestampsByDensity = (current: number, start: number, end: number, density: number) => {
|
||||
const diff = end - start;
|
||||
const step = Math.floor(diff / density);
|
||||
const currentIndex = Math.floor((current - start) / step);
|
||||
const startTimestamp = parseInt(start + currentIndex * step);
|
||||
const endTimestamp = parseInt(startTimestamp + step);
|
||||
const startTimestamp = start + currentIndex * step;
|
||||
const endTimestamp = startTimestamp + step;
|
||||
return { startTimestamp, endTimestamp };
|
||||
};
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { Map, List } from 'immutable';
|
||||
import { List } from 'immutable';
|
||||
import Session from 'Types/session';
|
||||
import { camelCased } from 'App/utils';
|
||||
|
||||
|
|
@ -29,7 +29,6 @@ import SlowestDomains from './slowestDomains';
|
|||
import ResourceLoadingTime from './resourceLoadingTime';
|
||||
|
||||
import Image from './image';
|
||||
import Resource from './resource';
|
||||
import Err from './err';
|
||||
import MissingResource from './missingResource';
|
||||
|
||||
|
|
@ -58,7 +57,7 @@ export const WIDGET_LIST = [{
|
|||
name: "User Activity",
|
||||
description: 'The average user feedback score, average number of visited pages per session and average session duration.',
|
||||
thumb: 'user_activity.png',
|
||||
dataWrapper: UserActivity,
|
||||
dataWrapper: data => new UserActivity(data),
|
||||
}, {
|
||||
key: "pageMetrics",
|
||||
name: "Page Metrics",
|
||||
|
|
@ -85,13 +84,6 @@ export const WIDGET_LIST = [{
|
|||
return i2.avgDuration - i1.avgDuration;
|
||||
}),
|
||||
},
|
||||
// {
|
||||
// key: "errorsTrend",
|
||||
// name: "Most Impactful Errors",
|
||||
// description: 'List of errors and exceptions, sorted by the number of impacted sessions.',
|
||||
// thumb: 'most_Impactful_errors.png',
|
||||
// dataWrapper: list => List(list).map(Err),
|
||||
// },
|
||||
{
|
||||
key: "sessionsFrustration",
|
||||
name: "Recent Frustrations",
|
||||
|
|
@ -114,19 +106,13 @@ export const WIDGET_LIST = [{
|
|||
type: 'resources',
|
||||
dataWrapper: list => List(list).map(MissingResource),
|
||||
},
|
||||
// {
|
||||
// key: "sessionsPerformance",
|
||||
// name: "Recent Performance Issues",
|
||||
// description: "",
|
||||
// dataWrapper: list => List(list).map(Session),
|
||||
// }
|
||||
{
|
||||
key: "slowestResources",
|
||||
name: "Slowest Resources",
|
||||
description: 'List of resources that are slowing down your website, sorted by the number of impacted sessions.',
|
||||
thumb: 'na.png',
|
||||
type: 'resources',
|
||||
dataWrapper: list => List(list).map(SlowestResources)
|
||||
dataWrapper: list => list.map(res => new SlowestResources(res))
|
||||
},
|
||||
{
|
||||
key: "overview",
|
||||
|
|
@ -138,8 +124,6 @@ export const WIDGET_LIST = [{
|
|||
.map(item => OverviewWidget({ key: camelCased(item.key), ...item.data}))
|
||||
.map(widget => widget.update("chart", getChartFormatter(period)))
|
||||
}
|
||||
// dataWrapper: (p, period) => List(p)
|
||||
// .update("chart", getChartFormatter(period))
|
||||
},
|
||||
{
|
||||
key: "speedLocation",
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
import Record from 'Types/Record';
|
||||
|
||||
const getName = (url = '') => url.split('/').filter(part => !!part).pop();
|
||||
|
||||
export default Record({
|
||||
avgDuration: undefined,
|
||||
sessions: undefined,
|
||||
chart: [],
|
||||
url: '',
|
||||
name: '',
|
||||
}, {
|
||||
fromJS: (resource) => ({
|
||||
...resource,
|
||||
name: getName(resource.url),
|
||||
})
|
||||
});
|
||||
24
frontend/app/types/dashboard/resource.ts
Normal file
24
frontend/app/types/dashboard/resource.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
const getName = (url = '') => url.split('/').filter(part => !!part).pop();
|
||||
|
||||
interface IResource {
|
||||
avgDuration: number;
|
||||
sessions: any[];
|
||||
chart: any[];
|
||||
url: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export default class Resource {
|
||||
avgDuration: IResource["avgDuration"];
|
||||
sessions: IResource["sessions"];
|
||||
chart: IResource["chart"] = [];
|
||||
url: IResource["url"] = '';
|
||||
name: IResource["name"] = '';
|
||||
|
||||
constructor(data: IResource) {
|
||||
Object.assign(this, {
|
||||
...data,
|
||||
name: getName(data.url),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
import { Record } from 'immutable';
|
||||
|
||||
const ResourceLoadingTime = Record({
|
||||
avg: undefined,
|
||||
timestamp: undefined
|
||||
});
|
||||
|
||||
function fromJS(resourceLoadingTime = {}) {
|
||||
if (resourceLoadingTime instanceof ResourceLoadingTime) return resourceLoadingTime;
|
||||
return new ResourceLoadingTime(resourceLoadingTime);
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
21
frontend/app/types/dashboard/resourceLoadingTime.ts
Normal file
21
frontend/app/types/dashboard/resourceLoadingTime.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
interface IResourceLoadingTime {
|
||||
avg: number;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
class ResourceLoadingTime {
|
||||
avg: IResourceLoadingTime["avg"];
|
||||
timestamp: IResourceLoadingTime["timestamp"];
|
||||
|
||||
constructor(data: IResourceLoadingTime) {
|
||||
Object.assign(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
function fromJS(resourceLoadingTime = {}) {
|
||||
if (resourceLoadingTime instanceof ResourceLoadingTime) return resourceLoadingTime;
|
||||
return new ResourceLoadingTime(resourceLoadingTime);
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import { Record } from 'immutable';
|
||||
|
||||
const ResponseTime = Record({
|
||||
avg: undefined,
|
||||
chart: [],
|
||||
});
|
||||
|
||||
|
||||
function fromJS(data = {}) {
|
||||
if (data instanceof ResponseTime) return data;
|
||||
return new ResponseTime(data);
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
20
frontend/app/types/dashboard/responseTime.ts
Normal file
20
frontend/app/types/dashboard/responseTime.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
interface IResponseTime {
|
||||
avg: number;
|
||||
chart: any[];
|
||||
}
|
||||
|
||||
class ResponseTime {
|
||||
avg: IResponseTime["avg"]
|
||||
chart: IResponseTime["chart"] = []
|
||||
|
||||
constructor(data: IResponseTime) {
|
||||
Object.assign(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
function fromJS(data = {}) {
|
||||
if (data instanceof ResponseTime) return data;
|
||||
return new ResponseTime(data);
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import { Record } from 'immutable';
|
||||
|
||||
const ResponseTimeDistribution = Record({
|
||||
chart: [],
|
||||
avg: undefined,
|
||||
percentiles: [],
|
||||
extremeValues: [],
|
||||
total: undefined
|
||||
});
|
||||
|
||||
|
||||
function fromJS(data = {}) {
|
||||
if (data instanceof ResponseTimeDistribution) return data;
|
||||
return new ResponseTimeDistribution(data);
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
27
frontend/app/types/dashboard/responseTimeDistribution.ts
Normal file
27
frontend/app/types/dashboard/responseTimeDistribution.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
interface IResponseTimeDistribution {
|
||||
chart: any[],
|
||||
avg: number,
|
||||
percentiles: number[],
|
||||
extremeValues: number[],
|
||||
total: number
|
||||
}
|
||||
|
||||
class ResponseTimeDistribution {
|
||||
chart: IResponseTimeDistribution["chart"] = []
|
||||
avg: IResponseTimeDistribution["avg"]
|
||||
percentiles: IResponseTimeDistribution["percentiles"] = []
|
||||
extremeValues: IResponseTimeDistribution["extremeValues"] = []
|
||||
total: IResponseTimeDistribution["total"]
|
||||
|
||||
constructor(data: IResponseTimeDistribution) {
|
||||
Object.assign(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function fromJS(data = {}) {
|
||||
if (data instanceof ResponseTimeDistribution) return data;
|
||||
return new ResponseTimeDistribution(data);
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import { Record } from 'immutable';
|
||||
|
||||
const SessionsImpactedByJSErrors = Record({
|
||||
errorsCount: undefined,
|
||||
chart: []
|
||||
});
|
||||
|
||||
|
||||
function fromJS(data = {}) {
|
||||
if (data instanceof SessionsImpactedByJSErrors) return data;
|
||||
return new SessionsImpactedByJSErrors(data);
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
20
frontend/app/types/dashboard/sessionsImpactedByJSErrors.ts
Normal file
20
frontend/app/types/dashboard/sessionsImpactedByJSErrors.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
interface ISessionsImpactedByJSErrors {
|
||||
errorsCount: number;
|
||||
chart: any[];
|
||||
}
|
||||
|
||||
class SessionsImpactedByJSErrors {
|
||||
errorsCount: ISessionsImpactedByJSErrors["errorsCount"];
|
||||
chart: ISessionsImpactedByJSErrors["chart"];
|
||||
|
||||
constructor(data: ISessionsImpactedByJSErrors) {
|
||||
Object.assign(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
function fromJS(data = {}) {
|
||||
if (data instanceof SessionsImpactedByJSErrors) return data;
|
||||
return new SessionsImpactedByJSErrors(data);
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import { Record } from 'immutable';
|
||||
|
||||
const SessionsImpactedBySlowRequests = Record({
|
||||
avg: undefined,
|
||||
chart: [],
|
||||
});
|
||||
|
||||
|
||||
function fromJS(data = {}) {
|
||||
if (data instanceof SessionsImpactedBySlowRequests) return data;
|
||||
return new SessionsImpactedBySlowRequests(data);
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
interface ISessionsSlowRequests {
|
||||
avg: number;
|
||||
chart: any[];
|
||||
}
|
||||
|
||||
class SessionsImpactedBySlowRequests {
|
||||
avg: ISessionsSlowRequests["avg"];
|
||||
chart: ISessionsSlowRequests["chart"] = [];
|
||||
|
||||
constructor(data: ISessionsSlowRequests) {
|
||||
Object.assign(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
function fromJS(data = {}) {
|
||||
if (data instanceof SessionsImpactedBySlowRequests) return data;
|
||||
return new SessionsImpactedBySlowRequests(data);
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
import { Record } from 'immutable';
|
||||
|
||||
const SessionsPerBrowser = Record({
|
||||
count: undefined,
|
||||
chart: [],
|
||||
});
|
||||
|
||||
function fromJS(sessionsPerBrowser = {}) {
|
||||
if (sessionsPerBrowser instanceof SessionsPerBrowser) return sessionsPerBrowser;
|
||||
return new SessionsPerBrowser({...sessionsPerBrowser, avg: Math.round(sessionsPerBrowser.avg)});
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
22
frontend/app/types/dashboard/sessionsPerBrowser.ts
Normal file
22
frontend/app/types/dashboard/sessionsPerBrowser.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
interface ISessionsPerBrowser {
|
||||
count?: number,
|
||||
chart?: any[],
|
||||
avg: number,
|
||||
}
|
||||
|
||||
class SessionsPerBrowser {
|
||||
count: ISessionsPerBrowser["count"]
|
||||
chart: ISessionsPerBrowser["chart"] = []
|
||||
avg: ISessionsPerBrowser["avg"]
|
||||
|
||||
constructor(data: ISessionsPerBrowser) {
|
||||
Object.assign(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
function fromJS(sessionsPerBrowser = {}) {
|
||||
if (sessionsPerBrowser instanceof SessionsPerBrowser) return sessionsPerBrowser;
|
||||
return new SessionsPerBrowser({...sessionsPerBrowser, avg: Math.round(sessionsPerBrowser.avg)});
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
|
|
@ -1,9 +1,18 @@
|
|||
import { Record } from 'immutable';
|
||||
|
||||
const SlowestDomains = Record({
|
||||
partition: [],
|
||||
avg: undefined,
|
||||
});
|
||||
interface ISlowestDomains {
|
||||
partition?: string[];
|
||||
avg: number;
|
||||
}
|
||||
|
||||
class SlowestDomains {
|
||||
partition: ISlowestDomains["partition"] = [];
|
||||
avg: ISlowestDomains["avg"];
|
||||
|
||||
constructor(data: ISlowestDomains) {
|
||||
Object.assign(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
function fromJS(slowestDomains = {}) {
|
||||
if (slowestDomains instanceof SlowestDomains) return slowestDomains;
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
import Record from 'Types/Record';
|
||||
import { fileType, fileName } from 'App/utils';
|
||||
|
||||
const validTypes = ['jpg', 'jpeg', 'js', 'css', 'woff', 'css', 'png', 'gif', 'svg']
|
||||
|
||||
export default Record({
|
||||
avg: 0,
|
||||
url: '',
|
||||
type: '',
|
||||
name: '',
|
||||
chart: [],
|
||||
}, {
|
||||
fromJS: pm => {
|
||||
const type = fileType(pm.url).toLowerCase();
|
||||
return {
|
||||
...pm,
|
||||
// type: validTypes.includes(type) ? type : 'n/a',
|
||||
// fileName: fileName(pm.url)
|
||||
}
|
||||
},
|
||||
});
|
||||
19
frontend/app/types/dashboard/slowestResources.ts
Normal file
19
frontend/app/types/dashboard/slowestResources.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
interface ISlowestResources {
|
||||
avg: number;
|
||||
url: string;
|
||||
type: string;
|
||||
name: string;
|
||||
chart: any[]
|
||||
}
|
||||
|
||||
export default class SlowestResources {
|
||||
avg: ISlowestResources["avg"];
|
||||
url: ISlowestResources["url"];
|
||||
type: ISlowestResources["type"];
|
||||
name: ISlowestResources["name"];
|
||||
chart: ISlowestResources["chart"];
|
||||
|
||||
constructor(data: ISlowestResources) {
|
||||
Object.assign(this, data);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import { Record } from 'immutable';
|
||||
|
||||
const SpeedLocation = Record({
|
||||
avg: undefined,
|
||||
chart: [],
|
||||
});
|
||||
|
||||
|
||||
function fromJS(data = {}) {
|
||||
if (data instanceof SpeedLocation) return data;
|
||||
return new SpeedLocation(data);
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
20
frontend/app/types/dashboard/speedLocation.ts
Normal file
20
frontend/app/types/dashboard/speedLocation.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
interface ISpeedLocation {
|
||||
avg?: number
|
||||
chart?: any[]
|
||||
}
|
||||
|
||||
class SpeedLocation {
|
||||
avg?: ISpeedLocation["avg"]
|
||||
chart?: ISpeedLocation["chart"]
|
||||
|
||||
constructor(data: ISpeedLocation) {
|
||||
Object.assign(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
function fromJS(data = {}) {
|
||||
if (data instanceof SpeedLocation) return data;
|
||||
return new SpeedLocation(data);
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
import { Record } from 'immutable';
|
||||
|
||||
const TimeToRender = Record({
|
||||
avg: undefined,
|
||||
chart: [],
|
||||
});
|
||||
|
||||
function fromJS(data = {}) {
|
||||
if (data instanceof TimeToRender) return data;
|
||||
return new TimeToRender(data);
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
20
frontend/app/types/dashboard/timeToRender.ts
Normal file
20
frontend/app/types/dashboard/timeToRender.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
interface ITimeToRender {
|
||||
avg?: number
|
||||
chart?: any[]
|
||||
}
|
||||
|
||||
class TimeToRender {
|
||||
avg: ITimeToRender["avg"]
|
||||
chart: ITimeToRender["chart"] = []
|
||||
|
||||
constructor(data: ITimeToRender) {
|
||||
Object.assign(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
function fromJS(data = {}) {
|
||||
if (data instanceof TimeToRender) return data;
|
||||
return new TimeToRender(data);
|
||||
}
|
||||
|
||||
export default fromJS;
|
||||
|
|
@ -1,8 +1,16 @@
|
|||
import { Record } from 'immutable';
|
||||
|
||||
const TopDomains = Record({
|
||||
chart: []
|
||||
});
|
||||
interface ITopDomains {
|
||||
chart?: any[]
|
||||
}
|
||||
|
||||
class TopDomains {
|
||||
chart: ITopDomains["chart"] = []
|
||||
|
||||
constructor(data: ITopDomains) {
|
||||
this.chart = data.chart
|
||||
}
|
||||
}
|
||||
|
||||
function fromJS(data = {}) {
|
||||
if (data instanceof TopDomains) return data;
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import Record from 'Types/Record';
|
||||
|
||||
export default Record({
|
||||
avgResponseTime: 0,
|
||||
requestsCount: 0,
|
||||
avgTimeTilFirstBite: 0,
|
||||
avgDomCompleteTime: 0
|
||||
}, {
|
||||
// fromJS: aa => ({
|
||||
// avgPageLoad: aa.avgDom,
|
||||
// avgPageLoadProgress: aa.avgDomProgress,
|
||||
// avgImgLoad: aa.avgLoad,
|
||||
// avgImgLoadProgress: aa.avgLoadProgress,
|
||||
// avgReqLoad: aa.avgFirstPixel,
|
||||
// avgReqLoadProgress: aa.avgFirstPixelProgress,
|
||||
// ...aa,
|
||||
// }),
|
||||
});
|
||||
|
||||
17
frontend/app/types/dashboard/topMetrics.ts
Normal file
17
frontend/app/types/dashboard/topMetrics.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
interface ITopMetrics {
|
||||
avgResponseTime: number
|
||||
requestsCount: number
|
||||
avgTimeTilFirstBite: number
|
||||
avgDomCompleteTime: number
|
||||
}
|
||||
|
||||
export default class TopMetrics {
|
||||
avgResponseTime: ITopMetrics["avgResponseTime"] = 0
|
||||
requestsCount: ITopMetrics["requestsCount"] = 0
|
||||
avgTimeTilFirstBite: ITopMetrics["avgTimeTilFirstBite"] = 0
|
||||
avgDomCompleteTime: ITopMetrics["avgDomCompleteTime"] = 0
|
||||
|
||||
constructor(data: ITopMetrics) {
|
||||
Object.assign(this, data)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import Record from 'Types/Record';
|
||||
|
||||
export default Record({
|
||||
avgVisitedPages: undefined,
|
||||
avgVisitedPagesProgress: undefined,
|
||||
avgDuration: undefined,
|
||||
avgDurationProgress: undefined,
|
||||
avgEmotionalRating: undefined,
|
||||
avgEmotionalRatingProgress: undefined,
|
||||
});
|
||||
17
frontend/app/types/dashboard/userActivity.ts
Normal file
17
frontend/app/types/dashboard/userActivity.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
interface IUserActivity {
|
||||
avgVisitedPages: number;
|
||||
avgVisitedPagesProgress: number;
|
||||
avgDuration: number;
|
||||
avgDurationProgress: number;
|
||||
}
|
||||
|
||||
export default class UserActivity {
|
||||
avgVisitedPages: IUserActivity["avgVisitedPages"]
|
||||
avgVisitedPagesProgress: IUserActivity["avgDurationProgress"]
|
||||
avgDuration: IUserActivity["avgDuration"]
|
||||
avgDurationProgress: IUserActivity["avgDurationProgress"]
|
||||
|
||||
constructor(activity: IUserActivity) {
|
||||
Object.assign(this, activity)
|
||||
}
|
||||
}
|
||||
|
|
@ -60,7 +60,7 @@ export interface ISession {
|
|||
eventsCount: number,
|
||||
pagesCount: number,
|
||||
errorsCount: number,
|
||||
issueTypes: [],
|
||||
issueTypes: string[],
|
||||
issues: [],
|
||||
referrer: string | null,
|
||||
userDeviceHeapSize: number,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue