fix(dashboard): share overview (all widgets didnt work)
This commit is contained in:
@@ -10,11 +10,12 @@ import { AnimatedNumber } from '../animated-number';
|
||||
|
||||
export interface LiveCounterProps {
|
||||
projectId: string;
|
||||
shareId?: string;
|
||||
}
|
||||
|
||||
const FIFTEEN_SECONDS = 1000 * 30;
|
||||
|
||||
export function LiveCounter({ projectId }: LiveCounterProps) {
|
||||
export function LiveCounter({ projectId, shareId }: LiveCounterProps) {
|
||||
const trpc = useTRPC();
|
||||
const client = useQueryClient();
|
||||
const counter = useDebounceState(0, 1000);
|
||||
@@ -22,6 +23,7 @@ export function LiveCounter({ projectId }: LiveCounterProps) {
|
||||
const query = useQuery(
|
||||
trpc.overview.liveVisitors.queryOptions({
|
||||
projectId,
|
||||
shareId,
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -18,16 +18,18 @@ import {
|
||||
import { SerieIcon } from '../report-chart/common/serie-icon';
|
||||
interface OverviewLiveHistogramProps {
|
||||
projectId: string;
|
||||
shareId?: string;
|
||||
}
|
||||
|
||||
export function OverviewLiveHistogram({
|
||||
projectId,
|
||||
shareId,
|
||||
}: OverviewLiveHistogramProps) {
|
||||
const trpc = useTRPC();
|
||||
|
||||
// Use the new liveData endpoint instead of chart props
|
||||
const { data: liveData, isLoading } = useQuery(
|
||||
trpc.overview.liveData.queryOptions({ projectId }),
|
||||
trpc.overview.liveData.queryOptions({ projectId, shareId }),
|
||||
);
|
||||
|
||||
const totalSessions = liveData?.totalSessions ?? 0;
|
||||
|
||||
90
apps/start/src/components/overview/overview-map.tsx
Normal file
90
apps/start/src/components/overview/overview-map.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import { useEventQueryFilters } from '@/hooks/use-event-query-filters';
|
||||
import { useTRPC } from '@/integrations/trpc/react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useMemo } from 'react';
|
||||
import WorldMap from 'react-svg-worldmap';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import { useOverviewOptions } from './useOverviewOptions';
|
||||
|
||||
interface OverviewMapProps {
|
||||
projectId: string;
|
||||
shareId?: string;
|
||||
}
|
||||
|
||||
export function OverviewMap({ projectId, shareId }: OverviewMapProps) {
|
||||
const { range, startDate, endDate } = useOverviewOptions();
|
||||
const [filters, setFilter] = useEventQueryFilters();
|
||||
const trpc = useTRPC();
|
||||
|
||||
const query = useQuery(
|
||||
trpc.overview.map.queryOptions({
|
||||
projectId,
|
||||
shareId,
|
||||
range,
|
||||
filters,
|
||||
startDate,
|
||||
endDate,
|
||||
}),
|
||||
);
|
||||
|
||||
const mapData = useMemo(() => {
|
||||
if (!query.data) return [];
|
||||
|
||||
// Aggregate by country (sum counts for same country)
|
||||
const countryMap = new Map<string, number>();
|
||||
query.data.forEach((item) => {
|
||||
const country = item.country.toLowerCase();
|
||||
const current = countryMap.get(country) ?? 0;
|
||||
countryMap.set(country, current + item.count);
|
||||
});
|
||||
|
||||
return Array.from(countryMap.entries()).map(([country, value]) => ({
|
||||
country,
|
||||
value,
|
||||
}));
|
||||
}, [query.data]);
|
||||
|
||||
if (query.isLoading) {
|
||||
return (
|
||||
<div className="h-full w-full flex items-center justify-center">
|
||||
<div className="text-muted-foreground">Loading map...</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (query.isError) {
|
||||
return (
|
||||
<div className="h-full w-full flex items-center justify-center">
|
||||
<div className="text-muted-foreground">Error loading map</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!query.data || mapData.length === 0) {
|
||||
return (
|
||||
<div className="h-full w-full flex items-center justify-center">
|
||||
<div className="text-muted-foreground">No data available</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full w-full" style={{ minHeight: 300 }}>
|
||||
<AutoSizer disableHeight>
|
||||
{({ width }) => (
|
||||
<WorldMap
|
||||
onClickFunction={(event) => {
|
||||
if (event.countryCode) {
|
||||
setFilter('country', event.countryCode);
|
||||
}
|
||||
}}
|
||||
size={width}
|
||||
data={mapData}
|
||||
color={'var(--chart-0)'}
|
||||
borderColor={'var(--foreground)'}
|
||||
/>
|
||||
)}
|
||||
</AutoSizer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -36,6 +36,7 @@ import { OverviewMetricCard } from './overview-metric-card';
|
||||
|
||||
interface OverviewMetricsProps {
|
||||
projectId: string;
|
||||
shareId?: string;
|
||||
}
|
||||
|
||||
const TITLES = [
|
||||
@@ -83,7 +84,10 @@ const TITLES = [
|
||||
},
|
||||
] as const;
|
||||
|
||||
export default function OverviewMetrics({ projectId }: OverviewMetricsProps) {
|
||||
export default function OverviewMetrics({
|
||||
projectId,
|
||||
shareId,
|
||||
}: OverviewMetricsProps) {
|
||||
const { range, interval, metric, setMetric, startDate, endDate } =
|
||||
useOverviewOptions();
|
||||
const [filters] = useEventQueryFilters();
|
||||
@@ -93,6 +97,7 @@ export default function OverviewMetrics({ projectId }: OverviewMetricsProps) {
|
||||
const overviewQuery = useQuery(
|
||||
trpc.overview.stats.queryOptions({
|
||||
projectId,
|
||||
shareId,
|
||||
range,
|
||||
interval,
|
||||
filters,
|
||||
@@ -138,7 +143,7 @@ export default function OverviewMetrics({ projectId }: OverviewMetricsProps) {
|
||||
'col-span-4 min-h-16 flex-1 p-4 pb-0 shadow-[0_0_0_0.5px] shadow-border max-md:row-start-1 md:col-span-1',
|
||||
)}
|
||||
>
|
||||
<OverviewLiveHistogram projectId={projectId} />
|
||||
<OverviewLiveHistogram projectId={projectId} shareId={shareId} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -344,7 +349,7 @@ function Chart({
|
||||
onAnimationEnd={handleAnimationEnd}
|
||||
/>
|
||||
<Tooltip />
|
||||
<YAxis {...yAxisProps} domain={[0, 'dataMax']} width={25} />
|
||||
<YAxis {...yAxisProps} width={25} />
|
||||
<XAxis {...xAxisProps} />
|
||||
<CartesianGrid
|
||||
strokeDasharray="3 3"
|
||||
@@ -471,7 +476,12 @@ function Chart({
|
||||
<Tooltip />
|
||||
<YAxis
|
||||
{...yAxisProps}
|
||||
domain={[0, activeMetric.key === 'bounce_rate' ? 100 : 'dataMax']}
|
||||
domain={[
|
||||
0,
|
||||
activeMetric.key === 'bounce_rate'
|
||||
? 100
|
||||
: (dataMax: number) => Math.max(dataMax, 1),
|
||||
]}
|
||||
width={25}
|
||||
/>
|
||||
<YAxis
|
||||
@@ -480,14 +490,18 @@ function Chart({
|
||||
orientation="right"
|
||||
domain={[
|
||||
0,
|
||||
data.reduce(
|
||||
(max, item) => Math.max(max, item.total_revenue ?? 0),
|
||||
0,
|
||||
) * 2,
|
||||
Math.max(
|
||||
data.reduce(
|
||||
(max, item) => Math.max(max, item.total_revenue ?? 0),
|
||||
0,
|
||||
) * 1.2,
|
||||
1,
|
||||
),
|
||||
]}
|
||||
width={30}
|
||||
allowDataOverflow={false}
|
||||
/>
|
||||
<XAxis {...xAxisProps} />
|
||||
<XAxis {...xAxisProps} padding={{ left: 10, right: 10 }} />
|
||||
|
||||
<CartesianGrid
|
||||
strokeDasharray="3 3"
|
||||
@@ -523,19 +537,11 @@ function Chart({
|
||||
stroke={'oklch(from var(--foreground) l c h / 0.1)'}
|
||||
strokeWidth={2}
|
||||
isAnimationActive={false}
|
||||
dot={
|
||||
data.length > 90
|
||||
? false
|
||||
: {
|
||||
stroke: 'oklch(from var(--foreground) l c h / 0.1)',
|
||||
fill: 'transparent',
|
||||
strokeWidth: 1.5,
|
||||
r: 2,
|
||||
}
|
||||
}
|
||||
dot={false}
|
||||
activeDot={{
|
||||
stroke: 'oklch(from var(--foreground) l c h / 0.2)',
|
||||
fill: 'transparent',
|
||||
fill: 'var(--def-100)',
|
||||
fillOpacity: 1,
|
||||
strokeWidth: 1.5,
|
||||
r: 3,
|
||||
}}
|
||||
@@ -581,7 +587,8 @@ function Chart({
|
||||
? false
|
||||
: {
|
||||
stroke: getChartColor(0),
|
||||
fill: 'transparent',
|
||||
fill: 'var(--def-100)',
|
||||
fillOpacity: 1,
|
||||
strokeWidth: 1.5,
|
||||
r: 3,
|
||||
}
|
||||
|
||||
@@ -26,9 +26,11 @@ import { useOverviewWidget } from './useOverviewWidget';
|
||||
|
||||
interface OverviewTopDevicesProps {
|
||||
projectId: string;
|
||||
shareId?: string;
|
||||
}
|
||||
export default function OverviewTopDevices({
|
||||
projectId,
|
||||
shareId,
|
||||
}: OverviewTopDevicesProps) {
|
||||
const { interval, range, previous, startDate, endDate } =
|
||||
useOverviewOptions();
|
||||
@@ -325,6 +327,7 @@ export default function OverviewTopDevices({
|
||||
const query = useQuery(
|
||||
trpc.overview.topGeneric.queryOptions({
|
||||
projectId,
|
||||
shareId,
|
||||
range,
|
||||
filters,
|
||||
column: widget.key,
|
||||
@@ -337,6 +340,7 @@ export default function OverviewTopDevices({
|
||||
trpc.overview.topGenericSeries.queryOptions(
|
||||
{
|
||||
projectId,
|
||||
shareId,
|
||||
range,
|
||||
filters,
|
||||
column: widget.key,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { useEventQueryFilters } from '@/hooks/use-event-query-filters';
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import type { IReportInput } from '@openpanel/validation';
|
||||
|
||||
import { useTRPC } from '@/integrations/trpc/react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Widget, WidgetBody } from '../widget';
|
||||
@@ -17,17 +15,18 @@ import { useOverviewWidgetV2 } from './useOverviewWidget';
|
||||
|
||||
export interface OverviewTopEventsProps {
|
||||
projectId: string;
|
||||
shareId?: string;
|
||||
}
|
||||
|
||||
export default function OverviewTopEvents({
|
||||
projectId,
|
||||
shareId,
|
||||
}: OverviewTopEventsProps) {
|
||||
const { interval, range, previous, startDate, endDate } =
|
||||
useOverviewOptions();
|
||||
const { range, startDate, endDate } = useOverviewOptions();
|
||||
const [filters, setFilter] = useEventQueryFilters();
|
||||
const trpc = useTRPC();
|
||||
const { data: conversions } = useQuery(
|
||||
trpc.event.conversionNames.queryOptions({ projectId }),
|
||||
trpc.overview.topConversions.queryOptions({ projectId, shareId }),
|
||||
);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
|
||||
@@ -36,15 +35,7 @@ export default function OverviewTopEvents({
|
||||
title: 'Events',
|
||||
btn: 'Events',
|
||||
meta: {
|
||||
filters: [
|
||||
{
|
||||
id: 'ex_session',
|
||||
name: 'name',
|
||||
operator: 'isNot',
|
||||
value: ['session_start', 'session_end', 'screen_view'],
|
||||
},
|
||||
],
|
||||
eventName: '*',
|
||||
type: 'events' as const,
|
||||
},
|
||||
},
|
||||
conversions: {
|
||||
@@ -52,69 +43,84 @@ export default function OverviewTopEvents({
|
||||
btn: 'Conversions',
|
||||
hide: !conversions || conversions.length === 0,
|
||||
meta: {
|
||||
filters: [
|
||||
{
|
||||
id: 'conversion',
|
||||
name: 'name',
|
||||
operator: 'is',
|
||||
value: conversions?.map((c) => c.name) ?? [],
|
||||
},
|
||||
],
|
||||
eventName: '*',
|
||||
type: 'conversions' as const,
|
||||
},
|
||||
},
|
||||
link_out: {
|
||||
title: 'Link out',
|
||||
btn: 'Link out',
|
||||
meta: {
|
||||
filters: [],
|
||||
eventName: 'link_out',
|
||||
breakdownProperty: 'properties.href',
|
||||
type: 'linkOut' as const,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const report: IReportInput = useMemo(
|
||||
() => ({
|
||||
limit: 1000,
|
||||
// Use different endpoints based on widget type
|
||||
const eventsQuery = useQuery(
|
||||
trpc.overview.topEvents.queryOptions({
|
||||
projectId,
|
||||
shareId,
|
||||
range,
|
||||
startDate,
|
||||
endDate,
|
||||
series: [
|
||||
{
|
||||
type: 'event' as const,
|
||||
segment: 'event' as const,
|
||||
filters: [...filters, ...(widget.meta?.filters ?? [])],
|
||||
id: 'A',
|
||||
name: widget.meta?.eventName ?? '*',
|
||||
},
|
||||
],
|
||||
breakdowns: [
|
||||
{
|
||||
id: 'A',
|
||||
name: widget.meta?.breakdownProperty ?? 'name',
|
||||
},
|
||||
],
|
||||
chartType: 'bar' as const,
|
||||
interval,
|
||||
range,
|
||||
previous,
|
||||
metric: 'sum' as const,
|
||||
filters,
|
||||
excludeEvents:
|
||||
widget.meta?.type === 'events'
|
||||
? ['session_start', 'session_end', 'screen_view']
|
||||
: undefined,
|
||||
}),
|
||||
[projectId, startDate, endDate, filters, widget, interval, range, previous],
|
||||
);
|
||||
|
||||
const query = useQuery(trpc.chart.aggregate.queryOptions(report));
|
||||
const linkOutQuery = useQuery(
|
||||
trpc.overview.topLinkOut.queryOptions({
|
||||
projectId,
|
||||
shareId,
|
||||
range,
|
||||
startDate,
|
||||
endDate,
|
||||
filters,
|
||||
}),
|
||||
);
|
||||
|
||||
const tableData: EventTableItem[] = useMemo(() => {
|
||||
if (!query.data?.series) return [];
|
||||
// For link out, use href as name
|
||||
if (widget.meta?.type === 'linkOut') {
|
||||
if (!linkOutQuery.data) return [];
|
||||
return linkOutQuery.data.map((item) => ({
|
||||
id: item.href,
|
||||
name: item.href,
|
||||
count: item.count,
|
||||
}));
|
||||
}
|
||||
|
||||
return query.data.series.map((serie) => ({
|
||||
id: serie.id,
|
||||
name: serie.names[serie.names.length - 1] ?? serie.names[0] ?? '',
|
||||
count: serie.metrics.sum,
|
||||
// For events and conversions
|
||||
if (!eventsQuery.data) return [];
|
||||
|
||||
// For conversions, filter events by conversion names (client-side filtering)
|
||||
if (widget.meta?.type === 'conversions' && conversions) {
|
||||
const conversionNames = new Set(conversions.map((c) => c.name));
|
||||
return eventsQuery.data
|
||||
.filter((item) => conversionNames.has(item.name))
|
||||
.map((item) => ({
|
||||
id: item.name,
|
||||
name: item.name,
|
||||
count: item.count,
|
||||
}));
|
||||
}
|
||||
|
||||
// For regular events
|
||||
return eventsQuery.data.map((item) => ({
|
||||
id: item.name,
|
||||
name: item.name,
|
||||
count: item.count,
|
||||
}));
|
||||
}, [query.data]);
|
||||
}, [eventsQuery.data, linkOutQuery.data, widget.meta?.type, conversions]);
|
||||
|
||||
// Determine which query's loading state to use
|
||||
const isLoading =
|
||||
widget.meta?.type === 'linkOut'
|
||||
? linkOutQuery.isLoading
|
||||
: eventsQuery.isLoading;
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
if (!searchQuery.trim()) {
|
||||
@@ -150,14 +156,14 @@ export default function OverviewTopEvents({
|
||||
className="border-b-0 pb-2"
|
||||
/>
|
||||
<WidgetBody className="p-0">
|
||||
{query.isLoading ? (
|
||||
{isLoading ? (
|
||||
<OverviewWidgetTableLoading />
|
||||
) : (
|
||||
<OverviewWidgetTableEvents
|
||||
data={filteredData}
|
||||
onItemClick={(name) => {
|
||||
if (widget.meta?.breakdownProperty) {
|
||||
setFilter(widget.meta.breakdownProperty, name);
|
||||
if (widget.meta?.type === 'linkOut') {
|
||||
setFilter('properties.href', name);
|
||||
} else {
|
||||
setFilter('name', name);
|
||||
}
|
||||
|
||||
@@ -9,9 +9,7 @@ import { countries } from '@/translations/countries';
|
||||
import { NOT_SET_VALUE } from '@openpanel/constants';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { ChevronRightIcon } from 'lucide-react';
|
||||
import { ReportChart } from '../report-chart';
|
||||
import { SerieIcon } from '../report-chart/common/serie-icon';
|
||||
import { ReportChartShortcut } from '../report-chart/shortcut';
|
||||
import { Widget, WidgetBody } from '../widget';
|
||||
import { OVERVIEW_COLUMNS_NAME } from './overview-constants';
|
||||
import OverviewDetailsButton from './overview-details-button';
|
||||
@@ -19,6 +17,7 @@ import {
|
||||
OverviewLineChart,
|
||||
OverviewLineChartLoading,
|
||||
} from './overview-line-chart';
|
||||
import { OverviewMap } from './overview-map';
|
||||
import { OverviewViewToggle, useOverviewView } from './overview-view-toggle';
|
||||
import {
|
||||
WidgetFooter,
|
||||
@@ -34,8 +33,12 @@ import { useOverviewWidgetV2 } from './useOverviewWidget';
|
||||
|
||||
interface OverviewTopGeoProps {
|
||||
projectId: string;
|
||||
shareId?: string;
|
||||
}
|
||||
export default function OverviewTopGeo({ projectId }: OverviewTopGeoProps) {
|
||||
export default function OverviewTopGeo({
|
||||
projectId,
|
||||
shareId,
|
||||
}: OverviewTopGeoProps) {
|
||||
const { interval, range, previous, startDate, endDate } =
|
||||
useOverviewOptions();
|
||||
const [chartType, setChartType] = useState<IChartType>('bar');
|
||||
@@ -63,6 +66,7 @@ export default function OverviewTopGeo({ projectId }: OverviewTopGeoProps) {
|
||||
const query = useQuery(
|
||||
trpc.overview.topGeneric.queryOptions({
|
||||
projectId,
|
||||
shareId,
|
||||
range,
|
||||
filters,
|
||||
column: widget.key,
|
||||
@@ -75,6 +79,7 @@ export default function OverviewTopGeo({ projectId }: OverviewTopGeoProps) {
|
||||
trpc.overview.topGenericSeries.queryOptions(
|
||||
{
|
||||
projectId,
|
||||
shareId,
|
||||
range,
|
||||
filters,
|
||||
column: widget.key,
|
||||
@@ -211,32 +216,7 @@ export default function OverviewTopGeo({ projectId }: OverviewTopGeoProps) {
|
||||
<div className="title">Map</div>
|
||||
</WidgetHead>
|
||||
<WidgetBody>
|
||||
<ReportChartShortcut
|
||||
{...{
|
||||
projectId,
|
||||
startDate,
|
||||
endDate,
|
||||
series: [
|
||||
{
|
||||
type: 'event',
|
||||
segment: 'event',
|
||||
filters,
|
||||
id: 'A',
|
||||
name: isPageFilter ? 'screen_view' : 'session_start',
|
||||
},
|
||||
],
|
||||
breakdowns: [
|
||||
{
|
||||
id: 'A',
|
||||
name: 'country',
|
||||
},
|
||||
],
|
||||
chartType: 'map',
|
||||
interval: interval,
|
||||
range: range,
|
||||
previous: previous,
|
||||
}}
|
||||
/>
|
||||
<OverviewMap projectId={projectId} shareId={shareId} />
|
||||
</WidgetBody>
|
||||
</Widget>
|
||||
</>
|
||||
|
||||
@@ -20,9 +20,13 @@ import { useOverviewWidgetV2 } from './useOverviewWidget';
|
||||
|
||||
interface OverviewTopPagesProps {
|
||||
projectId: string;
|
||||
shareId?: string;
|
||||
}
|
||||
|
||||
export default function OverviewTopPages({ projectId }: OverviewTopPagesProps) {
|
||||
export default function OverviewTopPages({
|
||||
projectId,
|
||||
shareId,
|
||||
}: OverviewTopPagesProps) {
|
||||
const { interval, range, startDate, endDate } = useOverviewOptions();
|
||||
const [filters] = useEventQueryFilters();
|
||||
const [domain, setDomain] = useQueryState('d', parseAsBoolean);
|
||||
@@ -56,6 +60,7 @@ export default function OverviewTopPages({ projectId }: OverviewTopPagesProps) {
|
||||
const query = useQuery(
|
||||
trpc.overview.topPages.queryOptions({
|
||||
projectId,
|
||||
shareId,
|
||||
filters,
|
||||
startDate,
|
||||
endDate,
|
||||
|
||||
@@ -24,9 +24,11 @@ import { useOverviewWidgetV2 } from './useOverviewWidget';
|
||||
|
||||
interface OverviewTopSourcesProps {
|
||||
projectId: string;
|
||||
shareId?: string;
|
||||
}
|
||||
export default function OverviewTopSources({
|
||||
projectId,
|
||||
shareId,
|
||||
}: OverviewTopSourcesProps) {
|
||||
const { interval, range, startDate, endDate } = useOverviewOptions();
|
||||
const [filters, setFilter] = useEventQueryFilters();
|
||||
@@ -71,6 +73,7 @@ export default function OverviewTopSources({
|
||||
const query = useQuery(
|
||||
trpc.overview.topGeneric.queryOptions({
|
||||
projectId,
|
||||
shareId,
|
||||
range,
|
||||
filters,
|
||||
column: widget.key,
|
||||
@@ -83,6 +86,7 @@ export default function OverviewTopSources({
|
||||
trpc.overview.topGenericSeries.queryOptions(
|
||||
{
|
||||
projectId,
|
||||
shareId,
|
||||
range,
|
||||
filters,
|
||||
column: widget.key,
|
||||
|
||||
@@ -29,6 +29,7 @@ import { useOverviewOptions } from './useOverviewOptions';
|
||||
|
||||
interface OverviewUserJourneyProps {
|
||||
projectId: string;
|
||||
shareId?: string;
|
||||
}
|
||||
|
||||
type PortalTooltipPosition = { left: number; top: number; ready: boolean };
|
||||
@@ -159,6 +160,7 @@ function SankeyPortalTooltip({
|
||||
|
||||
export default function OverviewUserJourney({
|
||||
projectId,
|
||||
shareId,
|
||||
}: OverviewUserJourneyProps) {
|
||||
const { range, startDate, endDate } = useOverviewOptions();
|
||||
const [filters] = useEventQueryFilters();
|
||||
@@ -177,6 +179,7 @@ export default function OverviewUserJourney({
|
||||
endDate,
|
||||
range,
|
||||
steps: steps ?? 5,
|
||||
shareId,
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user