ui: fix crashes related to metric type changes
This commit is contained in:
parent
2136f87a27
commit
34a51adfc2
7 changed files with 112 additions and 58 deletions
|
|
@ -15,7 +15,7 @@ function ClickMapCard() {
|
|||
|
||||
const sessionId = metricStore.instance.data.sessionId;
|
||||
const url = metricStore.instance.data.path;
|
||||
const operator = metricStore.instance.series[0].filter.filters[0].operator
|
||||
const operator = metricStore.instance.series[0]?.filter.filters[0]?.operator ? metricStore.instance.series[0].filter.filters[0].operator : 'startsWith'
|
||||
|
||||
|
||||
React.useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ function CategoryTab({ tab, inCards }: { tab: string; inCards?: boolean }) {
|
|||
metricType: selectedCard.cardType,
|
||||
name: selectedCard.title,
|
||||
metricOf: selectedCard.metricOf,
|
||||
category: card,
|
||||
};
|
||||
|
||||
if (selectedCard.filters) {
|
||||
|
|
@ -166,12 +167,14 @@ function CategoryTab({ tab, inCards }: { tab: string; inCards?: boolean }) {
|
|||
// TODO This code here makes 0 sense
|
||||
if (selectedCard.cardType === FUNNEL) {
|
||||
cardData.series = [];
|
||||
cardData.series.filter = [];
|
||||
cardData.series.push(new FilterSeries());
|
||||
cardData.series[0].filter.addFunnelDefaultFilters();
|
||||
cardData.series[0].filter.eventsOrder = 'then';
|
||||
cardData.series[0].filter.eventsOrderSupport = ['then'];
|
||||
}
|
||||
|
||||
metricStore.setCardCategory(tab);
|
||||
metricStore.merge(cardData);
|
||||
metricStore.instance.resetDefaults();
|
||||
|
||||
if (projectsStore.activeSiteId) {
|
||||
if (inCards) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import AddCardSection from '../AddCardSection/AddCardSection';
|
|||
import cn from 'classnames';
|
||||
import { Button, Popover } from 'antd'
|
||||
import { PlusOutlined } from '@ant-design/icons'
|
||||
import { Loader } from 'UI';
|
||||
|
||||
interface Props {
|
||||
siteId: string;
|
||||
|
|
|
|||
|
|
@ -6,9 +6,12 @@ import { tabItems } from 'Components/Dashboard/components/AddCardSection/AddCard
|
|||
import {
|
||||
CARD_LIST,
|
||||
} from 'Components/Dashboard/components/DashboardList/NewDashModal/ExampleCards';
|
||||
import FilterSeries from "App/mstore/types/filterSeries";
|
||||
import { FUNNEL, USER_PATH } from "App/constants/card";
|
||||
|
||||
function MetricTypeSelector() {
|
||||
const { metricStore } = useStore();
|
||||
const [selectedCategory, setSelectedCategory] = React.useState<string | null>(null);
|
||||
const metric = metricStore.instance;
|
||||
const cardCategory = metricStore.cardCategory;
|
||||
if (!cardCategory) {
|
||||
|
|
@ -18,22 +21,60 @@ function MetricTypeSelector() {
|
|||
value: opt.type,
|
||||
icon: opt.icon,
|
||||
}))
|
||||
React.useEffect(() => {
|
||||
const selected = metric.category ? { value: metric.category } : options.find(
|
||||
(i) => {
|
||||
if (metric.metricType === 'table') {
|
||||
return i.value === metric.metricOf;
|
||||
}
|
||||
return i.value === metric.metricType
|
||||
})
|
||||
if (selected) {
|
||||
setSelectedCategory(selected.value);
|
||||
}
|
||||
}, [])
|
||||
|
||||
const onChange = (type: string) => {
|
||||
const selectedCard = CARD_LIST.find((i) => i.key === type);
|
||||
|
||||
if (selectedCard) {
|
||||
metricStore.changeType(selectedCard.cardType, selectedCard.metricOf);
|
||||
setSelectedCategory(type);
|
||||
metricStore.init();
|
||||
const cardData: Record<string, any> = {
|
||||
metricType: selectedCard.cardType,
|
||||
name: selectedCard.title,
|
||||
metricOf: selectedCard.metricOf,
|
||||
series: [new FilterSeries()],
|
||||
category: type,
|
||||
}
|
||||
if (selectedCard.filters) {
|
||||
cardData.series = [
|
||||
new FilterSeries().fromJson({
|
||||
name: "Series 1",
|
||||
filter: {
|
||||
filters: selectedCard.filters,
|
||||
}
|
||||
})
|
||||
];
|
||||
}
|
||||
if (selectedCard.cardType === USER_PATH) {
|
||||
cardData.series = [];
|
||||
cardData.series.push(new FilterSeries());
|
||||
}
|
||||
if (selectedCard.cardType === FUNNEL) {
|
||||
cardData.series = [];
|
||||
cardData.series.push(new FilterSeries());
|
||||
cardData.series[0].filter.addFunnelDefaultFilters();
|
||||
cardData.series[0].filter.eventsOrder = 'then';
|
||||
cardData.series[0].filter.eventsOrderSupport = ['then'];
|
||||
}
|
||||
|
||||
metricStore.merge(cardData);
|
||||
}
|
||||
};
|
||||
|
||||
const selected = options.find(
|
||||
(i) => {
|
||||
if (metric.metricType === 'table') {
|
||||
return i.value === metric.metricOf;
|
||||
}
|
||||
return i.value === metric.metricType
|
||||
}) || options[0];
|
||||
return (
|
||||
<Segmented onChange={onChange} options={options} value={selected.value} />
|
||||
<Segmented onChange={onChange} options={options} value={selectedCategory} />
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ function WidgetChart(props: Props) {
|
|||
});
|
||||
const { isSaved = false, metric, isTemplate } = props;
|
||||
const { dashboardStore, metricStore } = useStore();
|
||||
const _metric: any = metricStore.instance;
|
||||
const _metric: any = props.isPreview ? metricStore.instance : props.metric;
|
||||
const data = _metric.data;
|
||||
const period = dashboardStore.period;
|
||||
const drillDownPeriod = dashboardStore.drillDownPeriod;
|
||||
|
|
@ -65,9 +65,9 @@ function WidgetChart(props: Props) {
|
|||
const [compData, setCompData] = useState<any>(null);
|
||||
const [enabledRows, setEnabledRows] = useState([]);
|
||||
const isTableWidget =
|
||||
metric.metricType === 'table' && metric.viewType === 'table';
|
||||
_metric.metricType === 'table' && _metric.viewType === 'table';
|
||||
const isPieChart =
|
||||
metric.metricType === 'table' && metric.viewType === 'pieChart';
|
||||
_metric.metricType === 'table' && _metric.viewType === 'pieChart';
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
|
|
@ -147,17 +147,17 @@ function WidgetChart(props: Props) {
|
|||
);
|
||||
const loadPage = () => {
|
||||
if (!inView) return;
|
||||
if (prevMetricRef.current && prevMetricRef.current.name !== metric.name) {
|
||||
prevMetricRef.current = metric;
|
||||
if (prevMetricRef.current && prevMetricRef.current.name !== _metric.name) {
|
||||
prevMetricRef.current = _metric;
|
||||
return;
|
||||
}
|
||||
prevMetricRef.current = metric;
|
||||
prevMetricRef.current = _metric;
|
||||
const timestmaps = drillDownPeriod.toTimestamps();
|
||||
const payload = isSaved
|
||||
? { ...metricParams }
|
||||
: { ...params, ...timestmaps, ...metric.toJson() };
|
||||
: { ...params, ...timestmaps, ..._metric.toJson() };
|
||||
debounceRequest(
|
||||
metric,
|
||||
_metric,
|
||||
payload,
|
||||
isSaved,
|
||||
!isSaved ? drillDownPeriod : period
|
||||
|
|
@ -172,11 +172,11 @@ function WidgetChart(props: Props) {
|
|||
const payload = {
|
||||
...params,
|
||||
...timestamps,
|
||||
...metric.toJson(),
|
||||
..._metric.toJson(),
|
||||
viewType: 'lineChart',
|
||||
};
|
||||
fetchMetricChartData(
|
||||
metric,
|
||||
_metric,
|
||||
payload,
|
||||
isSaved,
|
||||
dashboardStore.comparisonPeriod,
|
||||
|
|
@ -198,19 +198,19 @@ function WidgetChart(props: Props) {
|
|||
period,
|
||||
depsString,
|
||||
dashboardStore.selectedDensity,
|
||||
metric.metricType,
|
||||
metric.metricOf,
|
||||
metric.metricValue,
|
||||
metric.startType,
|
||||
metric.metricFormat,
|
||||
_metric.metricType,
|
||||
_metric.metricOf,
|
||||
_metric.metricValue,
|
||||
_metric.startType,
|
||||
_metric.metricFormat,
|
||||
inView,
|
||||
]);
|
||||
useEffect(loadPage, [_metric.page]);
|
||||
|
||||
const renderChart = React.useCallback(() => {
|
||||
const { metricType, metricOf } = metric;
|
||||
const viewType = metric.viewType;
|
||||
const metricWithData = { ...metric, data };
|
||||
const { metricType, metricOf } = _metric;
|
||||
const viewType = _metric.viewType;
|
||||
const metricWithData = { ..._metric, data };
|
||||
|
||||
if (metricType === FUNNEL) {
|
||||
if (viewType === 'table') {
|
||||
|
|
@ -250,7 +250,7 @@ function WidgetChart(props: Props) {
|
|||
|
||||
return (
|
||||
<FunnelWidget
|
||||
metric={metric}
|
||||
metric={_metric}
|
||||
data={data}
|
||||
compData={compData}
|
||||
isWidget={isSaved || isTemplate}
|
||||
|
|
@ -260,7 +260,7 @@ function WidgetChart(props: Props) {
|
|||
|
||||
if (metricType === 'predefined' || metricType === ERRORS) {
|
||||
const defaultMetric =
|
||||
metric.data.chart && metric.data.chart.length === 0
|
||||
_metric.data.chart && _metric.data.chart.length === 0
|
||||
? metricWithData
|
||||
: metric;
|
||||
return (
|
||||
|
|
@ -268,7 +268,7 @@ function WidgetChart(props: Props) {
|
|||
isTemplate={isTemplate}
|
||||
metric={defaultMetric}
|
||||
data={data}
|
||||
predefinedKey={metric.metricOf}
|
||||
predefinedKey={_metric.metricOf}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -288,7 +288,7 @@ function WidgetChart(props: Props) {
|
|||
params={params}
|
||||
onClick={onChartClick}
|
||||
label={
|
||||
metric.metricOf === 'sessionCount'
|
||||
_metric.metricOf === 'sessionCount'
|
||||
? 'Number of Sessions'
|
||||
: 'Number of Users'
|
||||
}
|
||||
|
|
@ -304,7 +304,7 @@ function WidgetChart(props: Props) {
|
|||
colors={colors}
|
||||
onClick={onChartClick}
|
||||
label={
|
||||
metric.metricOf === 'sessionCount'
|
||||
_metric.metricOf === 'sessionCount'
|
||||
? 'Number of Sessions'
|
||||
: 'Number of Users'
|
||||
}
|
||||
|
|
@ -321,7 +321,7 @@ function WidgetChart(props: Props) {
|
|||
colors={colors}
|
||||
onClick={onChartClick}
|
||||
label={
|
||||
metric.metricOf === 'sessionCount'
|
||||
_metric.metricOf === 'sessionCount'
|
||||
? 'Number of Sessions'
|
||||
: 'Number of Users'
|
||||
}
|
||||
|
|
@ -338,7 +338,7 @@ function WidgetChart(props: Props) {
|
|||
colors={colors}
|
||||
onClick={onChartClick}
|
||||
label={
|
||||
metric.metricOf === 'sessionCount'
|
||||
_metric.metricOf === 'sessionCount'
|
||||
? 'Number of Sessions'
|
||||
: 'Number of Users'
|
||||
}
|
||||
|
|
@ -349,12 +349,12 @@ function WidgetChart(props: Props) {
|
|||
return (
|
||||
<CustomMetricPieChart
|
||||
inGrid={!props.isPreview}
|
||||
metric={metric}
|
||||
metric={_metric}
|
||||
data={chartData}
|
||||
colors={colors}
|
||||
onClick={onChartClick}
|
||||
label={
|
||||
metric.metricOf === 'sessionCount'
|
||||
_metric.metricOf === 'sessionCount'
|
||||
? 'Number of Sessions'
|
||||
: 'Number of Users'
|
||||
}
|
||||
|
|
@ -369,7 +369,7 @@ function WidgetChart(props: Props) {
|
|||
colors={colors}
|
||||
params={params}
|
||||
label={
|
||||
metric.metricOf === 'sessionCount'
|
||||
_metric.metricOf === 'sessionCount'
|
||||
? 'Number of Sessions'
|
||||
: 'Number of Users'
|
||||
}
|
||||
|
|
@ -399,7 +399,7 @@ function WidgetChart(props: Props) {
|
|||
colors={colors}
|
||||
onClick={onChartClick}
|
||||
label={
|
||||
metric.metricOf === 'sessionCount'
|
||||
_metric.metricOf === 'sessionCount'
|
||||
? 'Number of Sessions'
|
||||
: 'Number of Users'
|
||||
}
|
||||
|
|
@ -412,7 +412,7 @@ function WidgetChart(props: Props) {
|
|||
if (metricOf === FilterKey.SESSIONS) {
|
||||
return (
|
||||
<CustomMetricTableSessions
|
||||
metric={metric}
|
||||
metric={_metric}
|
||||
data={data}
|
||||
isTemplate={isTemplate}
|
||||
isEdit={!isSaved && !isTemplate}
|
||||
|
|
@ -422,7 +422,7 @@ function WidgetChart(props: Props) {
|
|||
if (metricOf === FilterKey.ERRORS) {
|
||||
return (
|
||||
<CustomMetricTableErrors
|
||||
metric={metric}
|
||||
metric={_metric}
|
||||
data={data}
|
||||
// isTemplate={isTemplate}
|
||||
isEdit={!isSaved && !isTemplate}
|
||||
|
|
@ -432,7 +432,7 @@ function WidgetChart(props: Props) {
|
|||
if (viewType === TABLE) {
|
||||
return (
|
||||
<SessionsBy
|
||||
metric={metric}
|
||||
metric={_metric}
|
||||
data={data}
|
||||
onClick={onChartClick}
|
||||
isTemplate={isTemplate}
|
||||
|
|
@ -442,7 +442,7 @@ function WidgetChart(props: Props) {
|
|||
}
|
||||
if (metricType === HEATMAP) {
|
||||
if (!props.isPreview) {
|
||||
return metric.thumbnail ? (
|
||||
return _metric.thumbnail ? (
|
||||
<div
|
||||
style={{
|
||||
height: '229px',
|
||||
|
|
@ -450,7 +450,7 @@ function WidgetChart(props: Props) {
|
|||
marginBottom: '10px',
|
||||
}}
|
||||
>
|
||||
<img src={metric.thumbnail} alt="clickmap thumbnail" />
|
||||
<img src={_metric.thumbnail} alt="clickmap thumbnail" />
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
|
|
@ -497,7 +497,7 @@ function WidgetChart(props: Props) {
|
|||
}
|
||||
}
|
||||
return <div>Unknown metric type</div>;
|
||||
}, [data, compData, enabledRows, metric]);
|
||||
}, [data, compData, enabledRows, _metric]);
|
||||
|
||||
return (
|
||||
<div ref={ref}>
|
||||
|
|
@ -506,19 +506,19 @@ function WidgetChart(props: Props) {
|
|||
style={{
|
||||
minHeight: props.isPreview ? undefined : 240,
|
||||
paddingTop:
|
||||
props.isPreview && metric.metricType === TIMESERIES
|
||||
props.isPreview && _metric.metricType === TIMESERIES
|
||||
? '1.5rem'
|
||||
: 0,
|
||||
}}
|
||||
>
|
||||
{renderChart()}
|
||||
{props.isPreview && metric.metricType === TIMESERIES ? (
|
||||
{props.isPreview && _metric.metricType === TIMESERIES ? (
|
||||
<WidgetDatatable
|
||||
defaultOpen={metric.viewType === 'table'}
|
||||
defaultOpen={_metric.viewType === 'table'}
|
||||
data={data}
|
||||
enabledRows={enabledRows}
|
||||
setEnabledRows={setEnabledRows}
|
||||
metric={metric}
|
||||
metric={_metric}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -130,11 +130,13 @@ export default class MetricStore {
|
|||
merge(obj: any, updateChangeFlag: boolean = true) {
|
||||
const type = obj.metricType;
|
||||
|
||||
// handle metricType change
|
||||
if (obj.hasOwnProperty('metricType') && type !== this.instance.metricType) {
|
||||
this.instance.series.forEach((s: any, i: number) => {
|
||||
this.instance.series[i].filter.eventsOrderSupport = ['then', 'or', 'and']
|
||||
})
|
||||
if (type === HEATMAP && 'series' in obj) {
|
||||
delete obj['series']
|
||||
}
|
||||
this.changeType(type);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ export default class Widget {
|
|||
sessions: [],
|
||||
issues: [],
|
||||
total: 0,
|
||||
values: [],
|
||||
chart: [],
|
||||
namesMap: {},
|
||||
avg: 0,
|
||||
|
|
@ -261,7 +262,6 @@ export default class Widget {
|
|||
}
|
||||
|
||||
update(data: any) {
|
||||
console.log(this.data, data.data)
|
||||
runInAction(() => {
|
||||
Object.assign(this, data);
|
||||
});
|
||||
|
|
@ -295,6 +295,7 @@ export default class Widget {
|
|||
}
|
||||
|
||||
setData(data: { timestamp: number, [seriesName: string]: number}[], period: any, isComparison?: boolean) {
|
||||
if (!data) return;
|
||||
const _data: any = {};
|
||||
if (isComparison && this.metricType === TIMESERIES) {
|
||||
data.forEach((point, i) => {
|
||||
|
|
@ -306,6 +307,10 @@ export default class Widget {
|
|||
})
|
||||
}
|
||||
|
||||
if (this.metricType === HEATMAP) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.metricType === USER_PATH) {
|
||||
const _data = processData(data);
|
||||
Object.assign(this.data, _data);
|
||||
|
|
@ -342,10 +347,9 @@ export default class Widget {
|
|||
return unique;
|
||||
}, []);
|
||||
} else {
|
||||
const updatedData: any = data; // we don't use total anymore this.calculateTotalSeries(data);
|
||||
_data['chart'] = getChartFormatter(period)(updatedData);
|
||||
_data['namesMap'] = Array.isArray(updatedData)
|
||||
? updatedData
|
||||
_data['chart'] = getChartFormatter(period)(data);
|
||||
_data['namesMap'] = Array.isArray(data)
|
||||
? data
|
||||
.map((i) => Object.keys(i))
|
||||
.flat()
|
||||
.filter((i) => i !== 'time' && i !== 'timestamp')
|
||||
|
|
@ -359,8 +363,11 @@ export default class Widget {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (!isComparison) {
|
||||
Object.assign(this.data, _data);
|
||||
runInAction(() => {
|
||||
Object.assign(this.data, _data);
|
||||
})
|
||||
}
|
||||
return _data;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue