dashboard: add bots to overview
This commit is contained in:
81
apps/dashboard/src/components/overview/overview-top-bots.tsx
Normal file
81
apps/dashboard/src/components/overview/overview-top-bots.tsx
Normal file
@@ -0,0 +1,81 @@
|
||||
import { useState } from 'react';
|
||||
import { api } from '@/trpc/client';
|
||||
|
||||
import { Pagination } from '../pagination';
|
||||
import { Tooltiper } from '../ui/tooltip';
|
||||
import { WidgetTable } from '../widget-table';
|
||||
|
||||
interface Props {
|
||||
projectId: string;
|
||||
}
|
||||
|
||||
function getPath(path: string) {
|
||||
try {
|
||||
return new URL(path).pathname;
|
||||
} catch {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
const OverviewTopBots = ({ projectId }: Props) => {
|
||||
const [cursor, setCursor] = useState<number>(0);
|
||||
const res = api.event.bots.useQuery(
|
||||
{ projectId, cursor },
|
||||
{
|
||||
keepPreviousData: true,
|
||||
}
|
||||
);
|
||||
const data = res.data?.data ?? [];
|
||||
const count = res.data?.count ?? 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="-m-4">
|
||||
<WidgetTable
|
||||
className="max-w-full [&_td:first-child]:w-full [&_th]:text-xs [&_tr]:text-xs"
|
||||
data={data}
|
||||
keyExtractor={(item) => item.id}
|
||||
columns={[
|
||||
{
|
||||
name: 'Path',
|
||||
render(item) {
|
||||
return (
|
||||
<Tooltiper asChild content={item.path}>
|
||||
<span className="w-full">{getPath(item.path)}</span>
|
||||
</Tooltiper>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Date',
|
||||
render(item) {
|
||||
return (
|
||||
<div className="flex gap-2 whitespace-nowrap">
|
||||
<Tooltiper asChild content={`${item.type}`}>
|
||||
<div>{item.name}</div>
|
||||
</Tooltiper>
|
||||
<Tooltiper
|
||||
asChild
|
||||
content={`${item.createdAt.toLocaleString()}`}
|
||||
>
|
||||
<div>{item.createdAt.toLocaleDateString()}</div>
|
||||
</Tooltiper>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<Pagination
|
||||
className="mt-4"
|
||||
cursor={cursor}
|
||||
setCursor={setCursor}
|
||||
count={count}
|
||||
take={8}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default OverviewTopBots;
|
||||
@@ -9,6 +9,7 @@ import type { IChartType } from '@openpanel/validation';
|
||||
import { LazyChart } from '../report/chart/LazyChart';
|
||||
import { Widget, WidgetBody } from '../widget';
|
||||
import { OverviewChartToggle } from './overview-chart-toggle';
|
||||
import OverviewTopBots from './overview-top-bots';
|
||||
import { WidgetButtons, WidgetHead } from './overview-widget';
|
||||
import { useOverviewOptions } from './useOverviewOptions';
|
||||
import { useOverviewWidget } from './useOverviewWidget';
|
||||
@@ -112,6 +113,10 @@ export default function OverviewTopPages({ projectId }: OverviewTopPagesProps) {
|
||||
metric: 'sum',
|
||||
},
|
||||
},
|
||||
bot: {
|
||||
title: 'Bots',
|
||||
btn: 'Bots',
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -135,14 +140,18 @@ export default function OverviewTopPages({ projectId }: OverviewTopPagesProps) {
|
||||
</WidgetButtons>
|
||||
</WidgetHead>
|
||||
<WidgetBody>
|
||||
<LazyChart
|
||||
hideID
|
||||
{...widget.chart}
|
||||
previous={false}
|
||||
onClick={(item) => {
|
||||
setFilter('path', item.name);
|
||||
}}
|
||||
/>
|
||||
{widget.key === 'bot' ? (
|
||||
<OverviewTopBots projectId={projectId} />
|
||||
) : (
|
||||
<LazyChart
|
||||
hideID
|
||||
{...widget.chart}
|
||||
previous={false}
|
||||
onClick={(item) => {
|
||||
setFilter('path', item.name);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</WidgetBody>
|
||||
</Widget>
|
||||
</>
|
||||
|
||||
@@ -24,6 +24,7 @@ const data = {
|
||||
linkedin: 'https://linkedin.com',
|
||||
linux: 'https://upload.wikimedia.org/wikipedia/commons/3/35/Tux.svg',
|
||||
microlaunch: 'https://microlaunch.net',
|
||||
openalternative: 'https://openalternative.co',
|
||||
opera: 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/49/Opera_2015_icon.svg/1920px-Opera_2015_icon.svg.png',
|
||||
pinterest: 'https://www.pinterest.se',
|
||||
producthunt: 'https://www.producthunt.com',
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { cn } from '@/utils/cn';
|
||||
|
||||
interface Props<T> {
|
||||
columns: {
|
||||
name: string;
|
||||
@@ -5,11 +7,17 @@ interface Props<T> {
|
||||
}[];
|
||||
keyExtractor: (item: T) => string;
|
||||
data: T[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function WidgetTable<T>({ columns, data, keyExtractor }: Props<T>) {
|
||||
export function WidgetTable<T>({
|
||||
className,
|
||||
columns,
|
||||
data,
|
||||
keyExtractor,
|
||||
}: Props<T>) {
|
||||
return (
|
||||
<table className="w-full">
|
||||
<table className={cn('w-full', className)}>
|
||||
<thead className="border-b border-border bg-slate-50 text-sm text-slate-500 [&_th:last-child]:text-right [&_th]:whitespace-nowrap [&_th]:p-4 [&_th]:py-2 [&_th]:text-left [&_th]:font-medium">
|
||||
<tr>
|
||||
{columns.map((column) => (
|
||||
|
||||
Reference in New Issue
Block a user