diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTableSessions/CustomMetricTableSessions.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTableSessions/CustomMetricTableSessions.tsx
index 45cbd198a..8e2a56004 100644
--- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTableSessions/CustomMetricTableSessions.tsx
+++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricTableSessions/CustomMetricTableSessions.tsx
@@ -1,6 +1,8 @@
+import { useObserver } from 'mobx-react-lite';
import React from 'react';
import SessionItem from 'Shared/SessionItem';
import { Pagination } from 'UI';
+import { useStore } from 'App/mstore';
const PER_PAGE = 10;
interface Props {
@@ -11,8 +13,10 @@ interface Props {
}
function CustomMetricTableSessions(props: Props) {
- const { data = { sessions: [], total: 0 }, isEdit = false, metric = {}, isTemplate } = props;
+ const { data = { sessions: [], total: 0 }, isEdit = false } = props;
const currentPage = 1;
+ const { metricStore } = useStore();
+ const metric: any = useObserver(() => metricStore.instance);
return (
@@ -25,7 +29,7 @@ function CustomMetricTableSessions(props: Props) {
this.props.updateCurrentPage(page)}
+ onPageChange={(page: any) => metric.updateKey('page', page)}
limit={PER_PAGE}
debounceRequest={500}
/>
diff --git a/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx b/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx
index 83894d299..5df1873fe 100644
--- a/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx
+++ b/frontend/app/components/Dashboard/components/WidgetChart/WidgetChart.tsx
@@ -84,7 +84,7 @@ function WidgetChart(props: Props) {
prevMetricRef.current = metric;
const payload = isWidget ? { ...params } : { ...metricParams, ...metric.toJson() };
debounceRequest(metric, payload, isWidget);
- }, [period, depsString]);
+ }, [period, depsString, _metric.page]);
const renderChart = () => {
const { metricType, viewType, metricOf } = metric;
@@ -131,19 +131,24 @@ function WidgetChart(props: Props) {
if (metricType === 'table') {
if (metricOf === 'SESSIONS') {
- return
+ )
}
if (viewType === 'table') {
- return ;
+ return (
+
+ )
} else if (viewType === 'pieChart') {
return (
{
const wasCreating = !metric.exists()
- metricStore.save(metric, dashboardId).then((metric: any) => {
- if (wasCreating) {
- if (parseInt(dashboardId) > 0) {
- history.replace(withSiteId(dashboardMetricDetails(parseInt(dashboardId), metric.metricId), siteId));
- } else {
- history.replace(withSiteId(metricDetails(metric.metricId), siteId));
+ metricStore.save(metric, dashboardId)
+ .then((metric: any) => {
+ if (wasCreating) {
+ if (parseInt(dashboardId) > 0) {
+ history.replace(withSiteId(dashboardMetricDetails(parseInt(dashboardId), metric.metricId), siteId));
+ } else {
+ history.replace(withSiteId(metricDetails(metric.metricId), siteId));
+ }
}
- }
- });
+ });
}
const onDelete = async () => {
diff --git a/frontend/app/components/Dashboard/components/WidgetPreview/WidgetPreview.tsx b/frontend/app/components/Dashboard/components/WidgetPreview/WidgetPreview.tsx
index 679da3944..75e6eb270 100644
--- a/frontend/app/components/Dashboard/components/WidgetPreview/WidgetPreview.tsx
+++ b/frontend/app/components/Dashboard/components/WidgetPreview/WidgetPreview.tsx
@@ -5,6 +5,7 @@ import { useStore } from 'App/mstore';
import { SegmentSelection } from 'UI';
import { useObserver } from 'mobx-react-lite';
import SelectDateRange from 'Shared/SelectDateRange';
+import { FilterKey } from 'Types/filter/filterType';
interface Props {
className?: string;
@@ -16,6 +17,7 @@ function WidgetPreview(props: Props) {
const metric: any = useObserver(() => metricStore.instance);
const isTimeSeries = metric.metricType === 'timeseries';
const isTable = metric.metricType === 'table';
+ const disableVisualization = useObserver(() => metric.metricOf === FilterKey.SESSIONS || metric.metricOf === FilterKey.ERRORS);
const chagneViewType = (e, { name, value }: any) => {
metric.update({ [ name ]: value });
@@ -55,9 +57,11 @@ function WidgetPreview(props: Props) {
onSelect={ chagneViewType }
value={{ value: metric.viewType }}
list={[
- { value: 'table', name: 'Table', icon: 'table' },
- { value: 'pieChart', name: 'Chart', icon: 'pie-chart-fill' },
+ { value: 'table', name: 'Table', icon: 'table' },
+ { value: 'pieChart', name: 'Chart', icon: 'pie-chart-fill' },
]}
+ disabled={disableVisualization}
+ disabledMessage="Chart view is not supported"
/>
>
)}
diff --git a/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx b/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx
index 27d3b292c..338204f8a 100644
--- a/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx
+++ b/frontend/app/components/Dashboard/components/WidgetView/WidgetView.tsx
@@ -10,6 +10,7 @@ import WidgetName from '../WidgetName';
import { withSiteId } from 'App/routes';
import FunnelIssues from '../Funnels/FunnelIssues/FunnelIssues';
import Breadcrumb from 'Shared/Breadcrumb';
+import { FilterKey } from 'Types/filter/filterType';
interface Props {
history: any;
match: any
@@ -80,7 +81,7 @@ function WidgetView(props: Props) {
- { widget.metricOf !== 'SESSIONS' && widget.metricOf !== 'ERRORS' && (
+ { widget.metricOf !== FilterKey.SESSIONS && widget.metricOf !== FilterKey.ERRORS && (
<>
{ (widget.metricType === 'table' || widget.metricType === 'timeseries') && }
{ widget.metricType === 'funnel' && }
diff --git a/frontend/app/components/Session_/Player/Controls/Controls.js b/frontend/app/components/Session_/Player/Controls/Controls.js
index 48f738247..d42cff222 100644
--- a/frontend/app/components/Session_/Player/Controls/Controls.js
+++ b/frontend/app/components/Session_/Player/Controls/Controls.js
@@ -164,7 +164,6 @@ export default class Controls extends React.Component {
}
onKeyDown = (e) => {
- console.log(e.key, e.target)
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) {
return;
}
diff --git a/frontend/app/components/shared/SelectDateRange/SelectDateRange.tsx b/frontend/app/components/shared/SelectDateRange/SelectDateRange.tsx
index 13573b4d5..107c87337 100644
--- a/frontend/app/components/shared/SelectDateRange/SelectDateRange.tsx
+++ b/frontend/app/components/shared/SelectDateRange/SelectDateRange.tsx
@@ -5,6 +5,7 @@ import Period, { LAST_7_DAYS } from 'Types/app/period';
import { components } from 'react-select';
import DateRangePopup from 'Shared/DateRangeDropdown/DateRangePopup';
import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv';
+import cn from 'classnames';
interface Props {
period: any,
diff --git a/frontend/app/components/ui/SegmentSelection/SegmentSelection.js b/frontend/app/components/ui/SegmentSelection/SegmentSelection.js
index feebd694a..dde4d6b7c 100644
--- a/frontend/app/components/ui/SegmentSelection/SegmentSelection.js
+++ b/frontend/app/components/ui/SegmentSelection/SegmentSelection.js
@@ -1,5 +1,5 @@
import React from 'react';
-import { Icon } from 'UI';
+import { Icon, Popup } from 'UI';
import cn from 'classnames';
import styles from './segmentSelection.module.css';
@@ -9,29 +9,35 @@ class SegmentSelection extends React.Component {
}
render() {
- const { className, list, small = false, extraSmall = false, primary = false, size = "normal", icons = false } = this.props;
+ const { className, list, small = false, extraSmall = false, primary = false, size = "normal", icons = false, disabled = false, disabledMessage = 'Not Allowed' } = this.props;
return (
-
- { list.map(item => (
-
!item.disabled && this.setActiveItem(item) }
- >
- { item.icon &&
}
-
{ item.name }
-
- ))
- }
-
+
+ { list.map(item => (
+
!item.disabled && this.setActiveItem(item) }
+ >
+ { item.icon &&
}
+
{ item.name }
+
+ ))
+ }
+
+
);
}
}
diff --git a/frontend/app/components/ui/SegmentSelection/segmentSelection.module.css b/frontend/app/components/ui/SegmentSelection/segmentSelection.module.css
index 907f81e37..082e675c9 100644
--- a/frontend/app/components/ui/SegmentSelection/segmentSelection.module.css
+++ b/frontend/app/components/ui/SegmentSelection/segmentSelection.module.css
@@ -5,6 +5,7 @@
border: solid thin $gray-light;
border-radius: 3px;
overflow: hidden;
+ user-select: none;
& .item {
color: $gray-medium;
@@ -79,4 +80,10 @@
.icons .item {
padding: 4px !important;
font-size: 12px;
+}
+
+.disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ pointer-events: none;
}
\ No newline at end of file
diff --git a/frontend/app/mstore/dashboardStore.ts b/frontend/app/mstore/dashboardStore.ts
index 6ea803c82..98e0c5e78 100644
--- a/frontend/app/mstore/dashboardStore.ts
+++ b/frontend/app/mstore/dashboardStore.ts
@@ -434,8 +434,15 @@ export default class DashboardStore implements IDashboardSotre {
fetchMetricChartData(metric: IWidget, data: any, isWidget: boolean = false): Promise {
const period = this.period.toTimestamps()
+ const params = { ...period, ...data, key: metric.predefinedKey }
+
+ if (metric.page && metric.limit) {
+ params['page'] = metric.page
+ params['limit'] = metric.limit
+ }
+
return new Promise((resolve, reject) => {
- return metricService.getMetricChartData(metric, { ...period, ...data, key: metric.predefinedKey, page: 1, limit: 10 }, isWidget)
+ return metricService.getMetricChartData(metric, params, isWidget)
.then((data: any) => {
if (metric.metricType === 'predefined' && metric.viewType === 'overview') {
const _data = { ...data, chart: getChartFormatter(this.period)(data.chart) }
diff --git a/frontend/app/mstore/types/widget.ts b/frontend/app/mstore/types/widget.ts
index b343b529f..de01ad834 100644
--- a/frontend/app/mstore/types/widget.ts
+++ b/frontend/app/mstore/types/widget.ts
@@ -33,10 +33,13 @@ export interface IWidget {
dashboardId: any
colSpan: number
predefinedKey: string
+
+ page: number
+ limit: number
params: any
- udpateKey(key: string, value: any): void
+ updateKey(key: string, value: any): void
removeSeries(index: number): void
addSeries(): void
fromJson(json: any): void
@@ -68,6 +71,8 @@ export default class Widget implements IWidget {
dashboards: any[] = []
dashboardIds: any[] = []
config: any = {}
+ page: number = 1
+ limit: number = 5
params: any = { density: 70 }
sessionsLoading: boolean = false
@@ -100,6 +105,7 @@ export default class Widget implements IWidget {
dashboardId: observable,
colSpan: observable,
series: observable,
+ page: observable,
addSeries: action,
removeSeries: action,
@@ -107,14 +113,14 @@ export default class Widget implements IWidget {
toJson: action,
validate: action,
update: action,
- udpateKey: action,
+ updateKey: action,
})
const filterSeries = new FilterSeries()
this.series.push(filterSeries)
}
- udpateKey(key: string, value: any) {
+ updateKey(key: string, value: any) {
this[key] = value
}
diff --git a/frontend/app/services/MetricService.ts b/frontend/app/services/MetricService.ts
index 3bc4d4ef9..cfab5ae39 100644
--- a/frontend/app/services/MetricService.ts
+++ b/frontend/app/services/MetricService.ts
@@ -1,6 +1,7 @@
import Widget, { IWidget } from "App/mstore/types/widget";
import APIClient from 'App/api_client';
import { IFilter } from "App/mstore/types/filter";
+import { fetchErrorCheck } from "App/utils";
export interface IMetricService {
initClient(client?: APIClient): void;
@@ -59,8 +60,8 @@ export default class MetricService implements IMetricService {
const method = isCreating ? 'post' : 'put';
const url = isCreating ? '/metrics' : '/metrics/' + data[Widget.ID_KEY];
return this.client[method](url, data)
- .then((response: { json: () => any; }) => response.json())
- .then((response: { data: any; }) => response.data || {});
+ .then(fetchErrorCheck)
+ .then((response: { data: any; }) => response.data || {})
}
/**
diff --git a/frontend/app/types/filter/filterType.ts b/frontend/app/types/filter/filterType.ts
index 4194b759b..772bea55e 100644
--- a/frontend/app/types/filter/filterType.ts
+++ b/frontend/app/types/filter/filterType.ts
@@ -93,5 +93,5 @@ export enum FilterKey {
GRAPHQL_RESPONSE_BODY = "GRAPHQL_RESPONSE_BODY",
SESSIONS = 'SESSIONS',
- ERRORS = 'ERRORS'
+ ERRORS = 'js_exception'
}
\ No newline at end of file
diff --git a/frontend/app/utils.ts b/frontend/app/utils.ts
index 39b9cd3f7..4a2b57a56 100644
--- a/frontend/app/utils.ts
+++ b/frontend/app/utils.ts
@@ -308,4 +308,11 @@ export const exportCSVFile = (headers, items, fileTitle) => {
document.body.removeChild(link);
}
}
-}
\ No newline at end of file
+}
+
+export const fetchErrorCheck = (response: any) => {
+ if (!response.ok) {
+ throw Error(response.statusText);
+ }
+ return response.json();
+}