feat(ui) - sessions - widget

This commit is contained in:
Shekar Siri 2022-05-16 19:11:53 +02:00
parent f1d94c5378
commit 82ad650f0c
15 changed files with 196 additions and 6 deletions

View file

@ -1,8 +1,15 @@
import React from 'react';
import React, { useEffect } from 'react';
import ErrorListItem from '../ErrorListItem';
import { useStore } from 'App/mstore';
import { useObserver } from 'mobx-react-lite';
function ErrorsList(props) {
const { errorStore, metricStore } = useStore();
const metric = useObserver(() => metricStore.instance);
useEffect(() => {
errorStore.fetchErrors();
}, []);
return (
<div>
Errors List

View file

@ -0,0 +1,13 @@
import React from 'react';
import SessionListItem from '../SessionListItem';
function SessionList(props) {
return (
<div>
Session list
<SessionListItem session={{}} />
</div>
);
}
export default SessionList;

View file

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

View file

@ -0,0 +1,14 @@
import React from 'react';
interface Props {
session: any;
}
function SessionListItem(props: Props) {
return (
<div>
Session list item
</div>
);
}
export default SessionListItem;

View file

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

View file

@ -0,0 +1,12 @@
import React from 'react';
import SessionList from '../SessionList';
function SessionWidget(props) {
return (
<div>
<SessionList />
</div>
);
}
export default SessionWidget;

View file

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

View file

@ -13,6 +13,7 @@ import { getStartAndEndTimestampsByDensity } from 'Types/dashboard/helper';
import { debounce } from 'App/utils';
import FunnelWidget from 'App/components/Funnels/FunnelWidget';
import ErrorsWidget from '../Errors/ErrorsWidget';
import SessionWidget from '../Sessions/SessionWidget';
interface Props {
metric: any;
isWidget?: boolean
@ -84,6 +85,10 @@ function WidgetChart(props: Props) {
const renderChart = () => {
const { metricType, viewType } = metric;
if (metricType === 'sessions') {
return <SessionWidget metric={metric} />
}
if (metricType === 'errors') {
return <ErrorsWidget metric={metric} />
}

View file

@ -19,7 +19,6 @@ function WidgetView(props: Props) {
const { metricStore } = useStore();
const widget = useObserver(() => metricStore.instance);
const loading = useObserver(() => metricStore.isLoading);
const isFunnel = widget.metricType === 'funnel';
const [expanded, setExpanded] = useState(!metricId || metricId === 'create');
React.useEffect(() => {
@ -73,8 +72,8 @@ function WidgetView(props: Props) {
</div>
<WidgetPreview className="mt-8" />
{ !isFunnel && <WidgetSessions className="mt-8" /> }
{ isFunnel && <FunnelIssues /> }
{ (widget.metricType === 'table' || widget.metricType === 'timeseries') && <WidgetSessions className="mt-8" /> }
{ widget.metricType === 'funnel' && <FunnelIssues /> }
</div>
</Loader>
));

View file

@ -0,0 +1,55 @@
import { makeAutoObservable, runInAction, observable, action, reaction } from "mobx"
import { errorService } from "App/services"
import Error from "./types/error"
export default class ErrorStore {
isLoading: boolean = false
isSaving: boolean = false
errors: any[] = []
instance: Error | null = null
constructor() {
makeAutoObservable(this, {
})
}
updateKey(key: string, value: any) {
this[key] = value
}
fetchErrors(): Promise<any> {
this.isLoading = true
return new Promise((resolve, reject) => {
errorService.all()
.then(response => {
const errors = response.map(e => new Error().fromJSON(e));
this.errors = errors
resolve(errors)
}).catch(error => {
reject(error)
}).finally(() => {
this.isLoading = false
}
)
})
}
fetchError(errorId: string): Promise<any> {
this.isLoading = true
return new Promise((resolve, reject) => {
errorService.one(errorId)
.then(response => {
const error = new Error().fromJSON(response);
this.instance = error
resolve(error)
}).catch(error => {
reject(error)
}).finally(() => {
this.isLoading = false
}
)
})
}
}

View file

@ -5,9 +5,18 @@ import UserStore from './userStore';
import RoleStore from './roleStore';
import APIClient from 'App/api_client';
import FunnelStore from './funnelStore';
import { dashboardService, metricService, funnelService, sessionService, userService, auditService } from 'App/services';
import {
dashboardService,
metricService,
funnelService,
sessionService,
userService,
auditService,
errorService,
} from 'App/services';
import SettingsStore from './settingsStore';
import AuditStore from './auditStore';
import ErrorStore from './errorStore';
export class RootStore {
dashboardStore: IDashboardSotre;
@ -17,6 +26,7 @@ export class RootStore {
userStore: UserStore;
roleStore: RoleStore;
auditStore: AuditStore;
errorStore: ErrorStore;
constructor() {
this.dashboardStore = new DashboardStore();
@ -26,6 +36,7 @@ export class RootStore {
this.userStore = new UserStore();
this.roleStore = new RoleStore();
this.auditStore = new AuditStore();
this.errorStore = new ErrorStore();
}
initClient() {
@ -36,6 +47,7 @@ export class RootStore {
sessionService.initClient(client)
userService.initClient(client)
auditService.initClient(client)
errorService.initClient(client)
}
}

View file

@ -0,0 +1,42 @@
export default class Error {
sessionId: string = ''
messageId: string = ''
timestamp: string = ''
errorId: string = ''
projectId: string = ''
source: string = ''
name: string = ''
message: string = ''
time: string = ''
function: string = '?'
stack0InfoString: string = ''
constructor() {
}
fromJSON(json: any) {
this.sessionId = json.sessionId
this.messageId = json.messageId
this.timestamp = json.timestamp
this.errorId = json.errorId
this.projectId = json.projectId
this.source = json.source
this.name = json.name
this.message = json.message
this.time = json.time
this.function = json.function
this.stack0InfoString = getStck0InfoString(json.stack || [])
return this
}
}
function getStck0InfoString(stack) {
const stack0 = stack[0];
if (!stack0) return "";
let s = stack0.function || "";
if (stack0.url) {
s += ` (${stack0.url})`;
}
return s;
}

View file

@ -0,0 +1,12 @@
import APIClient from 'App/api_client';
export default class BaseService {
client: APIClient;
constructor(client?: APIClient) {
this.client = client ? client : new APIClient();
}
initClient(client?: APIClient) {
this.client = client || new APIClient();
}
}

View file

@ -0,0 +1,14 @@
import BaseService from './BaseService';
export default class ErrorService extends BaseService {
all(params: any = {}): Promise<any[]> {
return this.client.post('/errors/search', params)
.then(response => response.json())
.then(response => response.data || []);
}
one(id: string): Promise<any> {
return this.client.get(`/errors/${id}`)
.then(response => response.json())
}
}

View file

@ -4,6 +4,7 @@ import FunnelService, { IFunnelService } from "./FunnelService";
import SessionSerivce from "./SessionService";
import UserService from "./UserService";
import AuditService from './AuditService';
import ErrorService from "./ErrorService";
export const dashboardService: IDashboardService = new DashboardService();
export const metricService: IMetricService = new MetricService();
@ -11,3 +12,4 @@ export const sessionService: SessionSerivce = new SessionSerivce();
export const userService: UserService = new UserService();
export const funnelService: IFunnelService = new FunnelService();
export const auditService: AuditService = new AuditService();
export const errorService: ErrorService = new ErrorService();