From b7513f24d57572c4e3d8a2d3ff859fc11f13d5b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl-Gerhard=20Lindesva=CC=88rd?= Date: Mon, 18 Mar 2024 21:53:07 +0100 Subject: [PATCH] well deserved clean up (#1) --- apps/dashboard/package.json | 1 + .../dashboards/list-dashboards.tsx | 5 +- .../event-conversions-list.tsx | 2 +- .../events/event-conversions-list/index.tsx | 2 +- .../[projectId]/events/event-list.tsx | 4 +- .../[projectId]/layout-sidebar.tsx | 2 +- .../[projectId]/profiles/[profileId]/page.tsx | 6 +- .../[projectId]/profiles/_profile-list.tsx | 74 ------ .../profiles/profile-last-seen/index.tsx | 2 +- .../profiles/profile-list-item.tsx | 59 ----- .../profiles/profile-list/profile-list.tsx | 13 +- .../profiles/profile-top/index.tsx | 14 +- .../settings/clients/list-clients.tsx | 10 +- .../organization/edit-organization.tsx | 4 +- .../settings/organization/invite-user.tsx | 2 +- .../settings/organization/invited-users.tsx | 2 +- .../settings/profile/edit-profile.tsx | 4 +- .../[projectId]/settings/profile/logout.tsx | 2 +- .../settings/projects/list-projects.tsx | 2 +- .../settings/references/list-references.tsx | 2 +- .../[projectId]/test/page.tsx | 21 -- .../(app)/[organizationId]/create-project.tsx | 2 +- .../src/app/(app)/[organizationId]/page.tsx | 2 +- .../src/app/(app)/create-organization.tsx | 4 +- apps/dashboard/src/app/(app)/page.tsx | 2 +- .../app/(public)/share/overview/[id]/page.tsx | 2 +- apps/dashboard/src/app/auth.tsx | 6 +- apps/dashboard/src/components/Container.tsx | 11 - apps/dashboard/src/components/Content.tsx | 52 ----- apps/dashboard/src/components/Dropdown.tsx | 55 ----- apps/dashboard/src/components/PageTitle.tsx | 11 - apps/dashboard/src/components/WithSidebar.tsx | 15 -- ...ttonContainer.tsx => button-container.tsx} | 0 .../{ClientActions.tsx => client-actions.tsx} | 0 .../src/components/clients/table.tsx | 2 +- .../{ColorSquare.tsx => color-square.tsx} | 0 .../{DataTable.tsx => data-table.tsx} | 0 ...rtiesIcon.tsx => list-properties-icon.tsx} | 0 .../src/components/forms/InputError.tsx | 11 - ...nputWithLabel.tsx => input-with-label.tsx} | 0 ...ptyState.tsx => full-page-empty-state.tsx} | 0 .../components/general/ExpandableListItem.tsx | 57 ----- .../overview-latest-events.tsx | 2 +- .../components/overview/overview-metrics.tsx | 2 +- .../overview/overview-top-devices.tsx | 2 +- .../overview-top-events.tsx | 2 +- .../components/overview/overview-top-geo.tsx | 2 +- .../overview/overview-top-pages.tsx | 2 +- .../overview/overview-top-sources.tsx | 2 +- .../components/overview/overview-widget.tsx | 4 +- .../{ProfileAvatar.tsx => profile-avatar.tsx} | 0 ...ProjectActions.tsx => project-actions.tsx} | 0 .../src/components/projects/table.tsx | 9 +- ...r.tsx => react-virtualized-auto-sizer.tsx} | 0 .../src/components/report/ReportRange.tsx | 4 +- .../components/report/chart/ChartEmpty.tsx | 2 +- .../components/report/chart/MetricCard.tsx | 2 +- .../report/chart/ReportLineChart.tsx | 1 - .../report/chart/ReportPieChart.tsx | 2 +- .../components/report/chart/ReportTable.tsx | 13 +- .../report/sidebar/ReportBreakdowns.tsx | 2 +- .../report/sidebar/ReportEvents.tsx | 8 +- .../report/sidebar/filters/FilterItem.tsx | 8 +- .../src/components/ui/dropdown-menu.tsx | 44 ++++ .../dashboard/src/components/ui/key-value.tsx | 26 +-- .../src/hooks/useProfileProperties.ts | 3 +- apps/dashboard/src/hooks/useQueryParams.ts | 34 --- apps/dashboard/src/hooks/useRefetchActive.ts | 6 - .../src/hooks/useRouterBeforeLeave.ts | 21 -- apps/dashboard/src/hooks/useSetCookie.ts | 16 -- apps/dashboard/src/mappings.json | 144 +----------- apps/dashboard/src/modals/AddDashboard.tsx | 4 +- apps/dashboard/src/modals/AddProject.tsx | 4 +- apps/dashboard/src/modals/AddReference.tsx | 4 +- apps/dashboard/src/modals/Confirm.tsx | 2 +- apps/dashboard/src/modals/EditClient.tsx | 4 +- apps/dashboard/src/modals/EditDashboard.tsx | 4 +- apps/dashboard/src/modals/EditProject.tsx | 4 +- apps/dashboard/src/modals/EditReport.tsx | 4 +- apps/dashboard/src/modals/SaveReport.tsx | 6 +- .../src/modals/ShareOverviewModal.tsx | 4 +- apps/dashboard/src/server/api/root.ts | 2 - .../src/server/api/routers/chart.helpers.ts | 216 ++++++++++++++++- .../dashboard/src/server/api/routers/chart.ts | 217 ++---------------- .../src/server/api/routers/client.ts | 4 +- .../src/server/api/routers/dashboard.ts | 52 +---- .../src/server/api/routers/onboarding.ts | 15 +- .../src/server/api/routers/organization.ts | 1 - .../src/server/api/routers/profile.ts | 60 +---- .../src/server/api/routers/project.ts | 26 +-- .../src/server/api/routers/report.ts | 50 +--- .../dashboard/src/server/api/routers/share.ts | 2 +- apps/dashboard/src/server/api/routers/ui.ts | 15 -- apps/dashboard/src/server/auth.ts | 3 - apps/dashboard/src/server/cache.ts | 39 ---- apps/dashboard/src/styles/globals.css | 38 --- apps/dashboard/src/utils/date.ts | 6 - .../src/{server/db.ts => utils/getDbId.ts} | 6 +- apps/dashboard/src/utils/getters.ts | 6 - packages/db/src/services/clients.service.ts | 27 ++- packages/db/src/services/dashboard.service.ts | 16 -- .../db/src/services/organization.service.ts | 2 +- packages/db/src/services/profile.service.ts | 13 +- packages/db/src/services/project.service.ts | 8 +- packages/db/src/services/reference.service.ts | 8 +- pnpm-lock.yaml | 28 +-- 106 files changed, 453 insertions(+), 1275 deletions(-) delete mode 100644 apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/_profile-list.tsx delete mode 100644 apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-list-item.tsx delete mode 100644 apps/dashboard/src/app/(app)/[organizationId]/[projectId]/test/page.tsx delete mode 100644 apps/dashboard/src/components/Container.tsx delete mode 100644 apps/dashboard/src/components/Content.tsx delete mode 100644 apps/dashboard/src/components/Dropdown.tsx delete mode 100644 apps/dashboard/src/components/PageTitle.tsx delete mode 100644 apps/dashboard/src/components/WithSidebar.tsx rename apps/dashboard/src/components/{ButtonContainer.tsx => button-container.tsx} (100%) rename apps/dashboard/src/components/clients/{ClientActions.tsx => client-actions.tsx} (100%) rename apps/dashboard/src/components/{ColorSquare.tsx => color-square.tsx} (100%) rename apps/dashboard/src/components/{DataTable.tsx => data-table.tsx} (100%) rename apps/dashboard/src/components/events/{ListPropertiesIcon.tsx => list-properties-icon.tsx} (100%) delete mode 100644 apps/dashboard/src/components/forms/InputError.tsx rename apps/dashboard/src/components/forms/{InputWithLabel.tsx => input-with-label.tsx} (100%) rename apps/dashboard/src/components/{FullPageEmptyState.tsx => full-page-empty-state.tsx} (100%) delete mode 100644 apps/dashboard/src/components/general/ExpandableListItem.tsx rename apps/dashboard/src/components/profiles/{ProfileAvatar.tsx => profile-avatar.tsx} (100%) rename apps/dashboard/src/components/projects/{ProjectActions.tsx => project-actions.tsx} (100%) rename apps/dashboard/src/components/{AutoSizer.tsx => react-virtualized-auto-sizer.tsx} (100%) delete mode 100644 apps/dashboard/src/hooks/useQueryParams.ts delete mode 100644 apps/dashboard/src/hooks/useRefetchActive.ts delete mode 100644 apps/dashboard/src/hooks/useRouterBeforeLeave.ts delete mode 100644 apps/dashboard/src/hooks/useSetCookie.ts delete mode 100644 apps/dashboard/src/server/api/routers/ui.ts delete mode 100644 apps/dashboard/src/server/auth.ts delete mode 100644 apps/dashboard/src/server/cache.ts rename apps/dashboard/src/{server/db.ts => utils/getDbId.ts} (83%) delete mode 100644 apps/dashboard/src/utils/getters.ts diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json index fdef1dbd..4b69026e 100644 --- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -48,6 +48,7 @@ "@trpc/server": "^10.45.1", "@types/d3": "^7.4.3", "bcrypt": "^5.1.1", + "bind-event-listener": "^3.0.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "cmdk": "^0.2.1", diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/dashboards/list-dashboards.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/dashboards/list-dashboards.tsx index bce4e21b..59b75752 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/dashboards/list-dashboards.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/dashboards/list-dashboards.tsx @@ -1,10 +1,9 @@ 'use client'; import { api, handleErrorToastOptions } from '@/app/_trpc/client'; -import { Card, CardActions, CardActionsItem } from '@/components/Card'; -import { FullPageEmptyState } from '@/components/FullPageEmptyState'; +import { Card, CardActions, CardActionsItem } from '@/components/card'; +import { FullPageEmptyState } from '@/components/full-page-empty-state'; import { Button } from '@/components/ui/button'; -import { ToastAction } from '@/components/ui/toast'; import { useAppParams } from '@/hooks/useAppParams'; import { pushModal } from '@/modals'; import { LayoutPanelTopIcon, Pencil, PlusIcon, Trash } from 'lucide-react'; diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/events/event-conversions-list/event-conversions-list.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/events/event-conversions-list/event-conversions-list.tsx index 54c015b7..240bc8a9 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/events/event-conversions-list/event-conversions-list.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/events/event-conversions-list/event-conversions-list.tsx @@ -1,7 +1,7 @@ 'use client'; import { Fragment } from 'react'; -import { Widget, WidgetHead } from '@/components/Widget'; +import { Widget, WidgetHead } from '@/components/widget'; import { isSameDay } from 'date-fns'; import type { IServiceCreateEventPayload } from '@openpanel/db'; diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/events/event-conversions-list/index.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/events/event-conversions-list/index.tsx index 9dfc78a8..ba50a6f3 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/events/event-conversions-list/index.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/events/event-conversions-list/index.tsx @@ -1,4 +1,4 @@ -import { Widget } from '@/components/Widget'; +import { Widget } from '@/components/widget'; import { db, getEvents } from '@openpanel/db'; diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/events/event-list.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/events/event-list.tsx index a6ecf777..9d8b0282 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/events/event-list.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/events/event-list.tsx @@ -1,8 +1,8 @@ 'use client'; import { Fragment, Suspense } from 'react'; -import { FullPageEmptyState } from '@/components/FullPageEmptyState'; -import { Pagination } from '@/components/Pagination'; +import { FullPageEmptyState } from '@/components/full-page-empty-state'; +import { Pagination } from '@/components/pagination'; import { ChartSwitch, ChartSwitchShortcut } from '@/components/report/chart'; import { Button } from '@/components/ui/button'; import { useAppParams } from '@/hooks/useAppParams'; diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/layout-sidebar.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/layout-sidebar.tsx index bb2f402e..1b5552b3 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/layout-sidebar.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/layout-sidebar.tsx @@ -1,7 +1,7 @@ 'use client'; import { useEffect, useState } from 'react'; -import { Logo } from '@/components/Logo'; +import { Logo } from '@/components/logo'; import { buttonVariants } from '@/components/ui/button'; import { cn } from '@/utils/cn'; import { Rotate as Hamburger } from 'hamburger-react'; diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/[profileId]/page.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/[profileId]/page.tsx index 7a1132ea..88357c9c 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/[profileId]/page.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/[profileId]/page.tsx @@ -1,16 +1,15 @@ import PageLayout from '@/app/(app)/[organizationId]/[projectId]/page-layout'; import { OverviewFiltersButtons } from '@/components/overview/filters/overview-filters-buttons'; import { OverviewFiltersDrawer } from '@/components/overview/filters/overview-filters-drawer'; -import { ProfileAvatar } from '@/components/profiles/ProfileAvatar'; +import { ProfileAvatar } from '@/components/profiles/profile-avatar'; import { ChartSwitch } from '@/components/report/chart'; import { SerieIcon } from '@/components/report/chart/SerieIcon'; -import { Widget, WidgetBody, WidgetHead } from '@/components/Widget'; +import { Widget, WidgetBody, WidgetHead } from '@/components/widget'; import { eventQueryFiltersParser, eventQueryNamesFilter, } from '@/hooks/useEventQueryFilters'; import { getExists } from '@/server/pageExists'; -import { getProfileName } from '@/utils/getters'; import { notFound } from 'next/navigation'; import { parseAsInteger, parseAsString } from 'nuqs'; @@ -20,6 +19,7 @@ import { getEventList, getEventsCount, getProfileById, + getProfileName, } from '@openpanel/db'; import type { IChartEvent, IChartInput } from '@openpanel/validation'; diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/_profile-list.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/_profile-list.tsx deleted file mode 100644 index e8610a59..00000000 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/_profile-list.tsx +++ /dev/null @@ -1,74 +0,0 @@ -'use client'; - -import { Suspense } from 'react'; -import { FullPageEmptyState } from '@/components/FullPageEmptyState'; -import { Pagination } from '@/components/Pagination'; -import { Button } from '@/components/ui/button'; -import { useCursor } from '@/hooks/useCursor'; -import { useEventQueryFilters } from '@/hooks/useEventQueryFilters'; -import { UsersIcon } from 'lucide-react'; - -import type { IServiceProfile } from '@openpanel/db'; - -import { ProfileListItem } from './profile-list-item'; - -interface ProfileListProps { - data: IServiceProfile[]; - count: number; -} -export function ProfileList({ data, count }: ProfileListProps) { - const { cursor, setCursor } = useCursor(); - const [filters] = useEventQueryFilters(); - - return ( - -
- {data.length === 0 ? ( - - {cursor !== 0 ? ( - <> -

Looks like you have reached the end of the list

- - - ) : ( - <> - {filters.length ? ( -

Could not find any profiles with your filter

- ) : ( -

No profiles have been created yet

- )} - - )} -
- ) : ( - <> - -
- {data.map((item) => ( - - ))} -
- - - )} -
-
- ); -} diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-last-seen/index.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-last-seen/index.tsx index 5b48b3ab..174668b3 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-last-seen/index.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-last-seen/index.tsx @@ -3,7 +3,7 @@ import { TooltipContent, TooltipTrigger, } from '@/components/ui/tooltip'; -import { Widget, WidgetBody, WidgetHead } from '@/components/Widget'; +import { Widget, WidgetBody, WidgetHead } from '@/components/widget'; import { cn } from '@/utils/cn'; import { chQuery } from '@openpanel/db'; diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-list-item.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-list-item.tsx deleted file mode 100644 index 7822e586..00000000 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-list-item.tsx +++ /dev/null @@ -1,59 +0,0 @@ -'use client'; - -import { ExpandableListItem } from '@/components/general/ExpandableListItem'; -import { ProfileAvatar } from '@/components/profiles/ProfileAvatar'; -import { KeyValue, KeyValueSubtle } from '@/components/ui/key-value'; -import { useAppParams } from '@/hooks/useAppParams'; -import { useEventQueryFilters } from '@/hooks/useEventQueryFilters'; -import { getProfileName } from '@/utils/getters'; - -import type { IServiceProfile } from '@openpanel/db'; - -type ProfileListItemProps = IServiceProfile; - -export function ProfileListItem(props: ProfileListItemProps) { - const { id, properties, createdAt } = props; - const params = useAppParams(); - const [, setFilter] = useEventQueryFilters({ shallow: false }); - - const renderContent = () => { - return ( - <> - - - - ); - }; - - return ( - } - > - <> - {properties && ( -
-
Properties
-
- {Object.entries(properties) - .filter(([, value]) => !!value) - .map(([key, value]) => ( - setFilter(`properties.${key}`, value)} - key={key} - name={key} - value={value} - /> - ))} -
-
- )} - -
- ); -} diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-list/profile-list.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-list/profile-list.tsx index f803dd9f..53004398 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-list/profile-list.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-list/profile-list.tsx @@ -1,18 +1,19 @@ 'use client'; -import { ListPropertiesIcon } from '@/components/events/ListPropertiesIcon'; -import { FullPageEmptyState } from '@/components/FullPageEmptyState'; -import { Pagination } from '@/components/Pagination'; -import { ProfileAvatar } from '@/components/profiles/ProfileAvatar'; +import { ListPropertiesIcon } from '@/components/events/list-properties-icon'; +import { FullPageEmptyState } from '@/components/full-page-empty-state'; +import { Pagination } from '@/components/pagination'; +import { ProfileAvatar } from '@/components/profiles/profile-avatar'; import { Button } from '@/components/ui/button'; import { Tooltiper } from '@/components/ui/tooltip'; -import { Widget, WidgetHead } from '@/components/Widget'; +import { Widget, WidgetHead } from '@/components/widget'; import { WidgetTable } from '@/components/widget-table'; import { useAppParams } from '@/hooks/useAppParams'; import { useCursor } from '@/hooks/useCursor'; import { UsersIcon } from 'lucide-react'; import Link from 'next/link'; +import { getProfileName } from '@openpanel/db'; import type { IServiceProfile } from '@openpanel/db'; interface ProfileListProps { @@ -49,7 +50,7 @@ export function ProfileList({ data, count }: ProfileListProps) { className="flex gap-2 items-center font-medium" > - {profile.firstName} {profile.lastName} + {getProfileName(profile)} ); }, diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-top/index.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-top/index.tsx index 6870e9bb..b448ee00 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-top/index.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/profiles/profile-top/index.tsx @@ -1,10 +1,10 @@ -import { ListPropertiesIcon } from '@/components/events/ListPropertiesIcon'; -import { ProfileAvatar } from '@/components/profiles/ProfileAvatar'; -import { Widget, WidgetHead } from '@/components/Widget'; +import { ListPropertiesIcon } from '@/components/events/list-properties-icon'; +import { ProfileAvatar } from '@/components/profiles/profile-avatar'; +import { Widget, WidgetHead } from '@/components/widget'; import { WidgetTable } from '@/components/widget-table'; import Link from 'next/link'; -import { chQuery, getProfiles } from '@openpanel/db'; +import { chQuery, getProfileName, getProfiles } from '@openpanel/db'; interface Props { projectId: string; @@ -24,7 +24,7 @@ export default async function ProfileTopServer({ const list = res.map((item) => { return { count: item.count, - ...(profiles.find((p) => p.id === item.profile_id) ?? {}), + ...(profiles.find((p) => p.id === item.profile_id)! ?? {}), }; }); @@ -35,7 +35,7 @@ export default async function ProfileTopServer({ !!item.id)} - keyExtractor={(item) => item.id!} + keyExtractor={(item) => item.id} columns={[ { name: 'Name', @@ -46,7 +46,7 @@ export default async function ProfileTopServer({ className="flex gap-2 items-center font-medium" > - {profile.firstName} {profile.lastName} + {getProfileName(profile)} ); }, diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/clients/list-clients.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/clients/list-clients.tsx index ff1a48cb..f8e61509 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/clients/list-clients.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/clients/list-clients.tsx @@ -2,9 +2,8 @@ import { StickyBelowHeader } from '@/app/(app)/[organizationId]/[projectId]/layout-sticky-below-header'; import { columns } from '@/components/clients/table'; -import { DataTable } from '@/components/DataTable'; +import { DataTable } from '@/components/data-table'; import { Button } from '@/components/ui/button'; -import { useAppParams } from '@/hooks/useAppParams'; import { pushModal } from '@/modals'; import { PlusIcon } from 'lucide-react'; @@ -14,17 +13,12 @@ interface ListClientsProps { clients: Awaited>; } export default function ListClients({ clients }: ListClientsProps) { - const organizationId = useAppParams().organizationId; - return ( <>
- diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/organization/edit-organization.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/organization/edit-organization.tsx index e2e15e65..518be8e5 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/organization/edit-organization.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/organization/edit-organization.tsx @@ -1,9 +1,9 @@ 'use client'; import { api, handleError } from '@/app/_trpc/client'; -import { InputWithLabel } from '@/components/forms/InputWithLabel'; +import { InputWithLabel } from '@/components/forms/input-with-label'; import { Button } from '@/components/ui/button'; -import { Widget, WidgetBody, WidgetHead } from '@/components/Widget'; +import { Widget, WidgetBody, WidgetHead } from '@/components/widget'; import { useRouter } from 'next/navigation'; import { useForm } from 'react-hook-form'; import { toast } from 'sonner'; diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/organization/invite-user.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/organization/invite-user.tsx index 5d4eebc6..bcc4b9e8 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/organization/invite-user.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/organization/invite-user.tsx @@ -1,5 +1,5 @@ import { api } from '@/app/_trpc/client'; -import { InputWithLabel } from '@/components/forms/InputWithLabel'; +import { InputWithLabel } from '@/components/forms/input-with-label'; import { Button } from '@/components/ui/button'; import { useAppParams } from '@/hooks/useAppParams'; import { zodResolver } from '@hookform/resolvers/zod'; diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/organization/invited-users.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/organization/invited-users.tsx index 2b8d34d4..33b8bfe6 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/organization/invited-users.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/organization/invited-users.tsx @@ -8,7 +8,7 @@ import { TableHeader, TableRow, } from '@/components/ui/table'; -import { Widget, WidgetBody, WidgetHead } from '@/components/Widget'; +import { Widget, WidgetBody, WidgetHead } from '@/components/widget'; import type { IServiceInvites } from '@openpanel/db'; diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/profile/edit-profile.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/profile/edit-profile.tsx index 937e11a2..72072a56 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/profile/edit-profile.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/profile/edit-profile.tsx @@ -1,9 +1,9 @@ 'use client'; import { api, handleError } from '@/app/_trpc/client'; -import { InputWithLabel } from '@/components/forms/InputWithLabel'; +import { InputWithLabel } from '@/components/forms/input-with-label'; import { Button } from '@/components/ui/button'; -import { Widget, WidgetBody, WidgetHead } from '@/components/Widget'; +import { Widget, WidgetBody, WidgetHead } from '@/components/widget'; import { zodResolver } from '@hookform/resolvers/zod'; import { useRouter } from 'next/navigation'; import { useForm } from 'react-hook-form'; diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/profile/logout.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/profile/logout.tsx index a599d5f4..9bae0e26 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/profile/logout.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/profile/logout.tsx @@ -1,7 +1,7 @@ 'use client'; import { buttonVariants } from '@/components/ui/button'; -import { Widget, WidgetBody, WidgetHead } from '@/components/Widget'; +import { Widget, WidgetBody, WidgetHead } from '@/components/widget'; import { SignOutButton } from '@clerk/nextjs'; export function Logout() { diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/projects/list-projects.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/projects/list-projects.tsx index 231cedd8..3112a8a0 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/projects/list-projects.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/projects/list-projects.tsx @@ -1,7 +1,7 @@ 'use client'; import { StickyBelowHeader } from '@/app/(app)/[organizationId]/[projectId]/layout-sticky-below-header'; -import { DataTable } from '@/components/DataTable'; +import { DataTable } from '@/components/data-table'; import { columns } from '@/components/projects/table'; import { Button } from '@/components/ui/button'; import { useAppParams } from '@/hooks/useAppParams'; diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/references/list-references.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/references/list-references.tsx index 9304a7e1..2f284563 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/references/list-references.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/settings/references/list-references.tsx @@ -1,7 +1,7 @@ 'use client'; import { StickyBelowHeader } from '@/app/(app)/[organizationId]/[projectId]/layout-sticky-below-header'; -import { DataTable } from '@/components/DataTable'; +import { DataTable } from '@/components/data-table'; import { columns } from '@/components/references/table'; import { Button } from '@/components/ui/button'; import { pushModal } from '@/modals'; diff --git a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/test/page.tsx b/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/test/page.tsx deleted file mode 100644 index d03b06c1..00000000 --- a/apps/dashboard/src/app/(app)/[organizationId]/[projectId]/test/page.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Funnel } from '@/components/report/funnel'; - -import PageLayout from '../page-layout'; - -export const metadata = { - title: 'Funnel - Openpanel.dev', -}; - -interface PageProps { - params: { - organizationId: string; - }; -} - -export default function Page({ params: { organizationId } }: PageProps) { - return ( - - - - ); -} diff --git a/apps/dashboard/src/app/(app)/[organizationId]/create-project.tsx b/apps/dashboard/src/app/(app)/[organizationId]/create-project.tsx index 8d585245..8ebecfb4 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/create-project.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/create-project.tsx @@ -1,6 +1,6 @@ 'use client'; -import { LogoSquare } from '@/components/Logo'; +import { LogoSquare } from '@/components/logo'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; diff --git a/apps/dashboard/src/app/(app)/[organizationId]/page.tsx b/apps/dashboard/src/app/(app)/[organizationId]/page.tsx index f4e5738e..47d95831 100644 --- a/apps/dashboard/src/app/(app)/[organizationId]/page.tsx +++ b/apps/dashboard/src/app/(app)/[organizationId]/page.tsx @@ -1,4 +1,4 @@ -import { LogoSquare } from '@/components/Logo'; +import { LogoSquare } from '@/components/logo'; import { ProjectCard } from '@/components/projects/project-card'; import { notFound, redirect } from 'next/navigation'; diff --git a/apps/dashboard/src/app/(app)/create-organization.tsx b/apps/dashboard/src/app/(app)/create-organization.tsx index ea235757..2800bc76 100644 --- a/apps/dashboard/src/app/(app)/create-organization.tsx +++ b/apps/dashboard/src/app/(app)/create-organization.tsx @@ -1,8 +1,7 @@ 'use client'; -import { useState } from 'react'; import { CreateClientSuccess } from '@/components/clients/create-client-success'; -import { LogoSquare } from '@/components/Logo'; +import { LogoSquare } from '@/components/logo'; import { Button, buttonVariants } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; @@ -10,7 +9,6 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { cn } from '@/utils/cn'; import { zodResolver } from '@hookform/resolvers/zod'; import { SaveIcon, WallpaperIcon } from 'lucide-react'; -import Link from 'next/link'; import { useRouter } from 'next/navigation'; import type { SubmitHandler } from 'react-hook-form'; import { useForm } from 'react-hook-form'; diff --git a/apps/dashboard/src/app/(app)/page.tsx b/apps/dashboard/src/app/(app)/page.tsx index 45907d65..a519f007 100644 --- a/apps/dashboard/src/app/(app)/page.tsx +++ b/apps/dashboard/src/app/(app)/page.tsx @@ -1,6 +1,6 @@ // import { CreateOrganization } from '@clerk/nextjs'; -import { LogoSquare } from '@/components/Logo'; +import { LogoSquare } from '@/components/logo'; import { redirect } from 'next/navigation'; import { getCurrentOrganizations, isWaitlistUserAccepted } from '@openpanel/db'; diff --git a/apps/dashboard/src/app/(public)/share/overview/[id]/page.tsx b/apps/dashboard/src/app/(public)/share/overview/[id]/page.tsx index 809bf593..c30983e9 100644 --- a/apps/dashboard/src/app/(public)/share/overview/[id]/page.tsx +++ b/apps/dashboard/src/app/(public)/share/overview/[id]/page.tsx @@ -1,6 +1,6 @@ import { StickyBelowHeader } from '@/app/(app)/[organizationId]/[projectId]/layout-sticky-below-header'; import { OverviewReportRange } from '@/app/(app)/[organizationId]/[projectId]/overview-sticky-header'; -import { Logo } from '@/components/Logo'; +import { Logo } from '@/components/logo'; import { OverviewFiltersButtons } from '@/components/overview/filters/overview-filters-buttons'; import ServerLiveCounter from '@/components/overview/live-counter'; import { OverviewLiveHistogram } from '@/components/overview/overview-live-histogram'; diff --git a/apps/dashboard/src/app/auth.tsx b/apps/dashboard/src/app/auth.tsx index d73c4909..497eff0d 100644 --- a/apps/dashboard/src/app/auth.tsx +++ b/apps/dashboard/src/app/auth.tsx @@ -1,11 +1,11 @@ 'use client'; import { useState } from 'react'; -import { InputWithLabel } from '@/components/forms/InputWithLabel'; -import { Logo } from '@/components/Logo'; +import { InputWithLabel } from '@/components/forms/input-with-label'; +import { Logo } from '@/components/logo'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Button } from '@/components/ui/button'; -import { Widget, WidgetBody } from '@/components/Widget'; +import { Widget, WidgetBody } from '@/components/widget'; import { zodResolver } from '@hookform/resolvers/zod'; import { KeySquareIcon } from 'lucide-react'; import { signIn } from 'next-auth/react'; diff --git a/apps/dashboard/src/components/Container.tsx b/apps/dashboard/src/components/Container.tsx deleted file mode 100644 index 2f40b42b..00000000 --- a/apps/dashboard/src/components/Container.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import type { HtmlProps } from '@/types'; -import { cn } from '@/utils/cn'; - -export function Container({ className, ...props }: HtmlProps) { - return ( -
- ); -} diff --git a/apps/dashboard/src/components/Content.tsx b/apps/dashboard/src/components/Content.tsx deleted file mode 100644 index 2e7a736e..00000000 --- a/apps/dashboard/src/components/Content.tsx +++ /dev/null @@ -1,52 +0,0 @@ -'use client'; - -import { cn } from '@/utils/cn'; - -interface ContentHeaderProps { - title: string; - text: string; - children?: React.ReactNode; -} - -export function ContentHeader({ title, text, children }: ContentHeaderProps) { - return ( -
-
-

{title}

-

{text}

-
-
{children}
-
- ); -} - -interface ContentSectionProps { - title: string; - text?: string | React.ReactNode; - children: React.ReactNode; - asCol?: boolean; -} - -export function ContentSection({ - title, - text, - children, - asCol, -}: ContentSectionProps) { - return ( -
- {title && ( -
-

{title}

- {text &&

{text}

} -
- )} -
{children}
-
- ); -} diff --git a/apps/dashboard/src/components/Dropdown.tsx b/apps/dashboard/src/components/Dropdown.tsx deleted file mode 100644 index 1cb8ffe7..00000000 --- a/apps/dashboard/src/components/Dropdown.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { cloneElement } from 'react'; - -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuGroup, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from './ui/dropdown-menu'; - -interface DropdownProps { - children: React.ReactNode; - label?: string; - items: { - label: string; - value: Value; - }[]; - onChange?: (value: Value) => void; -} - -export function Dropdown({ - children, - label, - items, - onChange, -}: DropdownProps) { - return ( - - {children} - - {label && ( - <> - {label} - - - )} - - {items.map((item) => ( - { - onChange?.(item.value); - }} - > - {item.label} - - ))} - - - - ); -} diff --git a/apps/dashboard/src/components/PageTitle.tsx b/apps/dashboard/src/components/PageTitle.tsx deleted file mode 100644 index bcab27bf..00000000 --- a/apps/dashboard/src/components/PageTitle.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import type { HtmlProps } from '@/types'; - -type PageTitleProps = HtmlProps; - -export function PageTitle({ children }: PageTitleProps) { - return ( -
-

{children}

-
- ); -} diff --git a/apps/dashboard/src/components/WithSidebar.tsx b/apps/dashboard/src/components/WithSidebar.tsx deleted file mode 100644 index cd43d64c..00000000 --- a/apps/dashboard/src/components/WithSidebar.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import type { HtmlProps } from '@/types'; - -type WithSidebarProps = HtmlProps; - -export function WithSidebar({ children }: WithSidebarProps) { - return ( -
{children}
- ); -} - -type SidebarProps = HtmlProps; - -export function Sidebar({ children }: SidebarProps) { - return
{children}
; -} diff --git a/apps/dashboard/src/components/ButtonContainer.tsx b/apps/dashboard/src/components/button-container.tsx similarity index 100% rename from apps/dashboard/src/components/ButtonContainer.tsx rename to apps/dashboard/src/components/button-container.tsx diff --git a/apps/dashboard/src/components/clients/ClientActions.tsx b/apps/dashboard/src/components/clients/client-actions.tsx similarity index 100% rename from apps/dashboard/src/components/clients/ClientActions.tsx rename to apps/dashboard/src/components/clients/client-actions.tsx diff --git a/apps/dashboard/src/components/clients/table.tsx b/apps/dashboard/src/components/clients/table.tsx index 797c704f..a0f69d68 100644 --- a/apps/dashboard/src/components/clients/table.tsx +++ b/apps/dashboard/src/components/clients/table.tsx @@ -3,7 +3,7 @@ import type { ColumnDef } from '@tanstack/react-table'; import type { IServiceClientWithProject } from '@openpanel/db'; -import { ClientActions } from './ClientActions'; +import { ClientActions } from './client-actions'; export const columns: ColumnDef[] = [ { diff --git a/apps/dashboard/src/components/ColorSquare.tsx b/apps/dashboard/src/components/color-square.tsx similarity index 100% rename from apps/dashboard/src/components/ColorSquare.tsx rename to apps/dashboard/src/components/color-square.tsx diff --git a/apps/dashboard/src/components/DataTable.tsx b/apps/dashboard/src/components/data-table.tsx similarity index 100% rename from apps/dashboard/src/components/DataTable.tsx rename to apps/dashboard/src/components/data-table.tsx diff --git a/apps/dashboard/src/components/events/ListPropertiesIcon.tsx b/apps/dashboard/src/components/events/list-properties-icon.tsx similarity index 100% rename from apps/dashboard/src/components/events/ListPropertiesIcon.tsx rename to apps/dashboard/src/components/events/list-properties-icon.tsx diff --git a/apps/dashboard/src/components/forms/InputError.tsx b/apps/dashboard/src/components/forms/InputError.tsx deleted file mode 100644 index c68292e0..00000000 --- a/apps/dashboard/src/components/forms/InputError.tsx +++ /dev/null @@ -1,11 +0,0 @@ -interface InputErrorProps { - message?: string; -} - -export function InputError({ message }: InputErrorProps) { - if (!message) { - return null; - } - - return
{message}
; -} diff --git a/apps/dashboard/src/components/forms/InputWithLabel.tsx b/apps/dashboard/src/components/forms/input-with-label.tsx similarity index 100% rename from apps/dashboard/src/components/forms/InputWithLabel.tsx rename to apps/dashboard/src/components/forms/input-with-label.tsx diff --git a/apps/dashboard/src/components/FullPageEmptyState.tsx b/apps/dashboard/src/components/full-page-empty-state.tsx similarity index 100% rename from apps/dashboard/src/components/FullPageEmptyState.tsx rename to apps/dashboard/src/components/full-page-empty-state.tsx diff --git a/apps/dashboard/src/components/general/ExpandableListItem.tsx b/apps/dashboard/src/components/general/ExpandableListItem.tsx deleted file mode 100644 index 7b0b3ade..00000000 --- a/apps/dashboard/src/components/general/ExpandableListItem.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React, { useState } from 'react'; -import { cn } from '@/utils/cn'; -import { ChevronUp } from 'lucide-react'; -import AnimateHeight from 'react-animate-height'; - -import { Button } from '../ui/button'; - -interface ExpandableListItemProps { - children: React.ReactNode; - content: React.ReactNode; - title: React.ReactNode; - image?: React.ReactNode; - initialOpen?: boolean; - className?: string; -} -export function ExpandableListItem({ - title, - content, - image, - initialOpen = false, - children, - className, -}: ExpandableListItemProps) { - const [open, setOpen] = useState(initialOpen ?? false); - return ( -
-
-
{image}
-
-
{title}
- {!!content && ( -
- {content} -
- )} -
- -
- -
{children}
-
-
- ); -} diff --git a/apps/dashboard/src/components/overview/overview-latest-events/overview-latest-events.tsx b/apps/dashboard/src/components/overview/overview-latest-events/overview-latest-events.tsx index b3d9f5cb..9e21200d 100644 --- a/apps/dashboard/src/components/overview/overview-latest-events/overview-latest-events.tsx +++ b/apps/dashboard/src/components/overview/overview-latest-events/overview-latest-events.tsx @@ -4,7 +4,7 @@ import { ChartSwitch } from '@/components/report/chart'; import { useEventQueryFilters } from '@/hooks/useEventQueryFilters'; import { cn } from '@/utils/cn'; -import { Widget, WidgetBody } from '../../Widget'; +import { Widget, WidgetBody } from '../../widget'; import { WidgetButtons, WidgetHead } from '../overview-widget'; import { useOverviewOptions } from '../useOverviewOptions'; import { useOverviewWidget } from '../useOverviewWidget'; diff --git a/apps/dashboard/src/components/overview/overview-metrics.tsx b/apps/dashboard/src/components/overview/overview-metrics.tsx index 241bfc8a..827d00f4 100644 --- a/apps/dashboard/src/components/overview/overview-metrics.tsx +++ b/apps/dashboard/src/components/overview/overview-metrics.tsx @@ -3,7 +3,7 @@ import { WidgetHead } from '@/components/overview/overview-widget'; import { useOverviewOptions } from '@/components/overview/useOverviewOptions'; import { ChartSwitch } from '@/components/report/chart'; -import { Widget, WidgetBody } from '@/components/Widget'; +import { Widget, WidgetBody } from '@/components/widget'; import { useEventQueryFilters } from '@/hooks/useEventQueryFilters'; import { cn } from '@/utils/cn'; diff --git a/apps/dashboard/src/components/overview/overview-top-devices.tsx b/apps/dashboard/src/components/overview/overview-top-devices.tsx index c4c6557e..83add726 100644 --- a/apps/dashboard/src/components/overview/overview-top-devices.tsx +++ b/apps/dashboard/src/components/overview/overview-top-devices.tsx @@ -4,7 +4,7 @@ import { ChartSwitch } from '@/components/report/chart'; import { useEventQueryFilters } from '@/hooks/useEventQueryFilters'; import { cn } from '@/utils/cn'; -import { Widget, WidgetBody } from '../Widget'; +import { Widget, WidgetBody } from '../widget'; import { OverviewChartToggle } from './overview-chart-toggle'; import { WidgetButtons, WidgetHead } from './overview-widget'; import { useOverviewOptions } from './useOverviewOptions'; diff --git a/apps/dashboard/src/components/overview/overview-top-events/overview-top-events.tsx b/apps/dashboard/src/components/overview/overview-top-events/overview-top-events.tsx index add0d5f6..43115492 100644 --- a/apps/dashboard/src/components/overview/overview-top-events/overview-top-events.tsx +++ b/apps/dashboard/src/components/overview/overview-top-events/overview-top-events.tsx @@ -6,7 +6,7 @@ import { useEventQueryFilters } from '@/hooks/useEventQueryFilters'; import { cn } from '@/utils/cn'; import { BarChartIcon, LineChart, LineChartIcon } from 'lucide-react'; -import { Widget, WidgetBody } from '../../Widget'; +import { Widget, WidgetBody } from '../../widget'; import { OverviewChartToggle } from '../overview-chart-toggle'; import { WidgetButtons, WidgetHead } from '../overview-widget'; import { useOverviewOptions } from '../useOverviewOptions'; diff --git a/apps/dashboard/src/components/overview/overview-top-geo.tsx b/apps/dashboard/src/components/overview/overview-top-geo.tsx index 2a5a9f6a..6d85eaa6 100644 --- a/apps/dashboard/src/components/overview/overview-top-geo.tsx +++ b/apps/dashboard/src/components/overview/overview-top-geo.tsx @@ -4,7 +4,7 @@ import { ChartSwitch } from '@/components/report/chart'; import { useEventQueryFilters } from '@/hooks/useEventQueryFilters'; import { cn } from '@/utils/cn'; -import { Widget, WidgetBody } from '../Widget'; +import { Widget, WidgetBody } from '../widget'; import { OverviewChartToggle } from './overview-chart-toggle'; import { WidgetButtons, WidgetHead } from './overview-widget'; import { useOverviewOptions } from './useOverviewOptions'; diff --git a/apps/dashboard/src/components/overview/overview-top-pages.tsx b/apps/dashboard/src/components/overview/overview-top-pages.tsx index 3bad9079..b97e7e6f 100644 --- a/apps/dashboard/src/components/overview/overview-top-pages.tsx +++ b/apps/dashboard/src/components/overview/overview-top-pages.tsx @@ -4,7 +4,7 @@ import { ChartSwitch } from '@/components/report/chart'; import { useEventQueryFilters } from '@/hooks/useEventQueryFilters'; import { cn } from '@/utils/cn'; -import { Widget, WidgetBody } from '../Widget'; +import { Widget, WidgetBody } from '../widget'; import { OverviewChartToggle } from './overview-chart-toggle'; import { WidgetButtons, WidgetHead } from './overview-widget'; import { useOverviewOptions } from './useOverviewOptions'; diff --git a/apps/dashboard/src/components/overview/overview-top-sources.tsx b/apps/dashboard/src/components/overview/overview-top-sources.tsx index e38b3d11..63473528 100644 --- a/apps/dashboard/src/components/overview/overview-top-sources.tsx +++ b/apps/dashboard/src/components/overview/overview-top-sources.tsx @@ -4,7 +4,7 @@ import { ChartSwitch } from '@/components/report/chart'; import { useEventQueryFilters } from '@/hooks/useEventQueryFilters'; import { cn } from '@/utils/cn'; -import { Widget, WidgetBody } from '../Widget'; +import { Widget, WidgetBody } from '../widget'; import { OverviewChartToggle } from './overview-chart-toggle'; import { WidgetButtons, WidgetHead } from './overview-widget'; import { useOverviewOptions } from './useOverviewOptions'; diff --git a/apps/dashboard/src/components/overview/overview-widget.tsx b/apps/dashboard/src/components/overview/overview-widget.tsx index 9ae4be48..28d0d6d0 100644 --- a/apps/dashboard/src/components/overview/overview-widget.tsx +++ b/apps/dashboard/src/components/overview/overview-widget.tsx @@ -13,8 +13,8 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from '../ui/dropdown-menu'; -import type { WidgetHeadProps } from '../Widget'; -import { WidgetHead as WidgetHeadBase } from '../Widget'; +import type { WidgetHeadProps } from '../widget'; +import { WidgetHead as WidgetHeadBase } from '../widget'; export function WidgetHead({ className, ...props }: WidgetHeadProps) { return ( diff --git a/apps/dashboard/src/components/profiles/ProfileAvatar.tsx b/apps/dashboard/src/components/profiles/profile-avatar.tsx similarity index 100% rename from apps/dashboard/src/components/profiles/ProfileAvatar.tsx rename to apps/dashboard/src/components/profiles/profile-avatar.tsx diff --git a/apps/dashboard/src/components/projects/ProjectActions.tsx b/apps/dashboard/src/components/projects/project-actions.tsx similarity index 100% rename from apps/dashboard/src/components/projects/ProjectActions.tsx rename to apps/dashboard/src/components/projects/project-actions.tsx diff --git a/apps/dashboard/src/components/projects/table.tsx b/apps/dashboard/src/components/projects/table.tsx index 0fe220d0..64b058ad 100644 --- a/apps/dashboard/src/components/projects/table.tsx +++ b/apps/dashboard/src/components/projects/table.tsx @@ -1,13 +1,12 @@ import { formatDate } from '@/utils/date'; import type { ColumnDef } from '@tanstack/react-table'; -import { IServiceProject } from '@openpanel/db'; -import type { Project as IProject } from '@openpanel/db'; +import type { IServiceProject } from '@openpanel/db'; -import { ProjectActions } from './ProjectActions'; +import { ProjectActions } from './project-actions'; -export type Project = IProject; -export const columns: ColumnDef[] = [ +export type Project = IServiceProject; +export const columns: ColumnDef[] = [ { accessorKey: 'name', header: 'Name', diff --git a/apps/dashboard/src/components/AutoSizer.tsx b/apps/dashboard/src/components/react-virtualized-auto-sizer.tsx similarity index 100% rename from apps/dashboard/src/components/AutoSizer.tsx rename to apps/dashboard/src/components/react-virtualized-auto-sizer.tsx diff --git a/apps/dashboard/src/components/report/ReportRange.tsx b/apps/dashboard/src/components/report/ReportRange.tsx index 5c052c2e..208f8b7a 100644 --- a/apps/dashboard/src/components/report/ReportRange.tsx +++ b/apps/dashboard/src/components/report/ReportRange.tsx @@ -7,9 +7,8 @@ import { PopoverTrigger, } from '@/components/ui/popover'; import { useBreakpoint } from '@/hooks/useBreakpoint'; -import { useDispatch, useSelector } from '@/redux'; import { cn } from '@/utils/cn'; -import { endOfDay, format, startOfDay } from 'date-fns'; +import { format } from 'date-fns'; import { CalendarIcon, ChevronsUpDownIcon } from 'lucide-react'; import type { SelectRangeEventHandler } from 'react-day-picker'; @@ -18,7 +17,6 @@ import type { IChartRange } from '@openpanel/validation'; import type { ExtendedComboboxProps } from '../ui/combobox'; import { ToggleGroup, ToggleGroupItem } from '../ui/toggle-group'; -import { changeDates, changeEndDate, changeStartDate } from './reportSlice'; export function ReportRange({ range, diff --git a/apps/dashboard/src/components/report/chart/ChartEmpty.tsx b/apps/dashboard/src/components/report/chart/ChartEmpty.tsx index 068447a7..738b60d1 100644 --- a/apps/dashboard/src/components/report/chart/ChartEmpty.tsx +++ b/apps/dashboard/src/components/report/chart/ChartEmpty.tsx @@ -1,4 +1,4 @@ -import { FullPageEmptyState } from '@/components/FullPageEmptyState'; +import { FullPageEmptyState } from '@/components/full-page-empty-state'; import { cn } from '@/utils/cn'; import { useChartContext } from './ChartProvider'; diff --git a/apps/dashboard/src/components/report/chart/MetricCard.tsx b/apps/dashboard/src/components/report/chart/MetricCard.tsx index 04bfafe0..3c7a528d 100644 --- a/apps/dashboard/src/components/report/chart/MetricCard.tsx +++ b/apps/dashboard/src/components/report/chart/MetricCard.tsx @@ -1,7 +1,7 @@ 'use client'; import type { IChartData } from '@/app/_trpc/client'; -import { ColorSquare } from '@/components/ColorSquare'; +import { ColorSquare } from '@/components/color-square'; import { fancyMinutes, useNumber } from '@/hooks/useNumerFormatter'; import { theme } from '@/utils/theme'; import AutoSizer from 'react-virtualized-auto-sizer'; diff --git a/apps/dashboard/src/components/report/chart/ReportLineChart.tsx b/apps/dashboard/src/components/report/chart/ReportLineChart.tsx index ce2d0665..1ea9dd68 100644 --- a/apps/dashboard/src/components/report/chart/ReportLineChart.tsx +++ b/apps/dashboard/src/components/report/chart/ReportLineChart.tsx @@ -44,7 +44,6 @@ export function ReportLineChart({ const { series, setVisibleSeries } = useVisibleSeries(data); const rechartData = useRechartDataModel(series); const number = useNumber(); - console.log(references.map((ref) => ref.createdAt.getTime())); return ( <> diff --git a/apps/dashboard/src/components/report/chart/ReportPieChart.tsx b/apps/dashboard/src/components/report/chart/ReportPieChart.tsx index dc4211e0..c57746f8 100644 --- a/apps/dashboard/src/components/report/chart/ReportPieChart.tsx +++ b/apps/dashboard/src/components/report/chart/ReportPieChart.tsx @@ -1,5 +1,5 @@ import type { IChartData } from '@/app/_trpc/client'; -import { AutoSizer } from '@/components/AutoSizer'; +import { AutoSizer } from '@/components/react-virtualized-auto-sizer'; import { useVisibleSeries } from '@/hooks/useVisibleSeries'; import { cn } from '@/utils/cn'; import { round } from '@/utils/math'; diff --git a/apps/dashboard/src/components/report/chart/ReportTable.tsx b/apps/dashboard/src/components/report/chart/ReportTable.tsx index 9bc4030b..0fd1f6a7 100644 --- a/apps/dashboard/src/components/report/chart/ReportTable.tsx +++ b/apps/dashboard/src/components/report/chart/ReportTable.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import type { IChartData } from '@/app/_trpc/client'; -import { Pagination, usePagination } from '@/components/Pagination'; +import { Pagination, usePagination } from '@/components/pagination'; import { Badge } from '@/components/ui/badge'; import { Checkbox } from '@/components/ui/checkbox'; import { @@ -30,12 +30,14 @@ interface ReportTableProps { setVisibleSeries: React.Dispatch>; } +const ROWS_LIMIT = 50; + export function ReportTable({ data, visibleSeries, setVisibleSeries, }: ReportTableProps) { - const { setPage, paginate, page } = usePagination(50); + const { setPage, paginate, page } = usePagination(ROWS_LIMIT); const number = useNumber(); const interval = useSelector((state) => state.report.interval); const formatDate = useFormatDateInterval(interval); @@ -162,7 +164,12 @@ export function ReportTable({ Min: {number.format(data.metrics.min)} Max: {number.format(data.metrics.max)}
- +
); diff --git a/apps/dashboard/src/components/report/sidebar/ReportBreakdowns.tsx b/apps/dashboard/src/components/report/sidebar/ReportBreakdowns.tsx index bd23be75..60e49148 100644 --- a/apps/dashboard/src/components/report/sidebar/ReportBreakdowns.tsx +++ b/apps/dashboard/src/components/report/sidebar/ReportBreakdowns.tsx @@ -1,7 +1,7 @@ 'use client'; import { api } from '@/app/_trpc/client'; -import { ColorSquare } from '@/components/ColorSquare'; +import { ColorSquare } from '@/components/color-square'; import { Combobox } from '@/components/ui/combobox'; import { useAppParams } from '@/hooks/useAppParams'; import { useDispatch, useSelector } from '@/redux'; diff --git a/apps/dashboard/src/components/report/sidebar/ReportEvents.tsx b/apps/dashboard/src/components/report/sidebar/ReportEvents.tsx index db2f93f2..67b433a3 100644 --- a/apps/dashboard/src/components/report/sidebar/ReportEvents.tsx +++ b/apps/dashboard/src/components/report/sidebar/ReportEvents.tsx @@ -1,9 +1,9 @@ 'use client'; -import { ColorSquare } from '@/components/ColorSquare'; -import { Dropdown } from '@/components/Dropdown'; +import { ColorSquare } from '@/components/color-square'; import { Checkbox } from '@/components/ui/checkbox'; import { Combobox } from '@/components/ui/combobox'; +import { DropdownMenuComposed } from '@/components/ui/dropdown-menu'; import { Input } from '@/components/ui/input'; import { useAppParams } from '@/hooks/useAppParams'; import { useDebounceFn } from '@/hooks/useDebounceFn'; @@ -94,7 +94,7 @@ export function ReportEvents() { {/* Segment and Filter buttons */}
- { dispatch( changeEvent({ @@ -166,7 +166,7 @@ export function ReportEvents() { )} - + {/* */} diff --git a/apps/dashboard/src/components/report/sidebar/filters/FilterItem.tsx b/apps/dashboard/src/components/report/sidebar/filters/FilterItem.tsx index b41f9ca9..fb37473d 100644 --- a/apps/dashboard/src/components/report/sidebar/filters/FilterItem.tsx +++ b/apps/dashboard/src/components/report/sidebar/filters/FilterItem.tsx @@ -1,8 +1,8 @@ import { api } from '@/app/_trpc/client'; -import { ColorSquare } from '@/components/ColorSquare'; -import { Dropdown } from '@/components/Dropdown'; +import { ColorSquare } from '@/components/color-square'; import { Button } from '@/components/ui/button'; import { ComboboxAdvanced } from '@/components/ui/combobox-advanced'; +import { DropdownMenuComposed } from '@/components/ui/dropdown-menu'; import { RenderDots } from '@/components/ui/RenderDots'; import { useAppParams } from '@/hooks/useAppParams'; import { useMappings } from '@/hooks/useMappings'; @@ -104,7 +104,7 @@ export function FilterItem({ filter, event }: FilterProps) {
- ({ value: key, @@ -115,7 +115,7 @@ export function FilterItem({ filter, event }: FilterProps) { - + { + children: React.ReactNode; + label?: string; + items: { + label: string; + value: Value; + }[]; + onChange?: (value: Value) => void; +} + +export function DropdownMenuComposed({ + children, + label, + items, + onChange, +}: DropdownProps) { + return ( + + {children} + + {label && ( + <> + {label} + + + )} + + {items.map((item) => ( + { + onChange?.(item.value); + }} + > + {item.label} + + ))} + + + + ); +} + export { DropdownMenu, DropdownMenuTrigger, diff --git a/apps/dashboard/src/components/ui/key-value.tsx b/apps/dashboard/src/components/ui/key-value.tsx index be2a718f..7fe01bbf 100644 --- a/apps/dashboard/src/components/ui/key-value.tsx +++ b/apps/dashboard/src/components/ui/key-value.tsx @@ -1,17 +1,16 @@ -import { isValidElement } from 'react'; import { cn } from '@/utils/cn'; import Link from 'next/link'; interface KeyValueProps { name: string; - value: unknown; + value: any; onClick?: () => void; href?: string; } export function KeyValue({ href, onClick, name, value }: KeyValueProps) { const clickable = href || onClick; - const Component = href ? (Link as any) : onClick ? 'button' : 'div'; + const Component = (href ? Link : onClick ? 'button' : 'div') as 'button'; return ( ); } - -export function KeyValueSubtle({ href, onClick, name, value }: KeyValueProps) { - const clickable = href || onClick; - const Component = href ? (Link as any) : onClick ? 'button' : 'div'; - return ( - -
{name}
-
- {value} -
-
- ); -} diff --git a/apps/dashboard/src/hooks/useProfileProperties.ts b/apps/dashboard/src/hooks/useProfileProperties.ts index 3cd44a50..154db512 100644 --- a/apps/dashboard/src/hooks/useProfileProperties.ts +++ b/apps/dashboard/src/hooks/useProfileProperties.ts @@ -1,9 +1,8 @@ import { api } from '@/app/_trpc/client'; -export function useProfileProperties(projectId: string, event?: string) { +export function useProfileProperties(projectId: string) { const query = api.profile.properties.useQuery({ projectId: projectId, - event, }); return query.data ?? []; diff --git a/apps/dashboard/src/hooks/useQueryParams.ts b/apps/dashboard/src/hooks/useQueryParams.ts deleted file mode 100644 index afe65fc1..00000000 --- a/apps/dashboard/src/hooks/useQueryParams.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { useMemo } from 'react'; -import { useRouter } from 'next/router'; -import type { z } from 'zod'; - -export function useQueryParams(zod: Z) { - const router = useRouter(); - const value = zod.safeParse(router.query); - - return useMemo(() => { - function setQueryParams(newValue: Partial>) { - return router - .replace({ - pathname: router.pathname, - query: { - ...router.query, - ...newValue, - }, - }) - .catch(() => { - // ignore - }); - } - - if (value.success) { - return { ...value.data, setQueryParams } as z.infer & { - setQueryParams: typeof setQueryParams; - }; - } - return { ...router.query, setQueryParams } as z.infer & { - setQueryParams: typeof setQueryParams; - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [router.asPath, value.success]); -} diff --git a/apps/dashboard/src/hooks/useRefetchActive.ts b/apps/dashboard/src/hooks/useRefetchActive.ts deleted file mode 100644 index 5f96d435..00000000 --- a/apps/dashboard/src/hooks/useRefetchActive.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { useQueryClient } from '@tanstack/react-query'; - -export function useRefetchActive() { - const client = useQueryClient(); - return () => client.refetchQueries({ type: 'active' }); -} diff --git a/apps/dashboard/src/hooks/useRouterBeforeLeave.ts b/apps/dashboard/src/hooks/useRouterBeforeLeave.ts deleted file mode 100644 index cfe061f9..00000000 --- a/apps/dashboard/src/hooks/useRouterBeforeLeave.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { useEffect, useRef } from 'react'; -import { useRouter } from 'next/router'; - -export function useRouterBeforeLeave(callback: () => void) { - const router = useRouter(); - const prevUrl = useRef(router.asPath); - - useEffect(() => { - const handleRouteChange = (url: string) => { - if (prevUrl.current !== url) { - callback(); - } - prevUrl.current = url; - }; - - router.events.on('routeChangeStart', handleRouteChange); - return () => { - router.events.off('routeChangeStart', handleRouteChange); - }; - }, [router, callback]); -} diff --git a/apps/dashboard/src/hooks/useSetCookie.ts b/apps/dashboard/src/hooks/useSetCookie.ts deleted file mode 100644 index 58097ecd..00000000 --- a/apps/dashboard/src/hooks/useSetCookie.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { usePathname, useRouter } from 'next/navigation'; - -export function useSetCookie() { - const router = useRouter(); - const pathname = usePathname(); - return (key: string, value: string, path?: string) => { - fetch(`/api/cookie?${key}=${value}`).then(() => { - if (path && path !== pathname) { - router.refresh(); - router.replace(path); - } else { - router.refresh(); - } - }); - }; -} diff --git a/apps/dashboard/src/mappings.json b/apps/dashboard/src/mappings.json index d5cb7c91..f2d7122d 100644 --- a/apps/dashboard/src/mappings.json +++ b/apps/dashboard/src/mappings.json @@ -1,146 +1,6 @@ [ { - "id": "clbow140n0228u99ui1t24l85", - "name": "Mjölkproteinfritt" - }, - { - "id": "cl04a3trn0015ix50tzy40pyf", - "name": "Måltider" - }, - { - "id": "cl04a5p7s0401ix505n75yfcn", - "name": "Svårighetsgrad" - }, - { - "id": "cl04a7k3i0813ix50aau6yxqg", - "name": "Tid" - }, - { - "id": "cl04a47fu0103ix50dqckz2vc", - "name": "Frukost" - }, - { - "id": "cl04a4hvu0152ix50o0w4iy8l", - "name": "Mellis" - }, - { - "id": "cl04a58ju0281ix50kdmcwst6", - "name": "Dessert" - }, - { - "id": "cl04a5fjc0321ix50xiwhuydy", - "name": "Smakportioner" - }, - { - "id": "cl04a5kcu0361ix50bnmbhoxz", - "name": "Plockmat" - }, - { - "id": "cl04a60sk0496ix50et419drf", - "name": "Medium" - }, - { - "id": "cl04a67lx0536ix50sstoxnhi", - "name": "Avancerat" - }, - { - "id": "cl04a7qi60850ix50je7vaxo3", - "name": "0-10 min" - }, - { - "id": "cl04a7vxi0890ix50veumcuyu", - "name": "10-20 min" - }, - { - "id": "cl04a82bj0930ix50bboh3tl9", - "name": "20-30 min" - }, - { - "id": "cl04a8a7a0970ix50uet02cqh", - "name": "30-40 min" - }, - { - "id": "cl04a8g151010ix50z4cnf2kg", - "name": "40-50 min" - }, - { - "id": "cl04a8mqy1050ix50z0d1ho1a", - "name": "50-60 min" - }, - { - "id": "cl04a5ujg0447ix50vd3vor87", - "name": "Lätt" - }, - { - "id": "cl04a4qv60201ix50b8q5kn9r", - "name": "Lunch & Middag" - }, - { - "id": "clak50jem0072ri9ugwygg5ko", - "name": "Annat" - }, - { - "id": "clak510qm0120ri9upqkca39s", - "name": "För hela familjen" - }, - { - "id": "clak59l8x0085yd9uzllcuci5", - "name": "Under 3 ingredienser" - }, - { - "id": "clak59l8y0087yd9u53qperp8", - "name": "Under 5 ingredienser" - }, - { - "id": "claslo2sg0404no9uo2tckm5i", - "name": "Huvudingredienser" - }, - { - "id": "claslv9s20491no9ugo4fd9ns", - "name": "Fisk" - }, - { - "id": "claslv9s30493no9umug5po29", - "name": "Kyckling" - }, - { - "id": "claslv9s40495no9umor61pql", - "name": "Kött" - }, - { - "id": "claslv9s40497no9uttwkt47n", - "name": "Korv" - }, - { - "id": "claslv9s50499no9uch0lhs9i", - "name": "Vegetariskt" - }, - { - "id": "clb1y44f40128np9uufck0iqf", - "name": "Årstider" - }, - { - "id": "clb1y4ks80202np9uh43c84ts", - "name": "Jul" - }, - { - "id": "clbovy0fd0081u99u8dr0yplr", - "name": "Allergier" - }, - { - "id": "clbow140p0230u99uk9e7g1u1", - "name": "Äggfritt" - }, - { - "id": "clbow140q0232u99uy3lwukvc", - "name": "Vetefritt" - }, - { - "id": "clbow140q0234u99uiyrujxd4", - "name": "Glutenfritt" - }, - { - "id": "clbow140r0236u99u5333gpei", - "name": "Nötfritt" + "id": "123", + "name": "123" } ] diff --git a/apps/dashboard/src/modals/AddDashboard.tsx b/apps/dashboard/src/modals/AddDashboard.tsx index fde7d54a..64f8059a 100644 --- a/apps/dashboard/src/modals/AddDashboard.tsx +++ b/apps/dashboard/src/modals/AddDashboard.tsx @@ -1,8 +1,8 @@ 'use client'; import { api, handleError } from '@/app/_trpc/client'; -import { ButtonContainer } from '@/components/ButtonContainer'; -import { InputWithLabel } from '@/components/forms/InputWithLabel'; +import { ButtonContainer } from '@/components/button-container'; +import { InputWithLabel } from '@/components/forms/input-with-label'; import { Button } from '@/components/ui/button'; import { useAppParams } from '@/hooks/useAppParams'; import { zodResolver } from '@hookform/resolvers/zod'; diff --git a/apps/dashboard/src/modals/AddProject.tsx b/apps/dashboard/src/modals/AddProject.tsx index 6ee2c799..6032cc03 100644 --- a/apps/dashboard/src/modals/AddProject.tsx +++ b/apps/dashboard/src/modals/AddProject.tsx @@ -1,8 +1,8 @@ 'use client'; import { api, handleError } from '@/app/_trpc/client'; -import { ButtonContainer } from '@/components/ButtonContainer'; -import { InputWithLabel } from '@/components/forms/InputWithLabel'; +import { ButtonContainer } from '@/components/button-container'; +import { InputWithLabel } from '@/components/forms/input-with-label'; import { Button } from '@/components/ui/button'; import { zodResolver } from '@hookform/resolvers/zod'; import { useRouter } from 'next/navigation'; diff --git a/apps/dashboard/src/modals/AddReference.tsx b/apps/dashboard/src/modals/AddReference.tsx index b71802f5..833f0d90 100644 --- a/apps/dashboard/src/modals/AddReference.tsx +++ b/apps/dashboard/src/modals/AddReference.tsx @@ -1,8 +1,8 @@ 'use client'; import { api, handleError } from '@/app/_trpc/client'; -import { ButtonContainer } from '@/components/ButtonContainer'; -import { InputWithLabel } from '@/components/forms/InputWithLabel'; +import { ButtonContainer } from '@/components/button-container'; +import { InputWithLabel } from '@/components/forms/input-with-label'; import { Button } from '@/components/ui/button'; import { Calendar } from '@/components/ui/calendar'; import { useAppParams } from '@/hooks/useAppParams'; diff --git a/apps/dashboard/src/modals/Confirm.tsx b/apps/dashboard/src/modals/Confirm.tsx index 126d17ba..395e9765 100644 --- a/apps/dashboard/src/modals/Confirm.tsx +++ b/apps/dashboard/src/modals/Confirm.tsx @@ -1,6 +1,6 @@ 'use client'; -import { ButtonContainer } from '@/components/ButtonContainer'; +import { ButtonContainer } from '@/components/button-container'; import { Button } from '@/components/ui/button'; import { popModal } from '.'; diff --git a/apps/dashboard/src/modals/EditClient.tsx b/apps/dashboard/src/modals/EditClient.tsx index 4b295e47..962a4696 100644 --- a/apps/dashboard/src/modals/EditClient.tsx +++ b/apps/dashboard/src/modals/EditClient.tsx @@ -1,8 +1,8 @@ 'use client'; import { api, handleError } from '@/app/_trpc/client'; -import { ButtonContainer } from '@/components/ButtonContainer'; -import { InputWithLabel } from '@/components/forms/InputWithLabel'; +import { ButtonContainer } from '@/components/button-container'; +import { InputWithLabel } from '@/components/forms/input-with-label'; import { Button } from '@/components/ui/button'; import { zodResolver } from '@hookform/resolvers/zod'; import { useRouter } from 'next/navigation'; diff --git a/apps/dashboard/src/modals/EditDashboard.tsx b/apps/dashboard/src/modals/EditDashboard.tsx index 52b8c500..a9b1e424 100644 --- a/apps/dashboard/src/modals/EditDashboard.tsx +++ b/apps/dashboard/src/modals/EditDashboard.tsx @@ -1,8 +1,8 @@ 'use client'; import { api, handleError } from '@/app/_trpc/client'; -import { ButtonContainer } from '@/components/ButtonContainer'; -import { InputWithLabel } from '@/components/forms/InputWithLabel'; +import { ButtonContainer } from '@/components/button-container'; +import { InputWithLabel } from '@/components/forms/input-with-label'; import { Button } from '@/components/ui/button'; import { zodResolver } from '@hookform/resolvers/zod'; import { useRouter } from 'next/navigation'; diff --git a/apps/dashboard/src/modals/EditProject.tsx b/apps/dashboard/src/modals/EditProject.tsx index f5c1a8e4..e148a67a 100644 --- a/apps/dashboard/src/modals/EditProject.tsx +++ b/apps/dashboard/src/modals/EditProject.tsx @@ -1,8 +1,8 @@ 'use client'; import { api, handleError } from '@/app/_trpc/client'; -import { ButtonContainer } from '@/components/ButtonContainer'; -import { InputWithLabel } from '@/components/forms/InputWithLabel'; +import { ButtonContainer } from '@/components/button-container'; +import { InputWithLabel } from '@/components/forms/input-with-label'; import { Button } from '@/components/ui/button'; import { zodResolver } from '@hookform/resolvers/zod'; import { useRouter } from 'next/navigation'; diff --git a/apps/dashboard/src/modals/EditReport.tsx b/apps/dashboard/src/modals/EditReport.tsx index bcbabab6..42f299be 100644 --- a/apps/dashboard/src/modals/EditReport.tsx +++ b/apps/dashboard/src/modals/EditReport.tsx @@ -1,7 +1,7 @@ 'use client'; -import { ButtonContainer } from '@/components/ButtonContainer'; -import { InputWithLabel } from '@/components/forms/InputWithLabel'; +import { ButtonContainer } from '@/components/button-container'; +import { InputWithLabel } from '@/components/forms/input-with-label'; import { Button } from '@/components/ui/button'; import { zodResolver } from '@hookform/resolvers/zod'; import type { SubmitHandler } from 'react-hook-form'; diff --git a/apps/dashboard/src/modals/SaveReport.tsx b/apps/dashboard/src/modals/SaveReport.tsx index 337301b4..b1ca490f 100644 --- a/apps/dashboard/src/modals/SaveReport.tsx +++ b/apps/dashboard/src/modals/SaveReport.tsx @@ -1,8 +1,8 @@ 'use client'; import { api, handleError } from '@/app/_trpc/client'; -import { ButtonContainer } from '@/components/ButtonContainer'; -import { InputWithLabel } from '@/components/forms/InputWithLabel'; +import { ButtonContainer } from '@/components/button-container'; +import { InputWithLabel } from '@/components/forms/input-with-label'; import { Button } from '@/components/ui/button'; import { Combobox } from '@/components/ui/combobox'; import { Label } from '@/components/ui/label'; @@ -36,7 +36,7 @@ export default function SaveReport({ report }: SaveReportProps) { const searchParams = useSearchParams(); const dashboardId = searchParams?.get('dashboardId') ?? undefined; - const save = api.report.save.useMutation({ + const save = api.report.create.useMutation({ onError: handleError, onSuccess(res) { toast('Success', { diff --git a/apps/dashboard/src/modals/ShareOverviewModal.tsx b/apps/dashboard/src/modals/ShareOverviewModal.tsx index 89cfe684..1e79e8c6 100644 --- a/apps/dashboard/src/modals/ShareOverviewModal.tsx +++ b/apps/dashboard/src/modals/ShareOverviewModal.tsx @@ -1,8 +1,8 @@ 'use client'; import { api, handleError } from '@/app/_trpc/client'; -import { ButtonContainer } from '@/components/ButtonContainer'; -import { InputWithLabel } from '@/components/forms/InputWithLabel'; +import { ButtonContainer } from '@/components/button-container'; +import { InputWithLabel } from '@/components/forms/input-with-label'; import { Button } from '@/components/ui/button'; import { Checkbox } from '@/components/ui/checkbox'; import { useAppParams } from '@/hooks/useAppParams'; diff --git a/apps/dashboard/src/server/api/root.ts b/apps/dashboard/src/server/api/root.ts index 0b09b4b7..17fecfc4 100644 --- a/apps/dashboard/src/server/api/root.ts +++ b/apps/dashboard/src/server/api/root.ts @@ -11,7 +11,6 @@ import { projectRouter } from './routers/project'; import { referenceRouter } from './routers/reference'; import { reportRouter } from './routers/report'; import { shareRouter } from './routers/share'; -import { uiRouter } from './routers/ui'; import { userRouter } from './routers/user'; /** @@ -29,7 +28,6 @@ export const appRouter = createTRPCRouter({ client: clientRouter, event: eventRouter, profile: profileRouter, - ui: uiRouter, share: shareRouter, onboarding: onboardingRouter, reference: referenceRouter, diff --git a/apps/dashboard/src/server/api/routers/chart.helpers.ts b/apps/dashboard/src/server/api/routers/chart.helpers.ts index 220dc277..204f1e42 100644 --- a/apps/dashboard/src/server/api/routers/chart.helpers.ts +++ b/apps/dashboard/src/server/api/routers/chart.helpers.ts @@ -1,10 +1,17 @@ -import { getDaysOldDate } from '@/utils/date'; import { round } from '@/utils/math'; +import { subDays } from 'date-fns'; import * as mathjs from 'mathjs'; -import { sort } from 'ramda'; +import { repeat, reverse, sort } from 'ramda'; import { alphabetIds, NOT_SET_VALUE } from '@openpanel/constants'; -import { chQuery, convertClickhouseDateToJs, getChartSql } from '@openpanel/db'; +import { + chQuery, + convertClickhouseDateToJs, + createSqlBuilder, + formatClickhouseDate, + getChartSql, + getEventFiltersWhereClause, +} from '@openpanel/db'; import type { IChartEvent, IChartInput, @@ -317,7 +324,7 @@ export function getDatesFromRange(range: IChartRange) { let days = 1; if (range === '24h') { - const startDate = getDaysOldDate(days); + const startDate = subDays(new Date(), days); const endDate = new Date(); return { startDate: startDate.toUTCString(), @@ -337,7 +344,7 @@ export function getDatesFromRange(range: IChartRange) { days = 365; } - const startDate = getDaysOldDate(days); + const startDate = subDays(new Date(), days); startDate.setUTCHours(0, 0, 0, 0); const endDate = new Date(); endDate.setUTCHours(23, 59, 59, 999); @@ -347,10 +354,197 @@ export function getDatesFromRange(range: IChartRange) { }; } -export function getChartStartEndDate( - input: Pick -) { - return input.startDate && input.endDate - ? { startDate: input.startDate, endDate: input.endDate } - : getDatesFromRange(input.range); +export function getChartStartEndDate({ + startDate, + endDate, + range, +}: Pick) { + return startDate && endDate + ? { startDate: startDate, endDate: endDate } + : getDatesFromRange(range); +} + +export function getChartPrevStartEndDate({ + startDate, + endDate, + range, +}: { + startDate: string; + endDate: string; + range: IChartRange; +}) { + let diff = 0; + + switch (range) { + case '30min': { + diff = 1000 * 60 * 30; + break; + } + case '1h': { + diff = 1000 * 60 * 60; + break; + } + case '24h': + case 'today': { + diff = 1000 * 60 * 60 * 24; + break; + } + case '7d': { + diff = 1000 * 60 * 60 * 24 * 7; + break; + } + case '14d': { + diff = 1000 * 60 * 60 * 24 * 14; + break; + } + case '1m': { + diff = 1000 * 60 * 60 * 24 * 30; + break; + } + case '3m': { + diff = 1000 * 60 * 60 * 24 * 90; + break; + } + case '6m': { + diff = 1000 * 60 * 60 * 24 * 180; + break; + } + } + + return { + startDate: new Date(new Date(startDate).getTime() - diff).toISOString(), + endDate: new Date(new Date(endDate).getTime() - diff).toISOString(), + }; +} + +export async function getFunnelData({ projectId, ...payload }: IChartInput) { + const { startDate, endDate } = getChartStartEndDate(payload); + + if (payload.events.length === 0) { + return { + totalSessions: 0, + steps: [], + }; + } + + const funnels = payload.events.map((event) => { + const { sb, getWhere } = createSqlBuilder(); + sb.where = getEventFiltersWhereClause(event.filters); + sb.where.name = `name = '${event.name}'`; + return getWhere().replace('WHERE ', ''); + }); + + const innerSql = `SELECT + session_id, + windowFunnel(6048000000000000,'strict_increase')(toUnixTimestamp(created_at), ${funnels.join(', ')}) AS level + FROM events + WHERE (project_id = '${projectId}' AND created_at >= '${formatClickhouseDate(startDate)}') AND (created_at <= '${formatClickhouseDate(endDate)}') + GROUP BY session_id`; + + const sql = `SELECT level, count() AS count FROM (${innerSql}) GROUP BY level ORDER BY level DESC`; + + const [funnelRes, sessionRes] = await Promise.all([ + chQuery<{ level: number; count: number }>(sql), + chQuery<{ count: number }>( + `SELECT count(name) as count FROM events WHERE project_id = '${projectId}' AND name = 'session_start' AND (created_at >= '${formatClickhouseDate(startDate)}') AND (created_at <= '${formatClickhouseDate(endDate)}')` + ), + ]); + + if (funnelRes[0]?.level !== payload.events.length) { + funnelRes.unshift({ + level: payload.events.length, + count: 0, + }); + } + + const totalSessions = sessionRes[0]?.count ?? 0; + const filledFunnelRes = funnelRes.reduce( + (acc, item, index) => { + const diff = + index !== 0 ? (acc[acc.length - 1]?.level ?? 0) - item.level : 1; + + if (diff > 1) { + acc.push( + ...reverse( + repeat({}, diff - 1).map((_, index) => ({ + count: acc[acc.length - 1]?.count ?? 0, + level: item.level + index + 1, + })) + ) + ); + } + + return [ + ...acc, + { + count: item.count + (acc[acc.length - 1]?.count ?? 0), + level: item.level, + }, + ]; + }, + [] as typeof funnelRes + ); + + const steps = reverse(filledFunnelRes) + .filter((item) => item.level !== 0) + .reduce( + (acc, item, index, list) => { + const prev = list[index - 1] ?? { count: totalSessions }; + return [ + ...acc, + { + event: payload.events[item.level - 1]!, + before: prev.count, + current: item.count, + dropoff: { + count: prev.count - item.count, + percent: 100 - (item.count / prev.count) * 100, + }, + percent: (item.count / totalSessions) * 100, + prevPercent: (prev.count / totalSessions) * 100, + }, + ]; + }, + [] as { + event: IChartEvent; + before: number; + current: number; + dropoff: { + count: number; + percent: number; + }; + percent: number; + prevPercent: number; + }[] + ); + + return { + totalSessions, + steps, + }; +} + +export async function getSeriesFromEvents(input: IChartInput) { + const { startDate, endDate } = + input.startDate && input.endDate + ? { + startDate: input.startDate, + endDate: input.endDate, + } + : getDatesFromRange(input.range); + + const series = ( + await Promise.all( + input.events.map(async (event) => + getChartData({ + ...input, + startDate, + endDate, + event, + }) + ) + ) + ).flat(); + + return withFormula(input, series); } diff --git a/apps/dashboard/src/server/api/routers/chart.ts b/apps/dashboard/src/server/api/routers/chart.ts index f4da0c29..20be96e7 100644 --- a/apps/dashboard/src/server/api/routers/chart.ts +++ b/apps/dashboard/src/server/api/routers/chart.ts @@ -4,132 +4,20 @@ import { publicProcedure, } from '@/server/api/trpc'; import { average, max, min, round, sum } from '@/utils/math'; -import { flatten, map, pipe, prop, repeat, reverse, sort, uniq } from 'ramda'; +import { flatten, map, pipe, prop, sort, uniq } from 'ramda'; import { z } from 'zod'; -import { - chQuery, - createSqlBuilder, - formatClickhouseDate, - getEventFiltersWhereClause, -} from '@openpanel/db'; +import { chQuery, createSqlBuilder } from '@openpanel/db'; import { zChartInput } from '@openpanel/validation'; import type { IChartEvent, IChartInput } from '@openpanel/validation'; import { - getChartData, + getChartPrevStartEndDate, getChartStartEndDate, - getDatesFromRange, - withFormula, + getFunnelData, + getSeriesFromEvents, } from './chart.helpers'; -async function getFunnelData({ projectId, ...payload }: IChartInput) { - const { startDate, endDate } = getChartStartEndDate(payload); - - if (payload.events.length === 0) { - return { - totalSessions: 0, - steps: [], - }; - } - - const funnels = payload.events.map((event) => { - const { sb, getWhere } = createSqlBuilder(); - sb.where = getEventFiltersWhereClause(event.filters); - sb.where.name = `name = '${event.name}'`; - return getWhere().replace('WHERE ', ''); - }); - - const innerSql = `SELECT - session_id, - windowFunnel(6048000000000000,'strict_increase')(toUnixTimestamp(created_at), ${funnels.join(', ')}) AS level - FROM events - WHERE (project_id = '${projectId}' AND created_at >= '${formatClickhouseDate(startDate)}') AND (created_at <= '${formatClickhouseDate(endDate)}') - GROUP BY session_id`; - - const sql = `SELECT level, count() AS count FROM (${innerSql}) GROUP BY level ORDER BY level DESC`; - - const [funnelRes, sessionRes] = await Promise.all([ - chQuery<{ level: number; count: number }>(sql), - chQuery<{ count: number }>( - `SELECT count(name) as count FROM events WHERE project_id = '${projectId}' AND name = 'session_start' AND (created_at >= '${formatClickhouseDate(startDate)}') AND (created_at <= '${formatClickhouseDate(endDate)}')` - ), - ]); - - if (funnelRes[0]?.level !== payload.events.length) { - funnelRes.unshift({ - level: payload.events.length, - count: 0, - }); - } - - const totalSessions = sessionRes[0]?.count ?? 0; - const filledFunnelRes = funnelRes.reduce( - (acc, item, index) => { - const diff = - index !== 0 ? (acc[acc.length - 1]?.level ?? 0) - item.level : 1; - - if (diff > 1) { - acc.push( - ...reverse( - repeat({}, diff - 1).map((_, index) => ({ - count: acc[acc.length - 1]?.count ?? 0, - level: item.level + index + 1, - })) - ) - ); - } - - return [ - ...acc, - { - count: item.count + (acc[acc.length - 1]?.count ?? 0), - level: item.level, - }, - ]; - }, - [] as typeof funnelRes - ); - - const steps = reverse(filledFunnelRes) - .filter((item) => item.level !== 0) - .reduce( - (acc, item, index, list) => { - const prev = list[index - 1] ?? { count: totalSessions }; - return [ - ...acc, - { - event: payload.events[item.level - 1]!, - before: prev.count, - current: item.count, - dropoff: { - count: prev.count - item.count, - percent: 100 - (item.count / prev.count) * 100, - }, - percent: (item.count / totalSessions) * 100, - prevPercent: (prev.count / totalSessions) * 100, - }, - ]; - }, - [] as { - event: IChartEvent; - before: number; - current: number; - dropoff: { - count: number; - percent: number; - }; - percent: number; - prevPercent: number; - }[] - ); - - return { - totalSessions, - steps, - }; -} - type PreviousValue = { value: number; diff: number | null; @@ -243,7 +131,7 @@ export const chartRouter = createTRPCRouter({ .replace(/^properties\./, '') .replace('.*.', '.%.')}')) as values`; } else { - sb.select.values = `${property} as values`; + sb.select.values = `distinct ${property} as values`; } const events = await chQuery<{ values: string[] }>(getSql()); @@ -266,57 +154,19 @@ export const chartRouter = createTRPCRouter({ // TODO: Make this private chart: publicProcedure.input(zChartInput).query(async ({ input }) => { - const { startDate, endDate } = getChartStartEndDate(input); - let diff = 0; + const currentPeriod = getChartStartEndDate(input); + const previousPeriod = getChartPrevStartEndDate({ + range: input.range, + ...currentPeriod, + }); - switch (input.range) { - case '30min': { - diff = 1000 * 60 * 30; - break; - } - case '1h': { - diff = 1000 * 60 * 60; - break; - } - case '24h': - case 'today': { - diff = 1000 * 60 * 60 * 24; - break; - } - case '7d': { - diff = 1000 * 60 * 60 * 24 * 7; - break; - } - case '14d': { - diff = 1000 * 60 * 60 * 24 * 14; - break; - } - case '1m': { - diff = 1000 * 60 * 60 * 24 * 30; - break; - } - case '3m': { - diff = 1000 * 60 * 60 * 24 * 90; - break; - } - case '6m': { - diff = 1000 * 60 * 60 * 24 * 180; - break; - } - } - - const promises = [getSeriesFromEvents(input)]; + const promises = [getSeriesFromEvents({ ...input, ...currentPeriod })]; if (input.previous) { promises.push( getSeriesFromEvents({ ...input, - ...{ - startDate: new Date( - new Date(startDate).getTime() - diff - ).toISOString(), - endDate: new Date(new Date(endDate).getTime() - diff).toISOString(), - }, + ...previousPeriod, }) ); } @@ -407,11 +257,11 @@ export const chartRouter = createTRPCRouter({ final.metrics.max = max(final.series.map((item) => item.metrics.max)); final.metrics.previous = { sum: getPreviousMetric( - sum(final.series.map((item) => item.metrics.sum)), + final.metrics.sum, sum(final.series.map((item) => item.metrics.previous.sum?.value ?? 0)) ), average: getPreviousMetric( - round(average(final.series.map((item) => item.metrics.average)), 2), + final.metrics.average, round( average( final.series.map( @@ -422,15 +272,16 @@ export const chartRouter = createTRPCRouter({ ) ), min: getPreviousMetric( - min(final.series.map((item) => item.metrics.min)), + final.metrics.min, min(final.series.map((item) => item.metrics.previous.min?.value ?? 0)) ), max: getPreviousMetric( - max(final.series.map((item) => item.metrics.max)), + final.metrics.max, max(final.series.map((item) => item.metrics.previous.max?.value ?? 0)) ), }; + // Sort by sum final.series = final.series.sort((a, b) => { if (input.chartType === 'linear') { const sumA = a.data.reduce((acc, item) => acc + (item.count ?? 0), 0); @@ -441,16 +292,11 @@ export const chartRouter = createTRPCRouter({ } }); - // await new Promise((res) => { - // setTimeout(() => { - // res(); - // }, 100); - // }); return final; }), }); -function getPreviousMetric( +export function getPreviousMetric( current: number, previous: number | null ): PreviousValue { @@ -483,28 +329,3 @@ function getPreviousMetric( value: previous, }; } - -async function getSeriesFromEvents(input: IChartInput) { - const { startDate, endDate } = - input.startDate && input.endDate - ? { - startDate: input.startDate, - endDate: input.endDate, - } - : getDatesFromRange(input.range); - - const series = ( - await Promise.all( - input.events.map(async (event) => - getChartData({ - ...input, - startDate, - endDate, - event, - }) - ) - ) - ).flat(); - - return withFormula(input, series); -} diff --git a/apps/dashboard/src/server/api/routers/client.ts b/apps/dashboard/src/server/api/routers/client.ts index aa989c74..f88b1a19 100644 --- a/apps/dashboard/src/server/api/routers/client.ts +++ b/apps/dashboard/src/server/api/routers/client.ts @@ -1,9 +1,9 @@ import { randomUUID } from 'crypto'; import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; -import { db } from '@/server/db'; import { z } from 'zod'; import { hashPassword, stripTrailingSlash } from '@openpanel/common'; +import { db, transformClient } from '@openpanel/db'; export const clientRouter = createTRPCRouter({ list: protectedProcedure @@ -76,7 +76,7 @@ export const clientRouter = createTRPCRouter({ }); return { - ...client, + ...transformClient(client), secret: input.cors ? null : secret, }; }), diff --git a/apps/dashboard/src/server/api/routers/dashboard.ts b/apps/dashboard/src/server/api/routers/dashboard.ts index 029bcf31..cf875407 100644 --- a/apps/dashboard/src/server/api/routers/dashboard.ts +++ b/apps/dashboard/src/server/api/routers/dashboard.ts @@ -1,60 +1,20 @@ import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; -import { db, getId } from '@/server/db'; +import { getId } from '@/utils/getDbId'; import { PrismaError } from 'prisma-error-enum'; import { z } from 'zod'; +import { db, getDashboardsByProjectId } from '@openpanel/db'; import type { Prisma } from '@openpanel/db'; export const dashboardRouter = createTRPCRouter({ - get: protectedProcedure - .input(z.object({ id: z.string() })) - .query(async ({ input }) => { - return db.dashboard.findUnique({ - where: { - id: input.id, - }, - }); - }), list: protectedProcedure .input( - z - .object({ - projectId: z.string(), - }) - .or( - z.object({ - organizationId: z.string(), - }) - ) + z.object({ + projectId: z.string(), + }) ) .query(async ({ input }) => { - if ('projectId' in input) { - return db.dashboard.findMany({ - where: { - project_id: input.projectId, - }, - orderBy: { - createdAt: 'desc', - }, - include: { - project: true, - }, - }); - } else { - return db.dashboard.findMany({ - where: { - project: { - organization_slug: input.organizationId, - }, - }, - include: { - project: true, - }, - orderBy: { - createdAt: 'desc', - }, - }); - } + return getDashboardsByProjectId(input.projectId); }), create: protectedProcedure .input( diff --git a/apps/dashboard/src/server/api/routers/onboarding.ts b/apps/dashboard/src/server/api/routers/onboarding.ts index e046f5c9..9da3096d 100644 --- a/apps/dashboard/src/server/api/routers/onboarding.ts +++ b/apps/dashboard/src/server/api/routers/onboarding.ts @@ -4,7 +4,12 @@ import { clerkClient } from '@clerk/nextjs'; import { z } from 'zod'; import { hashPassword, stripTrailingSlash } from '@openpanel/common'; -import { db } from '@openpanel/db'; +import { + db, + transformClient, + transformOrganization, + transformProject, +} from '@openpanel/db'; export const onboardingRouter = createTRPCRouter({ organziation: protectedProcedure @@ -41,12 +46,12 @@ export const onboardingRouter = createTRPCRouter({ }); return { - client: { + client: transformClient({ ...client, secret: input.cors ? null : secret, - }, - project, - organization: org, + }), + project: transformProject(project), + organization: transformOrganization(org), }; } diff --git a/apps/dashboard/src/server/api/routers/organization.ts b/apps/dashboard/src/server/api/routers/organization.ts index 395e323c..dc648f8b 100644 --- a/apps/dashboard/src/server/api/routers/organization.ts +++ b/apps/dashboard/src/server/api/routers/organization.ts @@ -9,7 +9,6 @@ export const organizationRouter = createTRPCRouter({ list: protectedProcedure.query(() => { return clerkClient.organizations.getOrganizationList(); }), - // first: protectedProcedure.query(() => getCurrentOrganization()), get: protectedProcedure .input( z.object({ diff --git a/apps/dashboard/src/server/api/routers/profile.ts b/apps/dashboard/src/server/api/routers/profile.ts index 2e3ee6a6..5d3c6a78 100644 --- a/apps/dashboard/src/server/api/routers/profile.ts +++ b/apps/dashboard/src/server/api/routers/profile.ts @@ -3,71 +3,12 @@ import { protectedProcedure, publicProcedure, } from '@/server/api/trpc'; -import { db } from '@/server/db'; import { flatten, map, pipe, prop, sort, uniq } from 'ramda'; import { z } from 'zod'; import { chQuery, createSqlBuilder } from '@openpanel/db'; export const profileRouter = createTRPCRouter({ - list: protectedProcedure - .input( - z.object({ - query: z.string().nullable(), - projectId: z.string(), - take: z.number().default(100), - skip: z.number().default(0), - }) - ) - .query(async ({ input: { take, skip, projectId, query } }) => { - return db.profile.findMany({ - take, - skip, - where: { - project_id: projectId, - ...(query - ? { - OR: [ - { - first_name: { - contains: query, - mode: 'insensitive', - }, - }, - { - last_name: { - contains: query, - mode: 'insensitive', - }, - }, - { - email: { - contains: query, - mode: 'insensitive', - }, - }, - ], - } - : {}), - }, - orderBy: { - createdAt: 'desc', - }, - }); - }), - get: protectedProcedure - .input( - z.object({ - id: z.string(), - }) - ) - .query(async ({ input: { id } }) => { - return db.profile.findUniqueOrThrow({ - where: { - id, - }, - }); - }), properties: protectedProcedure .input(z.object({ projectId: z.string() })) .query(async ({ input: { projectId } }) => { @@ -88,6 +29,7 @@ export const profileRouter = createTRPCRouter({ uniq )(properties); }), + values: publicProcedure .input( z.object({ diff --git a/apps/dashboard/src/server/api/routers/project.ts b/apps/dashboard/src/server/api/routers/project.ts index 9b8f87d3..61ffa9bb 100644 --- a/apps/dashboard/src/server/api/routers/project.ts +++ b/apps/dashboard/src/server/api/routers/project.ts @@ -1,8 +1,9 @@ import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; -import { db, getId } from '@/server/db'; -import { slug } from '@/utils/slug'; +import { getId } from '@/utils/getDbId'; import { z } from 'zod'; +import { db, getProjectsByOrganizationSlug } from '@openpanel/db'; + export const projectRouter = createTRPCRouter({ list: protectedProcedure .input( @@ -12,26 +13,9 @@ export const projectRouter = createTRPCRouter({ ) .query(async ({ input: { organizationId } }) => { if (organizationId === null) return []; + return getProjectsByOrganizationSlug(organizationId); + }), - return db.project.findMany({ - where: { - organization_slug: organizationId, - }, - }); - }), - get: protectedProcedure - .input( - z.object({ - id: z.string(), - }) - ) - .query(({ input: { id } }) => { - return db.project.findUniqueOrThrow({ - where: { - id, - }, - }); - }), update: protectedProcedure .input( z.object({ diff --git a/apps/dashboard/src/server/api/routers/report.ts b/apps/dashboard/src/server/api/routers/report.ts index 3767a594..95a68860 100644 --- a/apps/dashboard/src/server/api/routers/report.ts +++ b/apps/dashboard/src/server/api/routers/report.ts @@ -1,57 +1,11 @@ import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; -import { db } from '@/server/db'; import { z } from 'zod'; -import { transformReport } from '@openpanel/db'; +import { db } from '@openpanel/db'; import { zChartInput } from '@openpanel/validation'; export const reportRouter = createTRPCRouter({ - get: protectedProcedure - .input( - z.object({ - id: z.string(), - }) - ) - .query(({ input: { id } }) => { - return db.report - .findUniqueOrThrow({ - where: { - id, - }, - }) - .then(transformReport); - }), - list: protectedProcedure - .input( - z.object({ - projectId: z.string(), - dashboardId: z.string(), - }) - ) - .query(async ({ input: { projectId, dashboardId } }) => { - const [dashboard, reports] = await db.$transaction([ - db.dashboard.findUniqueOrThrow({ - where: { - id: dashboardId, - }, - }), - db.report.findMany({ - where: { - project_id: projectId, - dashboard_id: dashboardId, - }, - orderBy: { - createdAt: 'desc', - }, - }), - ]); - - return { - reports: reports.map(transformReport), - dashboard, - }; - }), - save: protectedProcedure + create: protectedProcedure .input( z.object({ report: zChartInput.omit({ projectId: true }), diff --git a/apps/dashboard/src/server/api/routers/share.ts b/apps/dashboard/src/server/api/routers/share.ts index 450d0044..2b456940 100644 --- a/apps/dashboard/src/server/api/routers/share.ts +++ b/apps/dashboard/src/server/api/routers/share.ts @@ -1,7 +1,7 @@ import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; -import { db } from '@/server/db'; import ShortUniqueId from 'short-unique-id'; +import { db } from '@openpanel/db'; import { zShareOverview } from '@openpanel/validation'; const uid = new ShortUniqueId({ length: 6 }); diff --git a/apps/dashboard/src/server/api/routers/ui.ts b/apps/dashboard/src/server/api/routers/ui.ts deleted file mode 100644 index 18ea02c5..00000000 --- a/apps/dashboard/src/server/api/routers/ui.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; -import { z } from 'zod'; - -export const uiRouter = createTRPCRouter({ - breadcrumbs: protectedProcedure - .input( - z.object({ - url: z.string(), - }) - ) - .query(({ input: { url } }) => { - const parts = url.split('/').filter(Boolean); - return parts; - }), -}); diff --git a/apps/dashboard/src/server/auth.ts b/apps/dashboard/src/server/auth.ts deleted file mode 100644 index 7ae3487b..00000000 --- a/apps/dashboard/src/server/auth.ts +++ /dev/null @@ -1,3 +0,0 @@ -export async function getSession() { - return true; -} diff --git a/apps/dashboard/src/server/cache.ts b/apps/dashboard/src/server/cache.ts deleted file mode 100644 index 1ce18bb9..00000000 --- a/apps/dashboard/src/server/cache.ts +++ /dev/null @@ -1,39 +0,0 @@ -const cache = new Map< - string, - { - expires: number; - data: any; - } ->(); - -export function get(key: string) { - const hit = cache.get(key); - if (hit) { - if (hit.expires > Date.now()) { - return hit.data; - } - cache.delete(key); - } - return null; -} - -export function set(key: string, expires: number, data: any) { - cache.set(key, { - expires: Date.now() + expires, - data, - }); -} - -export async function getOr( - key: string, - expires: number, - fn: () => Promise -): Promise { - const hit = get(key); - if (hit) { - return hit; - } - const data = await fn(); - set(key, expires, data); - return data; -} diff --git a/apps/dashboard/src/styles/globals.css b/apps/dashboard/src/styles/globals.css index 08cd73d3..8737cbb2 100644 --- a/apps/dashboard/src/styles/globals.css +++ b/apps/dashboard/src/styles/globals.css @@ -126,44 +126,6 @@ } } -.resizer { - position: absolute; - right: 0; - top: 0; - height: 100%; - width: 5px; - background: rgba(0, 0, 0, 0.1); - cursor: col-resize; - user-select: none; - touch-action: none; -} - -.resizer.isResizing { - @apply bg-black; - opacity: 1; -} - -@media (hover: hover) { - .resizer { - opacity: 0; - } - - *:hover > .resizer { - opacity: 1; - } -} - -/* For Webkit-based browsers (Chrome, Safari and Opera) */ -.scrollbar-hide::-webkit-scrollbar { - display: none; -} - -/* For IE, Edge and Firefox */ -.scrollbar-hide { - -ms-overflow-style: none; /* IE and Edge */ - scrollbar-width: none; /* Firefox */ -} - /* Rechart */ .recharts-wrapper .recharts-cartesian-grid-horizontal line:first-child, diff --git a/apps/dashboard/src/utils/date.ts b/apps/dashboard/src/utils/date.ts index bf8179dc..4f23fe6e 100644 --- a/apps/dashboard/src/utils/date.ts +++ b/apps/dashboard/src/utils/date.ts @@ -1,9 +1,3 @@ -export function getDaysOldDate(days: number) { - const date = new Date(); - date.setDate(date.getDate() - days); - return date; -} - export function dateDifferanceInDays(date1: Date, date2: Date) { const diffTime = Math.abs(date2.getTime() - date1.getTime()); return Math.ceil(diffTime / (1000 * 60 * 60 * 24)); diff --git a/apps/dashboard/src/server/db.ts b/apps/dashboard/src/utils/getDbId.ts similarity index 83% rename from apps/dashboard/src/server/db.ts rename to apps/dashboard/src/utils/getDbId.ts index 183f31b3..600be848 100644 --- a/apps/dashboard/src/server/db.ts +++ b/apps/dashboard/src/utils/getDbId.ts @@ -1,8 +1,6 @@ -import { slug } from '@/utils/slug'; - import { db } from '@openpanel/db'; -export { db } from '@openpanel/db'; +import { slug } from './slug'; export async function getId(tableName: 'project' | 'dashboard', name: string) { const newId = slug(name); @@ -15,7 +13,7 @@ export async function getId(tableName: 'project' | 'dashboard', name: string) { } // @ts-expect-error - const existingProject = await db[tableName]!.findUnique({ + const existingProject = await db[tableName].findUnique({ where: { id: newId, }, diff --git a/apps/dashboard/src/utils/getters.ts b/apps/dashboard/src/utils/getters.ts deleted file mode 100644 index 1257b551..00000000 --- a/apps/dashboard/src/utils/getters.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { IServiceProfile } from '@openpanel/db'; - -export function getProfileName(profile: IServiceProfile | undefined | null) { - if (!profile) return 'No profile'; - return [profile.first_name, profile.last_name].filter(Boolean).join(' '); -} diff --git a/packages/db/src/services/clients.service.ts b/packages/db/src/services/clients.service.ts index bd29220a..417d3df2 100644 --- a/packages/db/src/services/clients.service.ts +++ b/packages/db/src/services/clients.service.ts @@ -1,14 +1,22 @@ import type { Client } from '../prisma-client'; import { db } from '../prisma-client'; +import { transformProject } from './project.service'; import type { IServiceProject } from './project.service'; -export type IServiceClient = Client; -export type IServiceClientWithProject = Client & { +export type IServiceClient = ReturnType; +export type IServiceClientWithProject = IServiceClient & { project: Exclude; }; -export function getClientsByOrganizationId(organizationId: string) { - return db.client.findMany({ +export function transformClient({ organization_slug, ...client }: Client) { + return { + ...client, + organizationSlug: organization_slug, + }; +} + +export async function getClientsByOrganizationId(organizationId: string) { + const clients = await db.client.findMany({ where: { organization_slug: organizationId, }, @@ -16,4 +24,15 @@ export function getClientsByOrganizationId(organizationId: string) { project: true, }, }); + + return clients + .map((client) => { + return { + ...transformClient(client), + project: transformProject(client.project), + }; + }) + .filter( + (client): client is IServiceClientWithProject => client.project !== null + ); } diff --git a/packages/db/src/services/dashboard.service.ts b/packages/db/src/services/dashboard.service.ts index 52bae331..16f4e65e 100644 --- a/packages/db/src/services/dashboard.service.ts +++ b/packages/db/src/services/dashboard.service.ts @@ -23,22 +23,6 @@ export async function getDashboardById(id: string, projectId: string) { return dashboard; } -export async function getDashboardsByOrganization(organizationSlug: string) { - return db.dashboard.findMany({ - where: { - organization_slug: organizationSlug, - }, - include: { - project: true, - }, - orderBy: { - reports: { - _count: 'desc', - }, - }, - }); -} - export function getDashboardsByProjectId(projectId: string) { return db.dashboard.findMany({ where: { diff --git a/packages/db/src/services/organization.service.ts b/packages/db/src/services/organization.service.ts index 0327e658..a4456d41 100644 --- a/packages/db/src/services/organization.service.ts +++ b/packages/db/src/services/organization.service.ts @@ -12,7 +12,7 @@ export type IServiceOrganization = Awaited< export type IServiceInvites = Awaited>; -function transformOrganization(org: Organization) { +export function transformOrganization(org: Organization) { return { id: org.id, name: org.name, diff --git a/packages/db/src/services/profile.service.ts b/packages/db/src/services/profile.service.ts index 9dbc7fcd..5a1451cf 100644 --- a/packages/db/src/services/profile.service.ts +++ b/packages/db/src/services/profile.service.ts @@ -129,7 +129,7 @@ export async function getProfilesByExternalId( export type IServiceProfile = Omit< IClickhouseProfile, - 'max_created_at' | 'properties' + 'max_created_at' | 'properties' | 'first_name' | 'last_name' > & { firstName: string; lastName: string; @@ -169,12 +169,14 @@ export interface IServiceUpsertProfile { function transformProfile({ max_created_at, + first_name, + last_name, ...profile }: IClickhouseProfile): IServiceProfile { return { ...profile, - firstName: profile.first_name, - lastName: profile.last_name, + firstName: first_name, + lastName: last_name, properties: toObject(profile.properties), createdAt: new Date(max_created_at), }; @@ -216,3 +218,8 @@ export async function upsertProfile({ ], }); } + +export function getProfileName(profile: IServiceProfile | undefined | null) { + if (!profile) return 'No name'; + return [profile.firstName, profile.lastName].filter(Boolean).join(' '); +} diff --git a/packages/db/src/services/project.service.ts b/packages/db/src/services/project.service.ts index 47cc2a14..044cdc21 100644 --- a/packages/db/src/services/project.service.ts +++ b/packages/db/src/services/project.service.ts @@ -1,9 +1,9 @@ import type { Project } from '../prisma-client'; import { db } from '../prisma-client'; -export type IServiceProject = ReturnType; +export type IServiceProject = ReturnType; -function transform({ organization_slug, ...project }: Project) { +export function transformProject({ organization_slug, ...project }: Project) { return { organizationSlug: organization_slug, ...project, @@ -21,7 +21,7 @@ export async function getProjectById(id: string) { return null; } - return transform(res); + return transformProject(res); } export async function getProjectsByOrganizationSlug(slug: string) { @@ -31,5 +31,5 @@ export async function getProjectsByOrganizationSlug(slug: string) { }, }); - return res.map(transform); + return res.map(transformProject); } diff --git a/packages/db/src/services/reference.service.ts b/packages/db/src/services/reference.service.ts index 3a8023b3..043a6cc0 100644 --- a/packages/db/src/services/reference.service.ts +++ b/packages/db/src/services/reference.service.ts @@ -1,13 +1,11 @@ import type { Prisma, Reference } from '../prisma-client'; import { db } from '../prisma-client'; -// import type { Report as DbReport } from '../prisma-client'; - export type IServiceReference = Omit & { projectId: string; }; -export function transform({ +export function transformReference({ project_id, ...item }: Reference): IServiceReference { @@ -28,7 +26,7 @@ export async function getReferenceById(id: string) { return null; } - return transform(reference); + return transformReference(reference); } export async function getReferences({ @@ -46,5 +44,5 @@ export async function getReferences({ skip, }); - return references.map(transform); + return references.map(transformReference); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 335af6e2..8bff5760 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -216,6 +216,9 @@ importers: bcrypt: specifier: ^5.1.1 version: 5.1.1 + bind-event-listener: + specifier: ^3.0.0 + version: 3.0.0 class-variance-authority: specifier: ^0.7.0 version: 0.7.0 @@ -3162,7 +3165,7 @@ packages: '@expo/rudder-sdk-node': 1.1.1 '@expo/spawn-async': 1.5.0 '@expo/xcpretty': 4.3.1 - '@react-native/dev-middleware': 0.73.7 + '@react-native/dev-middleware': 0.73.8 '@urql/core': 2.3.6(graphql@15.8.0) '@urql/exchange-retry': 0.3.0(graphql@15.8.0) accepts: 1.3.8 @@ -5992,25 +5995,6 @@ packages: engines: {node: '>=18'} dev: false - /@react-native/dev-middleware@0.73.7: - resolution: {integrity: sha512-BZXpn+qKp/dNdr4+TkZxXDttfx8YobDh8MFHsMk9usouLm22pKgFIPkGBV0X8Do4LBkFNPGtrnsKkWk/yuUXKg==} - engines: {node: '>=18'} - dependencies: - '@isaacs/ttlcache': 1.4.1 - '@react-native/debugger-frontend': 0.73.3 - chrome-launcher: 0.15.2 - chromium-edge-launcher: 1.0.0 - connect: 3.7.0 - debug: 2.6.9 - node-fetch: 2.7.0 - open: 7.4.2 - serve-static: 1.15.0 - temp-dir: 2.0.0 - transitivePeerDependencies: - - encoding - - supports-color - dev: false - /@react-native/dev-middleware@0.73.8: resolution: {integrity: sha512-oph4NamCIxkMfUL/fYtSsE+JbGOnrlawfQ0kKtDQ5xbOjPKotKoXqrs1eGwozNKv7FfQ393stk1by9a6DyASSg==} engines: {node: '>=18'} @@ -7666,6 +7650,10 @@ packages: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} + /bind-event-listener@3.0.0: + resolution: {integrity: sha512-PJvH288AWQhKs2v9zyfYdPzlPqf5bXbGMmhmUIY9x4dAUGIWgomO771oBQNwJnMQSnUIXhKu6sgzpBRXTlvb8Q==} + dev: false + /bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} dependencies: