From 0a15a773e2095383236f3bafc26db2e629ecdf49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl-Gerhard=20Lindesva=CC=88rd?= Date: Wed, 13 Dec 2023 11:08:10 +0100 Subject: [PATCH] web: filter events by name (all events and profile events) --- README.md | 6 +-- .../web/src/components/events/EventsTable.tsx | 13 +---- .../src/components/ui/combobox-advanced.tsx | 6 +-- apps/web/src/modals/index.tsx | 2 + .../pages/[organization]/[project]/events.tsx | 30 +++++++++-- .../[project]/profiles/[profileId].tsx | 29 +++++++++-- apps/web/src/server/api/routers/event.ts | 52 +++++++++++-------- 7 files changed, 93 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 7b8bbb33..1d3007b1 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,8 @@ As of today (2023-12-12) I have more then 1.2 million events in PSQL and perform - [ ] Active users (5min, 10min, 30min) - [x] Save report to a specific dashboard - [x] View events in a list - - [ ] Simple filters -- [*] View profiles in a list + - [x] Simple filters +- [x] View profiles in a list - [ ] Invite users - [ ] Drag n Drop reports on dashboard - [x] Manage dashboards @@ -42,7 +42,7 @@ As of today (2023-12-12) I have more then 1.2 million events in PSQL and perform ### SDK -- [*] Store duration on screen view events (can be done in backend as well) +- [x] Store duration on screen view events (can be done in backend as well) - [x] Create native sdk - [x] Handle sessions - [x] Create web sdk diff --git a/apps/web/src/components/events/EventsTable.tsx b/apps/web/src/components/events/EventsTable.tsx index 163bba72..c9b92209 100644 --- a/apps/web/src/components/events/EventsTable.tsx +++ b/apps/web/src/components/events/EventsTable.tsx @@ -1,7 +1,5 @@ import { useMemo } from 'react'; import { DataTable } from '@/components/DataTable'; -import { Pagination } from '@/components/Pagination'; -import type { PaginationProps } from '@/components/Pagination'; import { Avatar, AvatarFallback } from '@/components/ui/avatar'; import { Table, TableBody, TableCell, TableRow } from '@/components/ui/table'; import { useOrganizationParams } from '@/hooks/useOrganizationParams'; @@ -17,10 +15,9 @@ const columnHelper = interface EventsTableProps { data: RouterOutputs['event']['list']; - pagination: PaginationProps; } -export function EventsTable({ data, pagination }: EventsTableProps) { +export function EventsTable({ data }: EventsTableProps) { const params = useOrganizationParams(); const columns = useMemo(() => { return [ @@ -94,11 +91,5 @@ export function EventsTable({ data, pagination }: EventsTableProps) { ]; }, [params]); - return ( - <> - - - - - ); + return ; } diff --git a/apps/web/src/components/ui/combobox-advanced.tsx b/apps/web/src/components/ui/combobox-advanced.tsx index 91d00eac..c9684f78 100644 --- a/apps/web/src/components/ui/combobox-advanced.tsx +++ b/apps/web/src/components/ui/combobox-advanced.tsx @@ -5,7 +5,7 @@ import { Command, CommandGroup, CommandItem } from '@/components/ui/command'; import { Checkbox } from './checkbox'; import { Input } from './input'; -type IValue = string | number | boolean | null; +type IValue = any; type IItem = Record<'value' | 'label', IValue>; interface ComboboxAdvancedProps { @@ -60,7 +60,7 @@ export function ComboboxAdvanced({ ); }; - const renderUnknownItem = (value: string | number | null | boolean) => { + const renderUnknownItem = (value: IValue) => { const item = items.find((item) => item.value === value); return item ? renderItem(item) : renderItem({ value, label: value }); }; @@ -92,7 +92,7 @@ export function ComboboxAdvanced({
{open && ( -
+
emitter.emit('push', { name, + // @ts-expect-error props: Array.isArray(rest) && rest[0] ? rest[0] : {}, }); export const replaceModal = < @@ -194,6 +195,7 @@ export const replaceModal = < ) => emitter.emit('replace', { name, + // @ts-expect-error props: Array.isArray(rest) && rest[0] ? rest[0] : {}, }); export const popModal = (name?: StateItem['name']) => diff --git a/apps/web/src/pages/[organization]/[project]/events.tsx b/apps/web/src/pages/[organization]/[project]/events.tsx index 48e8db3b..f73c3bb2 100644 --- a/apps/web/src/pages/[organization]/[project]/events.tsx +++ b/apps/web/src/pages/[organization]/[project]/events.tsx @@ -1,17 +1,20 @@ -import { useMemo } from 'react'; +import { useMemo, useState } from 'react'; import { Container } from '@/components/Container'; import { EventsTable } from '@/components/events/EventsTable'; import { MainLayout } from '@/components/layouts/MainLayout'; import { PageTitle } from '@/components/PageTitle'; -import { usePagination } from '@/components/Pagination'; +import { Pagination, usePagination } from '@/components/Pagination'; +import { ComboboxAdvanced } from '@/components/ui/combobox-advanced'; import { useOrganizationParams } from '@/hooks/useOrganizationParams'; import { api } from '@/utils/api'; export default function Events() { const pagination = usePagination(); const params = useOrganizationParams(); + const [eventFilters, setEventFilters] = useState([]); const eventsQuery = api.event.list.useQuery( { + events: eventFilters, projectSlug: params.project, ...pagination, }, @@ -21,11 +24,32 @@ export default function Events() { ); const events = useMemo(() => eventsQuery.data ?? [], [eventsQuery]); + const filterEventsQuery = api.chart.events.useQuery({ + projectSlug: params.project, + }); + const filterEvents = (filterEventsQuery.data ?? []).map((item) => ({ + value: item.name, + label: item.name, + })); + return ( Events - + +
+
+ +
+ +
+ +
); diff --git a/apps/web/src/pages/[organization]/[project]/profiles/[profileId].tsx b/apps/web/src/pages/[organization]/[project]/profiles/[profileId].tsx index 345b83a3..090403f3 100644 --- a/apps/web/src/pages/[organization]/[project]/profiles/[profileId].tsx +++ b/apps/web/src/pages/[organization]/[project]/profiles/[profileId].tsx @@ -1,12 +1,12 @@ -import { useMemo } from 'react'; +import { useMemo, useState } from 'react'; import { Container } from '@/components/Container'; import { EventsTable } from '@/components/events/EventsTable'; import { MainLayout } from '@/components/layouts/MainLayout'; import { PageTitle } from '@/components/PageTitle'; -import { usePagination } from '@/components/Pagination'; +import { Pagination, usePagination } from '@/components/Pagination'; +import { ComboboxAdvanced } from '@/components/ui/combobox-advanced'; import { useOrganizationParams } from '@/hooks/useOrganizationParams'; import { useQueryParams } from '@/hooks/useQueryParams'; -import { createServerSideProps } from '@/server/getServerSideProps'; import { api } from '@/utils/api'; import { getProfileName } from '@/utils/getters'; import { z } from 'zod'; @@ -19,6 +19,14 @@ export default function ProfileId() { profileId: z.string(), }) ); + const [eventFilters, setEventFilters] = useState([]); + const filterEventsQuery = api.chart.events.useQuery({ + projectSlug: params.project, + }); + const filterEvents = (filterEventsQuery.data ?? []).map((item) => ({ + value: item.name, + label: item.name, + })); const profileQuery = api.profile.get.useQuery({ id: profileId, }); @@ -26,6 +34,7 @@ export default function ProfileId() { { projectSlug: params.project, profileId, + events: eventFilters, ...pagination, }, { @@ -40,7 +49,19 @@ export default function ProfileId() { {getProfileName(profile)}
{JSON.stringify(profile?.properties, null, 2)}
- +
+
+ +
+ +
+ +
); diff --git a/apps/web/src/server/api/routers/event.ts b/apps/web/src/server/api/routers/event.ts index ec7618fe..a2f5de49 100644 --- a/apps/web/src/server/api/routers/event.ts +++ b/apps/web/src/server/api/routers/event.ts @@ -16,27 +16,37 @@ export const eventRouter = createTRPCRouter({ take: z.number().default(100), skip: z.number().default(0), profileId: z.string().optional(), + events: z.array(z.string()).optional(), }) ) - .query(async ({ input: { take, skip, projectSlug, profileId } }) => { - const project = await db.project.findUniqueOrThrow({ - where: { - slug: projectSlug, - }, - }); - return db.event.findMany({ - take, - skip, - where: { - project_id: project.id, - profile_id: profileId, - }, - orderBy: { - createdAt: 'desc', - }, - include: { - profile: true, - }, - }); - }), + .query( + async ({ input: { take, skip, projectSlug, profileId, events } }) => { + const project = await db.project.findUniqueOrThrow({ + where: { + slug: projectSlug, + }, + }); + return db.event.findMany({ + take, + skip, + where: { + project_id: project.id, + profile_id: profileId, + ...(events && events.length > 0 + ? { + name: { + in: events, + }, + } + : {}), + }, + orderBy: { + createdAt: 'desc', + }, + include: { + profile: true, + }, + }); + } + ), });