Files
openobserve/web/src/composables/useEventFormatters.ts
T
Omkar Kesarkhane 2e4fb93291 fix: RUM session event details drawer UI improvements (#10329)
### **PR Type**
Enhancement, Bug fix


___

### **Description**
- Add tabbed RUM event details drawer

- Centralize RUM event formatting utilities

- Improve sidebar filtering and null safety

- Sync dashboard chart zoom to time range


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["RUM Session Viewer UI"] 
  B["Event detail drawer tabs (Overview/Network/Attributes)"]
  C["Shared formatter composable (`useEventFormatters`)"]
  D["Network resources list from related events"]
  E["Clipboard copy + JSON highlighting"]
  F["Dashboards emit `update:dateTime` on zoom"]
  G["Sidebar event type filter behavior"]
  H["Session email null-safety"]
  A -- "refactor + UX" --> B
  B -- "uses" --> C
  B -- "derives" --> D
  B -- "adds" --> E
  A -- "interactions" --> F
  A -- "filtering" --> G
  A -- "stability" --> H
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>14
files</summary><table>
<tr>
<td><strong>useEventFormatters.ts</strong><dd><code>Add shared
formatting helpers for RUM events</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-d301f514502d418578addfb8a9332f18193ec77414fe2de5f86584eaccf89a43">+88/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>LogsHighLighting.vue</strong><dd><code>Import highlighting
stylesheet via scoped SCSS</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-4ef4ac0444004add270de4da30fa39bafd95bd7f1c408d28cf6737655fc152eb">+4/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>EventDetailDrawerContent.vue</strong><dd><code>Redesign
drawer with tabs, copy, network</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-e31bfc4c2d218ac4beaa9110939974f0461a818a7d5d169279e2ff58dec8136c">+479/-353</a></td>

</tr>

<tr>
<td><strong>EventDetailsSection.vue</strong><dd><code>Add reusable
key-value section renderer</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-eb9d64194e4354ce8babdb843029087b4d0813100046f6de6fd2605816eede58">+67/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>EventTypeBadge.vue</strong><dd><code>Add reusable event type
badge component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-78d3b36f54018d0cc31a0ed96800588bacb5b3f6e608803f32e704e576d89001">+49/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>KeyValueRow.vue</strong><dd><code>Add reusable labeled
key-value row component</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-978f05f4c50530f6d772579c54478e1aef10b7f7b066f2769e9d34c62c488895">+53/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>PerformanceMetrics.vue</strong><dd><code>Add wrapper
component for performance metrics</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-7c9e28cabc9dd4189346dadc26dcb4def95a9265557144e99128a9f3b951c21e">+60/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>ActionPerformanceMetrics.vue</strong><dd><code>Add action
performance metric cards and statuses</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-cd6683a885104c9e5074ab1c2b97bed5275cffa688da905f539bef98efdb4ec8">+98/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>ErrorPerformanceMetrics.vue</strong><dd><code>Add error
performance metric cards and statuses</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-1fc102647ba527cfd553f4c0fd723f1b72fabbd85bad7518e0a826a09d858442">+76/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>MetricCard.vue</strong><dd><code>Add generic metric card
with formatting</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-3666ababe7e5a472c88da967ba6e5e632dfd907abb8555a6bb4baeabc0215e32">+168/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>ResourcePerformanceMetrics.vue</strong><dd><code>Add
resource timing breakdown metric cards</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-9dfcf79c8b3c1b1c0e43bc8e65c90a6cd6b75c84b7de8250f18ba985ef36ad55">+128/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>ViewPerformanceMetrics.vue</strong><dd><code>Add web vitals
and view metric cards</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-0ddb74b6ef8bdb8656c47fb4065e4add8ba853f5834fbf3e59087623b054aa2b">+172/-0</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>ErrorsDashboard.vue</strong><dd><code>Emit zoom events to
update time range</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-46138c05241c5e0911a0feba39a21dbb8452453c0e26a1d00c3493cc579f07b2">+8/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>WebVitalsDashboard.vue</strong><dd><code>Emit zoom events
and support dateTime updates</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-bbb15649f6ecf4b2968a8173091ef8b2a21bfe39bff8e08f91566bca189cca09">+9/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Miscellaneous</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>zincutils.ts</strong><dd><code>Adjust formatting and utility
function style</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-d3d59688cccdcc6c84ebe88b698c6910030abecc3125f4c0ef81b0df023699ba">+26/-14</a>&nbsp;
</td>

</tr>
</table></details></td></tr><tr><td><strong>Bug
fix</strong></td><td><details><summary>2 files</summary><table>
<tr>
<td><strong>PlayerEventsSidebar.vue</strong><dd><code>Improve
multiselect UX and filtering logic</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-a7d04eb87cd7588ba4811d79c6d32696a58d737a24931258329be4f96cee7610">+39/-10</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>SessionViewer.vue</strong><dd><code>Guard session email
access with optional chaining</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10329/files#diff-9f7a183be1e2cfcb3c3c852c059f66003dd4f3f586421b012e1b835724929ca1">+1/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr></tr></tbody></table>

</details>

___
2026-02-03 16:35:30 +05:30

89 lines
2.5 KiB
TypeScript

/**
* Event Formatters Composable
* ============================
* Reusable formatting utilities for RUM events
*/
import { date } from "quasar";
import { formatDuration } from "@/utils/zincutils";
export function useEventFormatters() {
/**
* Format timestamp to readable date string
*/
const formatTimestamp = (timestamp: number): string => {
if (!timestamp) return "N/A";
return date.formatDate(
Math.floor(timestamp),
"MMM DD, YYYY HH:mm:ss.SSS Z",
);
};
/**
* Format ID (currently pass-through, can be enhanced)
*/
const formatId = (id: string): string => {
if (!id) return "";
return id;
};
/**
* Get status icon based on HTTP status code
*/
const getStatusIcon = (statusCode: number): string => {
if (!statusCode) return "help";
if (statusCode >= 200 && statusCode < 300) return "check_circle";
if (statusCode >= 300 && statusCode < 400) return "info";
if (statusCode >= 400 && statusCode < 500) return "warning";
return "error";
};
/**
* Get status color based on HTTP status code
*/
const getStatusColor = (statusCode: number): string => {
if (!statusCode) return "grey";
if (statusCode >= 200 && statusCode < 300) return "positive";
if (statusCode >= 300 && statusCode < 400) return "info";
if (statusCode >= 400 && statusCode < 500) return "warning";
return "negative";
};
/**
* Format resource duration (microseconds or milliseconds)
*/
const formatResourceDuration = (
duration: number,
fromMicroseconds = false,
): string => {
if (!duration) return "N/A";
const durationInMs = fromMicroseconds ? duration / 1000000 : duration / 1000;
return formatDuration(durationInMs);
};
/**
* Get event type CSS classes
*/
const getEventTypeClass = (type: string): string => {
const classes: { [key: string]: string } = {
error:
"tw:bg-red-100 tw:text-red-700 tw:border tw:border-solid tw:border-red-300",
action:
"tw:bg-blue-100 tw:text-blue-700 tw:border tw:border-solid tw:border-blue-300",
view: "tw:bg-green-100 tw:text-green-700 tw:border tw:border-solid tw:border-green-300",
resource:
"tw:bg-purple-100 tw:text-purple-700 tw:border tw:border-solid tw:border-purple-300",
};
return classes[type] || "tw:bg-grey-100 tw:text-grey-700";
};
return {
formatTimestamp,
formatId,
getStatusIcon,
getStatusColor,
formatResourceDuration,
getEventTypeClass,
};
}