improvements(dashboard): add headers to all overview tables to get a better understanding if its sessions or page views
This commit is contained in:
@@ -31,6 +31,9 @@ export default function OverviewTopDevices({
|
|||||||
title: 'Top devices',
|
title: 'Top devices',
|
||||||
btn: 'Devices',
|
btn: 'Devices',
|
||||||
chart: {
|
chart: {
|
||||||
|
options: {
|
||||||
|
columns: ['Device', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
|
},
|
||||||
report: {
|
report: {
|
||||||
limit: 10,
|
limit: 10,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -64,6 +67,9 @@ export default function OverviewTopDevices({
|
|||||||
title: 'Top browser',
|
title: 'Top browser',
|
||||||
btn: 'Browser',
|
btn: 'Browser',
|
||||||
chart: {
|
chart: {
|
||||||
|
options: {
|
||||||
|
columns: ['Browser', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
|
},
|
||||||
report: {
|
report: {
|
||||||
limit: 10,
|
limit: 10,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -98,6 +104,7 @@ export default function OverviewTopDevices({
|
|||||||
btn: 'Browser Version',
|
btn: 'Browser Version',
|
||||||
chart: {
|
chart: {
|
||||||
options: {
|
options: {
|
||||||
|
columns: ['Version', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
renderSerieName(name) {
|
renderSerieName(name) {
|
||||||
return name[1] || NOT_SET_VALUE;
|
return name[1] || NOT_SET_VALUE;
|
||||||
},
|
},
|
||||||
@@ -139,6 +146,9 @@ export default function OverviewTopDevices({
|
|||||||
title: 'Top OS',
|
title: 'Top OS',
|
||||||
btn: 'OS',
|
btn: 'OS',
|
||||||
chart: {
|
chart: {
|
||||||
|
options: {
|
||||||
|
columns: ['OS', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
|
},
|
||||||
report: {
|
report: {
|
||||||
limit: 10,
|
limit: 10,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -173,6 +183,7 @@ export default function OverviewTopDevices({
|
|||||||
btn: 'OS Version',
|
btn: 'OS Version',
|
||||||
chart: {
|
chart: {
|
||||||
options: {
|
options: {
|
||||||
|
columns: ['Version', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
renderSerieName(name) {
|
renderSerieName(name) {
|
||||||
return name[1] || NOT_SET_VALUE;
|
return name[1] || NOT_SET_VALUE;
|
||||||
},
|
},
|
||||||
@@ -214,6 +225,9 @@ export default function OverviewTopDevices({
|
|||||||
title: 'Top Brands',
|
title: 'Top Brands',
|
||||||
btn: 'Brands',
|
btn: 'Brands',
|
||||||
chart: {
|
chart: {
|
||||||
|
options: {
|
||||||
|
columns: ['Brand', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
|
},
|
||||||
report: {
|
report: {
|
||||||
limit: 10,
|
limit: 10,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -248,6 +262,7 @@ export default function OverviewTopDevices({
|
|||||||
btn: 'Models',
|
btn: 'Models',
|
||||||
chart: {
|
chart: {
|
||||||
options: {
|
options: {
|
||||||
|
columns: ['Model', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
renderSerieName(name) {
|
renderSerieName(name) {
|
||||||
return name[1] || NOT_SET_VALUE;
|
return name[1] || NOT_SET_VALUE;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ export default function OverviewTopEvents({
|
|||||||
</WidgetHead>
|
</WidgetHead>
|
||||||
<WidgetBody>
|
<WidgetBody>
|
||||||
<ReportChart
|
<ReportChart
|
||||||
options={{ hideID: true }}
|
options={{ hideID: true, columns: ['Event', 'Count'] }}
|
||||||
report={{
|
report={{
|
||||||
...widget.chart.report,
|
...widget.chart.report,
|
||||||
previous: false,
|
previous: false,
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export default function OverviewTopGeo({ projectId }: OverviewTopGeoProps) {
|
|||||||
btn: 'Countries',
|
btn: 'Countries',
|
||||||
chart: {
|
chart: {
|
||||||
options: {
|
options: {
|
||||||
|
columns: ['Country', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
renderSerieName(name) {
|
renderSerieName(name) {
|
||||||
return getCountry(name[0]) || NOT_SET_VALUE;
|
return getCountry(name[0]) || NOT_SET_VALUE;
|
||||||
},
|
},
|
||||||
@@ -69,6 +70,7 @@ export default function OverviewTopGeo({ projectId }: OverviewTopGeoProps) {
|
|||||||
btn: 'Regions',
|
btn: 'Regions',
|
||||||
chart: {
|
chart: {
|
||||||
options: {
|
options: {
|
||||||
|
columns: ['Region', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
renderSerieName(name) {
|
renderSerieName(name) {
|
||||||
return name[1] || NOT_SET_VALUE;
|
return name[1] || NOT_SET_VALUE;
|
||||||
},
|
},
|
||||||
@@ -111,6 +113,7 @@ export default function OverviewTopGeo({ projectId }: OverviewTopGeoProps) {
|
|||||||
btn: 'Cities',
|
btn: 'Cities',
|
||||||
chart: {
|
chart: {
|
||||||
options: {
|
options: {
|
||||||
|
columns: ['City', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
renderSerieName(name) {
|
renderSerieName(name) {
|
||||||
return name[1] || NOT_SET_VALUE;
|
return name[1] || NOT_SET_VALUE;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export default function OverviewTopPages({ projectId }: OverviewTopPagesProps) {
|
|||||||
chart: {
|
chart: {
|
||||||
options: {
|
options: {
|
||||||
renderSerieName,
|
renderSerieName,
|
||||||
|
columns: ['URL', 'Views'],
|
||||||
},
|
},
|
||||||
report: {
|
report: {
|
||||||
limit: 10,
|
limit: 10,
|
||||||
@@ -89,6 +90,7 @@ export default function OverviewTopPages({ projectId }: OverviewTopPagesProps) {
|
|||||||
btn: 'Entries',
|
btn: 'Entries',
|
||||||
chart: {
|
chart: {
|
||||||
options: {
|
options: {
|
||||||
|
columns: ['URL', 'Sessions'],
|
||||||
renderSerieName,
|
renderSerieName,
|
||||||
},
|
},
|
||||||
report: {
|
report: {
|
||||||
@@ -129,6 +131,7 @@ export default function OverviewTopPages({ projectId }: OverviewTopPagesProps) {
|
|||||||
btn: 'Exits',
|
btn: 'Exits',
|
||||||
chart: {
|
chart: {
|
||||||
options: {
|
options: {
|
||||||
|
columns: ['URL', 'Sessions'],
|
||||||
renderSerieName,
|
renderSerieName,
|
||||||
},
|
},
|
||||||
report: {
|
report: {
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ export default function OverviewTopSources({
|
|||||||
title: 'Top sources',
|
title: 'Top sources',
|
||||||
btn: 'All',
|
btn: 'All',
|
||||||
chart: {
|
chart: {
|
||||||
|
options: {
|
||||||
|
columns: ['Source', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
|
},
|
||||||
report: {
|
report: {
|
||||||
limit: 10,
|
limit: 10,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -64,6 +67,9 @@ export default function OverviewTopSources({
|
|||||||
title: 'Top urls',
|
title: 'Top urls',
|
||||||
btn: 'URLs',
|
btn: 'URLs',
|
||||||
chart: {
|
chart: {
|
||||||
|
options: {
|
||||||
|
columns: ['URL', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
|
},
|
||||||
report: {
|
report: {
|
||||||
limit: 10,
|
limit: 10,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -97,6 +103,9 @@ export default function OverviewTopSources({
|
|||||||
title: 'Top types',
|
title: 'Top types',
|
||||||
btn: 'Types',
|
btn: 'Types',
|
||||||
chart: {
|
chart: {
|
||||||
|
options: {
|
||||||
|
columns: ['Type', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
|
},
|
||||||
report: {
|
report: {
|
||||||
limit: 10,
|
limit: 10,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -130,6 +139,9 @@ export default function OverviewTopSources({
|
|||||||
title: 'UTM Source',
|
title: 'UTM Source',
|
||||||
btn: 'Source',
|
btn: 'Source',
|
||||||
chart: {
|
chart: {
|
||||||
|
options: {
|
||||||
|
columns: ['Utm Source', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
|
},
|
||||||
report: {
|
report: {
|
||||||
limit: 10,
|
limit: 10,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -163,6 +175,9 @@ export default function OverviewTopSources({
|
|||||||
title: 'UTM Medium',
|
title: 'UTM Medium',
|
||||||
btn: 'Medium',
|
btn: 'Medium',
|
||||||
chart: {
|
chart: {
|
||||||
|
options: {
|
||||||
|
columns: ['Utm Medium', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
|
},
|
||||||
report: {
|
report: {
|
||||||
limit: 10,
|
limit: 10,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -196,6 +211,9 @@ export default function OverviewTopSources({
|
|||||||
title: 'UTM Campaign',
|
title: 'UTM Campaign',
|
||||||
btn: 'Campaign',
|
btn: 'Campaign',
|
||||||
chart: {
|
chart: {
|
||||||
|
options: {
|
||||||
|
columns: ['Utm Campaign', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
|
},
|
||||||
report: {
|
report: {
|
||||||
limit: 10,
|
limit: 10,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -229,6 +247,9 @@ export default function OverviewTopSources({
|
|||||||
title: 'UTM Term',
|
title: 'UTM Term',
|
||||||
btn: 'Term',
|
btn: 'Term',
|
||||||
chart: {
|
chart: {
|
||||||
|
options: {
|
||||||
|
columns: ['Utm Term', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
|
},
|
||||||
report: {
|
report: {
|
||||||
limit: 10,
|
limit: 10,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -262,6 +283,9 @@ export default function OverviewTopSources({
|
|||||||
title: 'UTM Content',
|
title: 'UTM Content',
|
||||||
btn: 'Content',
|
btn: 'Content',
|
||||||
chart: {
|
chart: {
|
||||||
|
options: {
|
||||||
|
columns: ['Utm Content', isPageFilter ? 'Views' : 'Sessions'],
|
||||||
|
},
|
||||||
report: {
|
report: {
|
||||||
limit: 10,
|
limit: 10,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -319,6 +343,7 @@ export default function OverviewTopSources({
|
|||||||
previous: false,
|
previous: false,
|
||||||
}}
|
}}
|
||||||
options={{
|
options={{
|
||||||
|
...widget.chart.options,
|
||||||
renderSerieName: (name) =>
|
renderSerieName: (name) =>
|
||||||
name[0] === NOT_SET_VALUE ? 'Direct / Not set' : name[0],
|
name[0] === NOT_SET_VALUE ? 'Direct / Not set' : name[0],
|
||||||
onClick: (item) => {
|
onClick: (item) => {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { useNumber } from '@/hooks/useNumerFormatter';
|
|||||||
import type { IChartData } from '@/trpc/client';
|
import type { IChartData } from '@/trpc/client';
|
||||||
import { cn } from '@/utils/cn';
|
import { cn } from '@/utils/cn';
|
||||||
import { DropdownMenuPortal } from '@radix-ui/react-dropdown-menu';
|
import { DropdownMenuPortal } from '@radix-ui/react-dropdown-menu';
|
||||||
import { useMemo } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { round } from '@openpanel/common';
|
import { round } from '@openpanel/common';
|
||||||
import { NOT_SET_VALUE } from '@openpanel/constants';
|
import { NOT_SET_VALUE } from '@openpanel/constants';
|
||||||
@@ -25,10 +25,11 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Chart({ data }: Props) {
|
export function Chart({ data }: Props) {
|
||||||
|
const [isOpen, setOpen] = useState<string | null>(null);
|
||||||
const {
|
const {
|
||||||
isEditMode,
|
isEditMode,
|
||||||
report: { metric, limit },
|
report: { metric, limit },
|
||||||
options: { onClick, dropdownMenuContent },
|
options: { onClick, dropdownMenuContent, columns },
|
||||||
} = useReportChartContext();
|
} = useReportChartContext();
|
||||||
const number = useNumber();
|
const number = useNumber();
|
||||||
const series = useMemo(
|
const series = useMemo(
|
||||||
@@ -44,6 +45,24 @@ export function Chart({ data }: Props) {
|
|||||||
isEditMode ? 'card gap-2 p-4 text-base' : '-m-3 gap-1',
|
isEditMode ? 'card gap-2 p-4 text-base' : '-m-3 gap-1',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
{columns && columns.length > 0 && (
|
||||||
|
<div className="relative z-10 flex w-full flex-1 items-center gap-4 overflow-hidden px-3 pt-2 pb-1">
|
||||||
|
{columns.map((column, index) => {
|
||||||
|
const isLast = columns.length - 1 <= index;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={column?.toString()}
|
||||||
|
className={cn(
|
||||||
|
'flex flex-1 items-center gap-2 break-all font-medium',
|
||||||
|
isLast && 'justify-end text-right',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{column}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{series.map((serie) => {
|
{series.map((serie) => {
|
||||||
const isClickable = !serie.names.includes(NOT_SET_VALUE) && onClick;
|
const isClickable = !serie.names.includes(NOT_SET_VALUE) && onClick;
|
||||||
const isDropDownEnabled =
|
const isDropDownEnabled =
|
||||||
@@ -51,15 +70,36 @@ export function Chart({ data }: Props) {
|
|||||||
(dropdownMenuContent?.(serie) || []).length > 0;
|
(dropdownMenuContent?.(serie) || []).length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu key={serie.id}>
|
<DropdownMenu
|
||||||
<DropdownMenuTrigger asChild disabled={!isDropDownEnabled}>
|
key={serie.id}
|
||||||
|
onOpenChange={() =>
|
||||||
|
setOpen((p) => (p === serie.id ? null : serie.id))
|
||||||
|
}
|
||||||
|
open={isOpen === serie.id}
|
||||||
|
>
|
||||||
|
<DropdownMenuTrigger
|
||||||
|
asChild
|
||||||
|
disabled={!isDropDownEnabled}
|
||||||
|
{...(isDropDownEnabled
|
||||||
|
? {
|
||||||
|
// We need to disable onPointerDown event to prevent the
|
||||||
|
// dropdown from opening when the user is scrolling (mobile/tablet).
|
||||||
|
// We also need to handle open/closed state and chnage this
|
||||||
|
// when onClick happens
|
||||||
|
onPointerDown: (e) => e.preventDefault(),
|
||||||
|
onClick: () => setOpen(serie.id),
|
||||||
|
}
|
||||||
|
: {})}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative',
|
'relative',
|
||||||
(isClickable || isDropDownEnabled) && 'cursor-pointer',
|
(isClickable || isDropDownEnabled) && 'cursor-pointer',
|
||||||
)}
|
)}
|
||||||
{...(isClickable && !isDropDownEnabled
|
{...(isClickable && !isDropDownEnabled
|
||||||
? { onClick: () => onClick?.(serie) }
|
? {
|
||||||
|
onClick: () => onClick(serie),
|
||||||
|
}
|
||||||
: {})}
|
: {})}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import type {
|
|||||||
|
|
||||||
export type ReportChartContextType = {
|
export type ReportChartContextType = {
|
||||||
options: Partial<{
|
options: Partial<{
|
||||||
|
columns: React.ReactNode[];
|
||||||
hideID: boolean;
|
hideID: boolean;
|
||||||
hideLegend: boolean;
|
hideLegend: boolean;
|
||||||
hideXAxis: boolean;
|
hideXAxis: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user