diff --git a/frontend/src/lib/components/EmptyMessage/EmptyMessage.tsx b/frontend/src/lib/components/EmptyMessage/EmptyMessage.tsx index c60ae07df27b7..e7e8ea3eecfbe 100644 --- a/frontend/src/lib/components/EmptyMessage/EmptyMessage.tsx +++ b/frontend/src/lib/components/EmptyMessage/EmptyMessage.tsx @@ -5,7 +5,7 @@ import { LemonButton } from 'lib/lemon-ui/LemonButton' export interface EmptyMessageProps { title: string description: string - buttonText: string + buttonText?: string buttonTo?: string } @@ -16,9 +16,11 @@ export function EmptyMessage({ title, description, buttonText, buttonTo }: Empty

{title}

{description}

- - {buttonText} - + {buttonText && ( + + {buttonText} + + )} ) diff --git a/frontend/src/scenes/error-tracking/ErrorTracking.scss b/frontend/src/scenes/error-tracking/ErrorTracking.scss new file mode 100644 index 0000000000000..fb8d2147a2d1b --- /dev/null +++ b/frontend/src/scenes/error-tracking/ErrorTracking.scss @@ -0,0 +1,4 @@ +.ErrorTracking__group { + height: calc(100vh - 13rem); + min-height: 41rem; +} diff --git a/frontend/src/scenes/error-tracking/ErrorTrackingGroupScene.tsx b/frontend/src/scenes/error-tracking/ErrorTrackingGroupScene.tsx index 10015b17d9ad4..d7509e87aa99e 100644 --- a/frontend/src/scenes/error-tracking/ErrorTrackingGroupScene.tsx +++ b/frontend/src/scenes/error-tracking/ErrorTrackingGroupScene.tsx @@ -1,12 +1,15 @@ -import { PersonDisplay } from '@posthog/apps-common' -import { LemonButton, LemonTabs, Spinner } from '@posthog/lemon-ui' +import './ErrorTracking.scss' + +import { PersonDisplay, TZLabel } from '@posthog/apps-common' +import { Spinner } from '@posthog/lemon-ui' +import clsx from 'clsx' import { useValues } from 'kea' +import { EmptyMessage } from 'lib/components/EmptyMessage/EmptyMessage' import { ErrorDisplay } from 'lib/components/Errors/ErrorDisplay' import { NotFound } from 'lib/components/NotFound' -import { IconChevronLeft, IconChevronRight } from 'lib/lemon-ui/icons' -import { useState } from 'react' +import { Playlist } from 'lib/components/Playlist/Playlist' import { SceneExport } from 'scenes/sceneTypes' -import { SessionRecordingsPlaylist } from 'scenes/session-recordings/playlist/SessionRecordingsPlaylist' +import { PropertyIcons } from 'scenes/session-recordings/playlist/SessionRecordingPreview' import { ErrorTrackingFilters } from './ErrorTrackingFilters' import { errorTrackingGroupSceneLogic, ExceptionEventType } from './errorTrackingGroupSceneLogic' @@ -21,79 +24,75 @@ export const scene: SceneExport = { export function ErrorTrackingGroupScene(): JSX.Element { const { events, eventsLoading } = useValues(errorTrackingGroupSceneLogic) - const [activeTab, setActiveTab] = useState<'details' | 'recordings'>('details') return eventsLoading ? ( ) : events && events.length > 0 ? ( -
+
- , - }, - { - key: 'recordings', - label: 'Recordings', - content: ( - e.properties.$session_id).filter(Boolean)} - /> - ), - }, - ]} - activeKey={activeTab} - onChange={setActiveTab} - /> + +
+
+ Empty
} + content={({ activeItem: event }) => + event ? ( +
+ +
+ ) : ( + + ) + } + /> +
+
) : ( ) } -const ExceptionDetails = ({ events }: { events: ExceptionEventType[] }): JSX.Element => { - const [activeEventId, setActiveEventId] = useState(events.length - 1) +const ListItemException = ({ item: event, isActive }: { item: ExceptionEventType; isActive: boolean }): JSX.Element => { + const properties = ['$browser', '$device_type', '$os'] + .flatMap((property) => { + let value = event.properties[property] + const label = value + if (property === '$device_type') { + value = event.properties['$device_type'] || event.properties['$initial_device_type'] + } - const event = events[activeEventId] + return { property, value, label } + }) + .filter((property) => !!property.value) return ( -
- {events.length > 1 && ( -
- } - onClick={() => setActiveEventId(activeEventId - 1)} - disabledReason={activeEventId <= 0 && 'No earlier examples'} - /> - } - onClick={() => setActiveEventId(activeEventId + 1)} - disabledReason={activeEventId >= events.length - 1 && 'No newer examples'} - /> - - {activeEventId + 1} of {events.length} - -
- )} -
+
+
+
- -
- ) -} - -const ExceptionRecordings = ({ sessionIds }: { sessionIds: string[] }): JSX.Element => { - return ( -
- + {event.properties.$current_url && ( +
{event.properties.$current_url}
+ )} +
) } diff --git a/frontend/src/scenes/error-tracking/errorTrackingGroupSceneLogic.ts b/frontend/src/scenes/error-tracking/errorTrackingGroupSceneLogic.ts index 95490466861ea..1a7685e2ed1b9 100644 --- a/frontend/src/scenes/error-tracking/errorTrackingGroupSceneLogic.ts +++ b/frontend/src/scenes/error-tracking/errorTrackingGroupSceneLogic.ts @@ -14,7 +14,7 @@ export interface ErrorTrackingGroupSceneLogicProps { id: string } -export type ExceptionEventType = Pick +export type ExceptionEventType = Pick export const errorTrackingGroupSceneLogic = kea([ path((key) => ['scenes', 'error-tracking', 'errorTrackingGroupSceneLogic', key]), @@ -39,9 +39,10 @@ export const errorTrackingGroupSceneLogic = kea ({ - properties: JSON.parse(r[0]), - timestamp: r[1], - person: r[2], + id: r[0], + properties: JSON.parse(r[1]), + timestamp: r[2], + person: r[3], })) }, }, diff --git a/frontend/src/scenes/error-tracking/queries.ts b/frontend/src/scenes/error-tracking/queries.ts index 5729c81a991d3..3502dabe8f901 100644 --- a/frontend/src/scenes/error-tracking/queries.ts +++ b/frontend/src/scenes/error-tracking/queries.ts @@ -54,7 +54,7 @@ export const errorTrackingGroupQuery = ({ }): EventsQuery => { return { kind: NodeKind.EventsQuery, - select: ['properties', 'timestamp', 'person'], + select: ['uuid', 'properties', 'timestamp', 'person'], where: [`properties.$exception_type = '${group}'`], ...defaultProperties({ dateRange, filterTestAccounts, filterGroup }), }