feat: group analytics

* wip

* wip

* wip

* wip

* wip

* add buffer

* wip

* wip

* fixes

* fix

* wip

* group validation

* fix group issues

* docs: add groups
This commit is contained in:
Carl-Gerhard Lindesvärd
2026-03-20 10:46:09 +01:00
committed by GitHub
parent 88a2d876ce
commit 11e9ecac1a
99 changed files with 5944 additions and 1432 deletions

View File

@@ -1,15 +1,10 @@
import type { IServiceProfile } from '@openpanel/db';
import type { ColumnDef } from '@tanstack/react-table';
import { ProfileAvatar } from '../profile-avatar';
import { ColumnCreatedAt } from '@/components/column-created-at';
import { ProjectLink } from '@/components/links';
import { SerieIcon } from '@/components/report-chart/common/serie-icon';
import { Tooltiper } from '@/components/ui/tooltip';
import { formatDateTime, formatTime } from '@/utils/date';
import { getProfileName } from '@/utils/getters';
import type { ColumnDef } from '@tanstack/react-table';
import { isToday } from 'date-fns';
import type { IServiceProfile } from '@openpanel/db';
import { ColumnCreatedAt } from '@/components/column-created-at';
import { ProfileAvatar } from '../profile-avatar';
export function useColumns(type: 'profiles' | 'power-users') {
const columns: ColumnDef<IServiceProfile>[] = [
@@ -20,8 +15,8 @@ export function useColumns(type: 'profiles' | 'power-users') {
const profile = row.original;
return (
<ProjectLink
href={`/profiles/${encodeURIComponent(profile.id)}`}
className="flex items-center gap-2 font-medium"
href={`/profiles/${encodeURIComponent(profile.id)}`}
title={getProfileName(profile, false)}
>
<ProfileAvatar size="sm" {...profile} />
@@ -100,13 +95,40 @@ export function useColumns(type: 'profiles' | 'power-users') {
},
{
accessorKey: 'createdAt',
header: 'Last seen',
header: 'First seen',
size: ColumnCreatedAt.size,
cell: ({ row }) => {
const item = row.original;
return <ColumnCreatedAt>{item.createdAt}</ColumnCreatedAt>;
},
},
{
accessorKey: 'groups',
header: 'Groups',
size: 200,
meta: {
hidden: true,
},
cell({ row }) {
const { groups } = row.original;
if (!groups?.length) {
return null;
}
return (
<div className="flex flex-wrap gap-1">
{groups.map((g) => (
<ProjectLink
className="rounded bg-muted px-1.5 py-0.5 font-mono text-xs hover:underline"
href={`/groups/${encodeURIComponent(g)}`}
key={g}
>
{g}
</ProjectLink>
))}
</div>
);
},
},
];
if (type === 'power-users') {