diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/page.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/page.tsx index 8821e926..098e4b99 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/page.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/[profileId]/page.tsx @@ -1,29 +1,25 @@ -import { Suspense, useMemo } from 'react'; +import { Suspense } from 'react'; import PageLayout from '@/app/(app)/[organizationSlug]/[projectId]/page-layout'; +import ClickToCopy from '@/components/click-to-copy'; import { ListPropertiesIcon } from '@/components/events/list-properties-icon'; -import { OverviewFiltersButtons } from '@/components/overview/filters/overview-filters-buttons'; -import { OverviewFiltersDrawer } from '@/components/overview/filters/overview-filters-drawer'; import { ProfileAvatar } from '@/components/profiles/profile-avatar'; import { ChartSwitch } from '@/components/report/chart'; -import { SerieIcon } from '@/components/report/chart/SerieIcon'; +import { Tooltiper } from '@/components/ui/tooltip'; import { Widget, WidgetBody, WidgetHead } from '@/components/widget'; import { eventQueryFiltersParser, eventQueryNamesFilter, } from '@/hooks/useEventQueryFilters'; +import { clipboard } from '@/utils/clipboard'; import { getProfileName } from '@/utils/getters'; +import { CopyIcon } from 'lucide-react'; import { notFound } from 'next/navigation'; import { parseAsInteger, parseAsString } from 'nuqs'; +import { toast } from 'sonner'; import type { GetEventListOptions } from '@openpanel/db'; -import { - getConversionEventNames, - getEventList, - getEventsCount, - getProfileById, - getProfileMetrics, -} from '@openpanel/db'; -import type { IChartEvent, IChartInput } from '@openpanel/validation'; +import { getEventList, getEventsCount, getProfileById } from '@openpanel/db'; +import type { IChartInput } from '@openpanel/validation'; import { EventList } from '../../events/event-list'; import { StickyBelowHeader } from '../../layout-sticky-below-header'; @@ -147,10 +143,12 @@ export default async function Page({
-

- {getProfileName(profile)} -

-
+ +

+ {getProfileName(profile)} +

+
+
diff --git a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profile-list/profile-list.tsx b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profile-list/profile-list.tsx index b8eabb54..7071b372 100644 --- a/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profile-list/profile-list.tsx +++ b/apps/dashboard/src/app/(app)/[organizationSlug]/[projectId]/profiles/profile-list/profile-list.tsx @@ -50,6 +50,7 @@ export function ProfileList({ data, count, limit = 50 }: ProfileListProps) { {getProfileName(profile)} diff --git a/apps/dashboard/src/components/click-to-copy.tsx b/apps/dashboard/src/components/click-to-copy.tsx new file mode 100644 index 00000000..f33ae5a0 --- /dev/null +++ b/apps/dashboard/src/components/click-to-copy.tsx @@ -0,0 +1,30 @@ +'use client'; + +import { clipboard } from '@/utils/clipboard'; +import { toast } from 'sonner'; + +import { Tooltiper } from './ui/tooltip'; + +type Props = { + children: React.ReactNode; + className?: string; + value: string; +}; + +const ClickToCopy = ({ children, value }: Props) => { + return ( + { + clipboard(value); + toast('Copied to clipboard'); + }} + > + {children} + + ); +}; + +export default ClickToCopy; diff --git a/apps/dashboard/src/components/events/list-properties-icon.tsx b/apps/dashboard/src/components/events/list-properties-icon.tsx index 6e9fa9c3..b89654a8 100644 --- a/apps/dashboard/src/components/events/list-properties-icon.tsx +++ b/apps/dashboard/src/components/events/list-properties-icon.tsx @@ -1,5 +1,10 @@ import { SerieIcon } from '../report/chart/SerieIcon'; -import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'; +import { + Tooltip, + TooltipContent, + Tooltiper, + TooltipTrigger, +} from '../ui/tooltip'; interface Props { country?: string; @@ -23,46 +28,26 @@ export function ListPropertiesIcon({ referrer_type, }: Props) { return ( -
+
{country && ( - - - - - - {country}, {city} - - + + + )} {os && ( - - - - - - {os} ({os_version}) - - + + + )} {browser && ( - - - - - - {browser} ({browser_version}) - - + + + )} {referrer_name && ( - - - - - - {referrer_name} ({referrer_type}) - - + + + )}
); diff --git a/apps/dashboard/src/components/ui/tooltip.tsx b/apps/dashboard/src/components/ui/tooltip.tsx index 3dd7e3bc..978f2070 100644 --- a/apps/dashboard/src/components/ui/tooltip.tsx +++ b/apps/dashboard/src/components/ui/tooltip.tsx @@ -38,20 +38,22 @@ interface TooltiperProps { content: string; children: React.ReactNode; className?: string; + onClick?: () => void; } export function Tooltiper({ asChild, content, children, className, + onClick, }: TooltiperProps) { return ( - - + + {children} - {content} + {content} ); diff --git a/apps/dashboard/src/components/widget-table.tsx b/apps/dashboard/src/components/widget-table.tsx index 85efcbf8..54ab6a24 100644 --- a/apps/dashboard/src/components/widget-table.tsx +++ b/apps/dashboard/src/components/widget-table.tsx @@ -36,26 +36,28 @@ export function WidgetTable({ keyExtractor, }: Props) { return ( - - - - {columns.map((column) => ( - - ))} - - - - {data.map((item) => ( - +
+
{column.name}
+ + {columns.map((column) => ( - + ))} - ))} - -
{column.render(item)}{column.name}
+ + + {data.map((item) => ( + + {columns.map((column) => ( + {column.render(item)} + ))} + + ))} + + +
); } diff --git a/apps/dashboard/src/utils/getters.ts b/apps/dashboard/src/utils/getters.ts index f8e2afe4..f5d8f6cd 100644 --- a/apps/dashboard/src/utils/getters.ts +++ b/apps/dashboard/src/utils/getters.ts @@ -1,9 +1,15 @@ import type { IServiceProfile } from '@openpanel/db'; -export function getProfileName(profile: IServiceProfile | undefined | null) { +export function getProfileName( + profile: IServiceProfile | undefined | null, + short = true +) { if (!profile) return 'Unknown'; if (!profile.isExternal) { + if (short) { + return profile.id.slice(0, 4) + '...' + profile.id.slice(-4); + } return profile.id; }