feat(ui) - funnels more steps

This commit is contained in:
Shekar Siri 2022-06-20 12:02:28 +02:00
parent fb164af465
commit 1bcb0dfc01
14 changed files with 212 additions and 111 deletions

View file

@ -18,10 +18,10 @@ function ErrorListItem(props: Props) {
const { error, className = '' } = props;
return (
<div
className={ cn("border p-3 flex justify-between cursor-pointer py-4 hover:bg-active-blue mb-3", className) }
className={ cn("border p-3 grid grid-cols-12 gap-4 cursor-pointer py-4 hover:bg-active-blue mb-3", className) }
id="error-item"
>
<div className={ cn("flex-1 leading-tight") } >
<div className={ cn("col-span-6 leading-tight") } >
<div>
<ErrorName
icon={error.status === IGNORED ? 'ban' : null }
@ -35,26 +35,31 @@ function ErrorListItem(props: Props) {
</div>
</div>
</div>
<BarChart width={ 150 } height={ 40 } data={ error.chart }>
<XAxis hide dataKey="timestamp" />
<YAxis hide domain={[0, 'dataMax + 8']} />
<Tooltip {...Styles.tooltip} label="Sessions" content={<CustomTooltip />} />
<Bar name="Sessions" minPointSize={1} dataKey="count" fill="#A8E0DA" />
</BarChart>
<div className="col-span-2">
<BarChart width={ 150 } height={ 40 } data={ error.chart }>
<XAxis hide dataKey="timestamp" />
<YAxis hide domain={[0, 'dataMax + 8']} />
<Tooltip {...Styles.tooltip} label="Sessions" content={<CustomTooltip />} />
<Bar name="Sessions" minPointSize={1} dataKey="count" fill="#A8E0DA" />
</BarChart>
</div>
<ErrorLabel
// className={stl.sessions}
topValue={ error.sessions }
bottomValue="Sessions"
className="col-span-1"
/>
<ErrorLabel
// className={stl.users}
topValue={ error.users }
bottomValue="Users"
className="col-span-1"
/>
<ErrorLabel
// className={stl.occurrence}
topValue={ `${error.lastOccurrence && diffFromNowString(error.lastOccurrence)} ago` }
bottomValue="Last Seen"
className="col-span-2"
/>
</div>
);

View file

@ -1,24 +1,19 @@
import React, { useEffect, useState } from 'react';
import { useStore } from 'App/mstore';
import { useObserver } from 'mobx-react-lite';
import { NoContent, Loader } from 'UI';
import { Loader } from 'UI';
import FunnelIssuesDropdown from '../FunnelIssuesDropdown';
import FunnelIssuesSort from '../FunnelIssuesSort';
import FunnelIssuesList from '../FunnelIssuesList';
import { DateTime } from 'luxon';
import { debounce } from 'App/utils';
import useIsMounted from 'App/hooks/useIsMounted';
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
function FunnelIssues() {
const { metricStore, dashboardStore } = useStore();
const [data, setData] = useState<any>({ issues: [] });
const [loading, setLoading] = useState(false);
const isMounted = useIsMounted()
// const funnel = useObserver(() => funnelStore.instance);
// const funnel = useObserver(() => metricStore.instance);
// const issues = useObserver(() => funnelStore.issues);
// const loading = useObserver(() => funnelStore.isLoadingIssues);
const fetchIssues = (filter: any) => {
if (!isMounted()) return;
@ -35,7 +30,6 @@ function FunnelIssues() {
const startTime = DateTime.fromMillis(filter.startTimestamp).toFormat('LLL dd, yyyy HH:mm a');
const endTime = DateTime.fromMillis(filter.endTimestamp).toFormat('LLL dd, yyyy HH:mm a');
const debounceRequest: any = React.useCallback(debounce(fetchIssues, 1000), []);
const depsString = JSON.stringify(widget.series);
useEffect(() => {
@ -54,17 +48,7 @@ function FunnelIssues() {
</div>
</div>
<Loader loading={loading}>
<NoContent
show={!loading && data.issues.length === 0}
title={
<div className="flex flex-col items-center justify-center">
<AnimatedSVG name={ICONS.NO_RESULTS} size="170" />
<div className="mt-6 text-2xl">No issues found</div>
</div>
}
>
<FunnelIssuesList issues={data.issues} />
</NoContent>
<FunnelIssuesList issues={data.issues} />
</Loader>
</div>
));

View file

@ -1,9 +1,10 @@
import React, { Component, ReactNode, FunctionComponent, useEffect } from 'react';
import React, { useEffect } from 'react';
import Select from 'Shared/Select'
import { components } from 'react-select';
import { Icon } from 'UI';
import FunnelIssuesSelectedFilters from '../FunnelIssuesSelectedFilters';
import { useStore } from 'App/mstore';
import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv';
const options = [
{ value: "click_rage", label: "Click Rage" },
@ -20,7 +21,7 @@ const options = [
{ value: "js_error", label: "Error" }
]
function FunnelIssuesDropdown(props) {
function FunnelIssuesDropdown() {
const { funnelStore } = useStore();
const [isOpen, setIsOpen] = React.useState(false);
const [selectedValues, setSelectedValues] = React.useState<any>([]);
@ -48,12 +49,20 @@ function FunnelIssuesDropdown(props) {
}
}
const onClickOutside = () => {
if (isOpen) {
setTimeout(() => {
setIsOpen(false);
}, 0);
}
}
return (
<div className="flex items-start">
<Select
menuIsOpen={isOpen}
onMenuOpen={() => setIsOpen(true)}
onMenuClose={() => setIsOpen(false)}
// onMenuOpen={() => setIsOpen(true)}
// onMenuClose={() => setIsOpen(false)}
options={filteredOptions}
onChange={handleChange}
styles={{
@ -77,11 +86,19 @@ function FunnelIssuesDropdown(props) {
IndicatorsContainer: (): any => null,
Control: ({ children, ...props }: any) => (
<components.Control {...props}>
{ children }
<button className="px-2 py-1 bg-white rounded-2xl border border-teal border-dashed color-teal flex items-center hover:bg-active-blue" onClick={() => setIsOpen(!isOpen)}>
<Icon name="funnel" size={16} color="teal" />
<span className="ml-2">Issues</span>
</button>
<OutsideClickDetectingDiv
// className={ cn("relative flex items-center", { "flex-1" : fullWidth }) }
onClickOutside={onClickOutside}
>
{ children }
<button
className="px-2 py-1 bg-white rounded-2xl border border-teal border-dashed color-teal flex items-center hover:bg-active-blue"
onClick={() => setIsOpen(!isOpen)}
>
<Icon name="funnel" size={16} color="teal" />
<span className="ml-2">Issues</span>
</button>
</OutsideClickDetectingDiv>
</components.Control>
),
Placeholder: (): any => null,

View file

@ -2,12 +2,15 @@ import { useStore } from 'App/mstore';
import { useObserver } from 'mobx-react-lite';
import React from 'react';
import FunnelIssuesListItem from '../FunnelIssuesListItem';
import { NoContent } from 'UI';
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
interface Props {
loading?: boolean;
issues: any;
}
function FunnelIssuesList(props: Props) {
const { issues } = props;
const { issues, loading } = props;
const { funnelStore } = useStore();
const issuesSort = useObserver(() => funnelStore.issuesSort);
const issuesFilter = useObserver(() => funnelStore.issuesFilter.map((issue: any) => issue.value));
@ -17,14 +20,22 @@ function FunnelIssuesList(props: Props) {
filteredIssues = useObserver(() => issuesSort.order === 'desc' ? filteredIssues.reverse() : filteredIssues);
return useObserver(() => (
<div>
<NoContent
show={!loading && filteredIssues.length === 0}
title={
<div className="flex flex-col items-center justify-center">
<AnimatedSVG name={ICONS.NO_RESULTS} size="170" />
<div className="mt-6 text-2xl">No issues found</div>
</div>
}
>
{filteredIssues.map((issue: any, index: React.Key) => (
<div key={index} className="mb-4">
<FunnelIssuesListItem issue={issue} />
</div>
))}
</div>
));
</NoContent>
))
}
export default FunnelIssuesList;

View file

@ -41,7 +41,6 @@ function WidgetChart(props: Props) {
const isTableWidget = metric.metricType === 'table' && metric.viewType === 'table';
const isPieChart = metric.metricType === 'table' && metric.viewType === 'pieChart';
const isFunnel = metric.metricType === 'funnel';
const onChartClick = (event: any) => {
if (event) {
@ -66,7 +65,6 @@ function WidgetChart(props: Props) {
}
const depsString = JSON.stringify(_metric.series);
const fetchMetricChartData = (metric: any, payload: any, isWidget: any) => {
if (!isMounted()) return;
setLoading(true)
@ -88,6 +86,7 @@ function WidgetChart(props: Props) {
debounceRequest(metric, payload, isWidget);
}, [period, depsString, _metric.page, metric.metricType, metric.metricOf, metric.viewType]);
const renderChart = () => {
const { metricType, viewType, metricOf } = metric;
@ -100,7 +99,7 @@ function WidgetChart(props: Props) {
}
if (metricType === 'funnel') {
return <FunnelWidget metric={metric} />
return <FunnelWidget metric={metric} isWidget={isWidget} />
}
if (metricType === 'predefined') {

View file

@ -145,7 +145,7 @@ function WidgetForm(props: Props) {
</>
)}
{metric.metricType === 'table' && (
{metric.metricType === 'table' && !(metric.metricOf === FilterKey.ERRORS || metric.metricOf === FilterKey.SESSIONS) && (
<>
<span className="mx-3">showing</span>
<Select

View file

@ -6,6 +6,7 @@ import { SegmentSelection } from 'UI';
import { useObserver } from 'mobx-react-lite';
import SelectDateRange from 'Shared/SelectDateRange';
import { FilterKey } from 'Types/filter/filterType';
// import Period, { LAST_24_HOURS, LAST_30_DAYS } from 'Types/app/period';
interface Props {
className?: string;
@ -13,16 +14,21 @@ interface Props {
function WidgetPreview(props: Props) {
const { className = '' } = props;
const { metricStore, dashboardStore } = useStore();
const period = useObserver(() => dashboardStore.period);
const metric: any = useObserver(() => metricStore.instance);
const isTimeSeries = metric.metricType === 'timeseries';
const isTable = metric.metricType === 'table';
// const drillDownFilter = useObserver(() => dashboardStore.drillDownFilter);
const disableVisualization = useObserver(() => metric.metricOf === FilterKey.SESSIONS || metric.metricOf === FilterKey.ERRORS);
const period = useObserver(() => dashboardStore.drillDownPeriod);
const chagneViewType = (e, { name, value }: any) => {
metric.update({ [ name ]: value });
}
const onChangePeriod = (period: any) => {
dashboardStore.setDrillDownPeriod(period);
}
return useObserver(() => (
<div className={cn(className)}>
<div className="flex items-center justify-between">
@ -39,8 +45,8 @@ function WidgetPreview(props: Props) {
onSelect={ chagneViewType }
value={{ value: metric.viewType }}
list={ [
{ value: 'lineChart', name: 'Chart', icon: 'graph-up-arrow' },
{ value: 'progress', name: 'Progress', icon: 'hash' },
{ value: 'lineChart', name: 'Chart', icon: 'graph-up-arrow' },
{ value: 'progress', name: 'Progress', icon: 'hash' },
]}
/>
</>
@ -69,7 +75,8 @@ function WidgetPreview(props: Props) {
<span className="mr-1 color-gray-medium">Time Range</span>
<SelectDateRange
period={period}
onChange={(period: any) => dashboardStore.setPeriod(period)}
// onChange={(period: any) => metric.setPeriod(period)}
onChange={onChangePeriod}
right={true}
/>
</div>

View file

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import { NoContent, Dropdown, Icon, Loader, Pagination } from 'UI';
import { NoContent, Loader, Pagination } from 'UI';
import Select from 'Shared/Select';
import cn from 'classnames';
import { useStore } from 'App/mstore';
@ -15,19 +15,29 @@ interface Props {
}
function WidgetSessions(props: Props) {
const { className = '' } = props;
const [activeSeries, setActiveSeries] = useState('all');
const [data, setData] = useState<any>([]);
const isMounted = useIsMounted()
const isMounted = useIsMounted();
const [loading, setLoading] = useState(false);
const filteredSessions = getListSessionsBySeries(data, activeSeries);
const { dashboardStore, metricStore } = useStore();
const filter = useObserver(() => dashboardStore.drillDownFilter);
const widget: any = useObserver(() => metricStore.instance);
const drillDownPeriod = useObserver(() => dashboardStore.drillDownPeriod);
const startTime = DateTime.fromMillis(filter.startTimestamp).toFormat('LLL dd, yyyy HH:mm a');
const endTime = DateTime.fromMillis(filter.endTimestamp).toFormat('LLL dd, yyyy HH:mm a');
const [timestamps, setTimestamps] = useState<any>({
startTimestamp: 0,
endTimestamp: 0,
});
const [seriesOptions, setSeriesOptions] = useState([
{ label: 'All', value: 'all' },
]);
const [activeSeries, setActiveSeries] = useState('all');
const writeOption = (e, { name, value }) => setActiveSeries(value.value);
const writeOption = ({ value }: any) => setActiveSeries(value.value);
useEffect(() => {
if (!data) return;
const seriesOptions = data.map(item => ({
const seriesOptions = data.map((item: any) => ({
label: item.seriesName,
value: item.seriesId,
}));
@ -37,22 +47,15 @@ function WidgetSessions(props: Props) {
]);
}, [data]);
const fetchSessions = (metricId, filter) => {
const fetchSessions = (metricId: any, filter: any) => {
if (!isMounted()) return;
setLoading(true)
widget.fetchSessions(metricId, filter).then(res => {
widget.fetchSessions(metricId, filter).then((res: any) => {
setData(res)
}).finally(() => {
setLoading(false)
});
}
const filteredSessions = getListSessionsBySeries(data, activeSeries);
const { dashboardStore, metricStore } = useStore();
const filter = useObserver(() => dashboardStore.drillDownFilter);
const widget: any = useObserver(() => metricStore.instance);
const startTime = DateTime.fromMillis(filter.startTimestamp).toFormat('LLL dd, yyyy HH:mm a');
const endTime = DateTime.fromMillis(filter.endTimestamp).toFormat('LLL dd, yyyy HH:mm a');
const debounceRequest: any = React.useCallback(debounce(fetchSessions, 1000), []);
const depsString = JSON.stringify(widget.series);
@ -60,6 +63,12 @@ function WidgetSessions(props: Props) {
debounceRequest(widget.metricId, { ...filter, series: widget.toJsonDrilldown(), page: metricStore.sessionsPage, limit: metricStore.sessionsPageSize });
}, [filter.startTimestamp, filter.endTimestamp, filter.filters, depsString, metricStore.sessionsPage]);
useEffect(() => {
const timestamps = drillDownPeriod.toTimestamps();
console.log('timestamps', timestamps);
debounceRequest(widget.metricId, { startTime: timestamps.startTimestamp, endTime: timestamps.endTimestamp, series: widget.toJsonDrilldown(), page: metricStore.sessionsPage, limit: metricStore.sessionsPageSize });
}, [drillDownPeriod]);
return useObserver(() => (
<div className={cn(className)}>
<div className="flex items-center justify-between">
@ -71,18 +80,6 @@ function WidgetSessions(props: Props) {
{ widget.metricType !== 'table' && (
<div className="flex items-center ml-6">
<span className="mr-2 color-gray-medium">Series</span>
{/* <Dropdown
// className={stl.dropdown}
className="font-medium flex items-center hover:bg-gray-light rounded px-2 py-1"
direction="left"
options={ seriesOptions }
name="change"
value={ activeSeries }
onChange={ writeOption }
id="change-dropdown"
// icon={null}
icon={ <Icon name="chevron-down" color="gray-dark" size="14" className="ml-2" /> }
/> */}
<Select
options={ seriesOptions }
onChange={ writeOption }
@ -102,7 +99,6 @@ function WidgetSessions(props: Props) {
</div>
}
show={filteredSessions.sessions.length === 0}
// animatedIcon="no-results"
>
{filteredSessions.sessions.map((session: any) => (
<SessionItem key={ session.sessionId } session={ session } />
@ -112,7 +108,7 @@ function WidgetSessions(props: Props) {
<Pagination
page={metricStore.sessionsPage}
totalPages={Math.ceil(filteredSessions.total / metricStore.sessionsPageSize)}
onPageChange={(page) => metricStore.updateKey('sessionsPage', page)}
onPageChange={(page: any) => metricStore.updateKey('sessionsPage', page)}
limit={metricStore.sessionsPageSize}
debounceRequest={500}
/>
@ -124,12 +120,12 @@ function WidgetSessions(props: Props) {
));
}
const getListSessionsBySeries = (data, seriesId) => {
const getListSessionsBySeries = (data: any, seriesId: any) => {
const arr: any = { sessions: [], total: 0 };
data.forEach(element => {
data.forEach((element: any) => {
if (seriesId === 'all') {
const sessionIds = arr.sessions.map(i => i.sessionId);
arr.sessions.push(...element.sessions.filter(i => !sessionIds.includes(i.sessionId)));
const sessionIds = arr.sessions.map((i: any) => i.sessionId);
arr.sessions.push(...element.sessions.filter((i: any) => !sessionIds.includes(i.sessionId)));
arr.total = element.total
} else {
if (element.seriesId === seriesId) {

View file

@ -18,14 +18,14 @@ interface Props {
}
function WidgetView(props: Props) {
const { match: { params: { siteId, dashboardId, metricId } } } = props;
const { metricStore } = useStore();
const { metricStore, dashboardStore } = useStore();
const widget = useObserver(() => metricStore.instance);
const loading = useObserver(() => metricStore.isLoading);
const [expanded, setExpanded] = useState(!metricId || metricId === 'create');
React.useEffect(() => {
if (metricId && metricId !== 'create') {
metricStore.fetch(metricId);
metricStore.fetch(metricId, dashboardStore.period);
} else if (metricId === 'create') {
metricStore.init();
}

View file

@ -8,27 +8,41 @@ import { useObserver } from 'mobx-react-lite';
interface Props {
metric: Widget;
isWidget?: boolean
}
function FunnelWidget(props: Props) {
const { metric } = props;
const { metric, isWidget = false } = props;
const funnel = metric.data.funnel || { stages: [] };
// pic firt and last from array
const totalSteps = funnel.stages.length;
const stages = isWidget ? [...funnel.stages.slice(0, 1), funnel.stages[funnel.stages.length - 1]] : funnel.stages;
const hasMoreSteps = funnel.stages.length > 2;
const lastStage = funnel.stages[funnel.stages.length - 1];
return useObserver(() => (
<>
<div className="w-full">
{funnel.stages.map((filter: any, index: any) => (
<div key={index} className={cn("flex items-start mb-4", stl.step, { [stl['step-disabled']] : !filter.isActive })}>
<div className="z-10 w-6 h-6 border mr-4 text-sm rounded-full bg-gray-lightest flex items-center justify-center leading-3">
{index + 1}
</div>
<Funnelbar key={index} filter={filter} />
<div className="self-end flex items-center justify-center ml-4" style={{ marginBottom: '49px'}}>
<button onClick={() => filter.updateKey('isActive', !filter.isActive)}>
<Icon name="eye-slash-fill" color={filter.isActive ? "gray-light" : "gray-darkest"} size="22" />
</button>
</div>
</div>
))}
{ !isWidget && (
stages.map((filter: any, index: any) => (
<Stage key={index} index={index + 1} isWidget={isWidget} stage={filter} />
))
)}
{ isWidget && (
<>
<Stage index={1} isWidget={isWidget} stage={stages[0]} />
{ hasMoreSteps && (
<>
<EmptyStage total={totalSteps} />
</>
)}
{funnel.stages.length > 1 && (
<Stage index={totalSteps} isWidget={isWidget} stage={lastStage} />
)}
</>
)}
</div>
<div className="flex items-center pb-4">
<div className="flex items-center">
@ -59,4 +73,45 @@ function FunnelWidget(props: Props) {
));
}
function EmptyStage({ total }: any) {
return useObserver( () => (
<div className={cn("flex items-center mb-4 pb-3", stl.step)}>
<IndexNumber index={0} />
<div className="w-fit px-2 border border-teal py-1 text-center justify-center bg-teal-lightest flex items-center rounded-full color-teal" style={{ width: '100px'}}>+{total} steps</div>
<div className="border-b w-full border-dotted"></div>
</div>
))
}
function Stage({ stage, index, isWidget }: any) {
return useObserver( () => (
<div className={cn("flex items-start", stl.step, { [stl['step-disabled']] : !stage.isActive })}>
<IndexNumber index={index } />
<Funnelbar filter={stage} />
{!isWidget && (
<BarActions bar={stage} />
)}
</div>
))
}
function IndexNumber({ index }: any) {
return (
<div className="z-10 w-6 h-6 border mr-4 text-sm rounded-full bg-gray-lightest flex items-center justify-center leading-3">
{index}
</div>
);
}
function BarActions({ bar }: any) {
return useObserver(() => (
<div className="self-end flex items-center justify-center ml-4" style={{ marginBottom: '49px'}}>
<button onClick={() => bar.updateKey('isActive', !bar.isActive)}>
<Icon name="eye-slash-fill" color={bar.isActive ? "gray-light" : "gray-darkest"} size="22" />
</button>
</div>
))
}
export default FunnelWidget;

View file

@ -20,6 +20,7 @@ export interface IDashboardSotre {
endTimestamp: number
period: Period
drillDownFilter: IFilter
drillDownPeriod: Period
siteId: any
currentWidget: Widget
@ -84,6 +85,7 @@ export default class DashboardStore implements IDashboardSotre {
widgets: Widget[] = []
period: Period = Period({ rangeName: LAST_30_DAYS })
drillDownFilter: Filter = new Filter()
drillDownPeriod: Period = Period({ rangeName: LAST_30_DAYS });
startTimestamp: number = 0
endTimestamp: number = 0
@ -107,6 +109,7 @@ export default class DashboardStore implements IDashboardSotre {
drillDownFilter: observable.ref,
widgetCategories: observable.ref,
selectedDashboard: observable.ref,
drillDownPeriod: observable,
resetCurrentWidget: action,
addDashboard: action,
removeDashboard: action,
@ -130,13 +133,15 @@ export default class DashboardStore implements IDashboardSotre {
fetchTemplates: action,
updatePinned: action,
setPeriod: action,
setDrillDownPeriod: action,
fetchMetricChartData: action
})
const drillDownPeriod = Period({ rangeName: LAST_30_DAYS }).toTimestamps();
this.drillDownFilter.updateKey('startTimestamp', drillDownPeriod.startTimestamp)
this.drillDownFilter.updateKey('endTimestamp', drillDownPeriod.endTimestamp)
this.drillDownPeriod = Period({ rangeName: LAST_24_HOURS });
const timeStamps = this.drillDownPeriod.toTimestamps();
this.drillDownFilter.updateKey('startTimestamp', timeStamps.startTimestamp)
this.drillDownFilter.updateKey('endTimestamp', timeStamps.endTimestamp)
}
toggleAllSelectedWidgets(isSelected: boolean) {
@ -434,6 +439,10 @@ export default class DashboardStore implements IDashboardSotre {
this.period = new Period({ start: period.startDate, end: period.endDate, rangeName: period.rangeName })
}
setDrillDownPeriod(period: any) {
this.drillDownPeriod = new Period({ start: period.startDate, end: period.endDate, rangeName: period.rangeName })
}
fetchMetricChartData(metric: IWidget, data: any, isWidget: boolean = false): Promise<any> {
const period = this.period.toTimestamps()
const params = { ...period, ...data, key: metric.predefinedKey }

View file

@ -78,14 +78,6 @@ export default class MetricStore implements IMetricStore {
paginatedList: computed,
})
// reaction(
// () => this.metricsSearch,
// (metricsSearch) => { // TODO filter the list for View
// this.page = 1
// this.paginatedList
// }
// )
}
// State Actions
@ -172,11 +164,14 @@ export default class MetricStore implements IMetricStore {
})
}
fetch(id: string) {
fetch(id: string, period?: any) {
this.isLoading = true
return metricService.getMetric(id)
.then((metric: any) => {
return this.instance = new Widget().fromJson(metric)
// if (period) {
// metric.period = period
// }
return this.instance = new Widget().fromJson(metric, period)
}).finally(() => {
this.isLoading = false
})

View file

@ -6,6 +6,7 @@ import Session from "App/mstore/types/session";
import Funnelissue from 'App/mstore/types/funnelIssue';
import { issueOptions } from 'App/constants/filterOptions';
import { FilterKey } from 'Types/filter/filterType';
import Period, { LAST_24_HOURS, LAST_30_DAYS } from 'Types/app/period';
export interface IWidget {
metricId: any
@ -40,6 +41,8 @@ export interface IWidget {
params: any
period: any
updateKey(key: string, value: any): void
removeSeries(index: number): void
addSeries(): void
@ -52,6 +55,7 @@ export interface IWidget {
toWidget(): any
setData(data: any): void
fetchSessions(metricId: any, filter: any): Promise<any>
setPeriod(period: Period): void
}
export default class Widget implements IWidget {
public static get ID_KEY():string { return "metricId" }
@ -75,6 +79,8 @@ export default class Widget implements IWidget {
page: number = 1
limit: number = 5
params: any = { density: 70 }
period: any = Period({ rangeName: LAST_24_HOURS }) // temp value in detail view
sessionsLoading: boolean = false
@ -117,6 +123,7 @@ export default class Widget implements IWidget {
validate: action,
update: action,
updateKey: action,
setPeriod: action,
})
const filterSeries = new FilterSeries()
@ -137,7 +144,7 @@ export default class Widget implements IWidget {
this.series.push(series)
}
fromJson(json: any) {
fromJson(json: any, period?: any) {
json.config = json.config || {}
runInAction(() => {
this.metricId = json.metricId
@ -155,10 +162,18 @@ export default class Widget implements IWidget {
this.config = json.config
this.position = json.config.position
this.predefinedKey = json.predefinedKey
if (period) {
this.period = period
}
})
return this
}
setPeriod(period: any) {
this.period = new Period({ start: period.startDate, end: period.endDate, rangeName: period.rangeName })
}
toWidget(): any {
return {
config: {
@ -186,7 +201,7 @@ export default class Widget implements IWidget {
series: this.series.map((series: any) => series.toJson()),
config: {
...this.config,
col: this.metricType === 'funnel' || this.metricOf === FilterKey.ERRORS ? 4 : this.config.col
col: this.metricType === 'funnel' || this.metricOf === FilterKey.ERRORS || this.metricOf === FilterKey.SESSIONS ? 4 : this.config.col
},
}
}

View file

@ -96,6 +96,14 @@ export default Record({
end: range.end.unix() * 1000,
}
},
// fromFilter: filter => {
// const range = getRange(filter.rangeName);
// return {
// start: range.start.unix() * 1000,
// end: range.end.unix() * 1000,
// rangeName: filter.rangeName,
// }
// },
methods: {
toJSON() {
return {