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) {