diff --git a/developer-extension/src/panel/components/tabs/eventsTab/eventRow.tsx b/developer-extension/src/panel/components/tabs/eventsTab/eventRow.tsx index 4444cab422..4192a64110 100644 --- a/developer-extension/src/panel/components/tabs/eventsTab/eventRow.tsx +++ b/developer-extension/src/panel/components/tabs/eventsTab/eventRow.tsx @@ -11,6 +11,7 @@ import type { RumLongTaskEvent, RumResourceEvent, RumViewEvent, + RumViewUpdateEvent, RumVitalEvent, } from '../../../../../../packages/rum-core/src/rumEvent.types' import type { SdkEvent } from '../../../sdkEvent' @@ -31,11 +32,11 @@ const RUM_EVENT_TYPE_COLOR = { error: 'red', long_task: 'yellow', view: 'blue', + view_update: 'blue', resource: 'cyan', telemetry: 'teal', vital: 'orange', transition: 'green', - view_update: 'blue', } const LOG_STATUS_COLOR = { @@ -288,6 +289,8 @@ export const EventDescription = React.memo(({ event }: { event: SdkEvent }) => { switch (event.type) { case 'view': return + case 'view_update': + return case 'long_task': return case 'error': @@ -338,6 +341,38 @@ function ViewDescription({ event }: { event: RumViewEvent }) { ) } +// view.id is always present in a view_update diff as a routing field to identify the view +const VIEW_UPDATE_ROUTING_KEYS = new Set(['id']) + +function ViewUpdateDescription({ event }: { event: RumViewUpdateEvent }) { + const changedFieldCount = event.view + ? Object.keys(event.view).filter((k) => !VIEW_UPDATE_ROUTING_KEYS.has(k)).length + : 0 + const viewName = event.view + ? event.view.url + ? getViewName({ name: event.view.name, url: event.view.url }) + : event.view.name + : undefined + + return ( + <> + View update{event._dd && v{event._dd.document_version}} + {viewName && ( + <> + {' '} + · {viewName} + + )} + {changedFieldCount > 0 && ( + <> + {' '} + · {changedFieldCount} {changedFieldCount === 1 ? 'field' : 'fields'} changed + + )} + + ) +} + function ActionDescription({ event }: { event: RumActionEvent }) { const actionName = event.action.target?.name const frustrationTypes = event.action.frustration?.type @@ -425,5 +460,5 @@ function Emphasis({ children }: { children: ReactNode }) { } function getViewName(view: { name?: string; url: string }) { - return `${view.name || new URL(view.url).pathname}` + return view.name ?? new URL(view.url).pathname } diff --git a/developer-extension/src/panel/hooks/useEvents/eventCollection.ts b/developer-extension/src/panel/hooks/useEvents/eventCollection.ts index cabe19636f..60df82c1b0 100644 --- a/developer-extension/src/panel/hooks/useEvents/eventCollection.ts +++ b/developer-extension/src/panel/hooks/useEvents/eventCollection.ts @@ -40,15 +40,15 @@ function compareEvents(a: SdkEvent, b: SdkEvent) { return b.date - a.date } - // If two events have the same date, make sure to display View events last. This ensures that View - // updates are collocated in the list (no other event are present between two updates) + // If two events have the same date, make sure to display type:view events last. This ensures that + // view events are collocated in the list (no other events appear between two view updates). // - // For example, we can receive an initial View event, then a 'document' Resource event, then a - // View event update. All of those events have the same date (navigationStart). If we only relied + // For example, we can receive an initial type:view event, then a 'document' Resource event, then + // a type:view update. All of those events have the same date (navigationStart). If we only relied // on the event date, events would be displayed in the order they are received, so the Resource - // event would be displayed between the two View events, which makes it a bit confusing. This - // ensures that all View updates are displayed before the Resource event. - return (isRumViewEvent(a) as any) - (isRumViewEvent(b) as any) + // event would be displayed between the two type:view events, which is confusing. This ensures + // that type:view events are grouped at the end. + return Number(isRumViewEvent(a)) - Number(isRumViewEvent(b)) } function listenEventsFromRequests(callback: (events: SdkEvent[]) => void) {