Skip to content

Conversation

@karthikscale3
Copy link
Contributor

This PR refines the observability UI with more compact, polished styling across the span detail panel and related components.

Changes:

  • Span detail panel: Reduced header size, moved duration to a subtle badge, improved panel height handling with flex layout
  • Attribute panel: Compact attribute display in bordered table-like layout with smaller font sizes
  • Detail cards: Added curved connecting lines between summary and expanded content
  • Events list: Consistent bordered container styling with attribute panel
  • Status badge: Redesigned with colored circle indicators, optional duration display, and enhanced error tooltips with copy functionality
  • Copyable text: Added overlay mode for inline copy buttons
  • Stream detail view: Simplified back navigation using router history

@changeset-bot
Copy link

changeset-bot bot commented Nov 28, 2025

🦋 Changeset detected

Latest commit: 6af5acb

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@workflow/web-shared Patch
@workflow/web Patch
@workflow/cli Patch
workflow Patch
@workflow/world-testing Patch
@workflow/ai Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Contributor

vercel bot commented Nov 28, 2025

@karthikscale3 is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

Comment on lines +119 to +124
<span
className="text-[11px] font-mono"
style={{ color: 'var(--ds-gray-1000)' }}
>
{String(value)}
</span>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Event attributes are displayed using String(value) instead of the AttributeBlock component, bypassing custom attribute formatters that were used in the previous implementation.

View Details
📝 Patch Details
diff --git a/packages/web-shared/src/sidebar/attribute-panel.tsx b/packages/web-shared/src/sidebar/attribute-panel.tsx
index aba8ef8..601b05c 100644
--- a/packages/web-shared/src/sidebar/attribute-panel.tsx
+++ b/packages/web-shared/src/sidebar/attribute-panel.tsx
@@ -219,6 +219,18 @@ const attributeToDisplayFn: Record<
   },
 };
 
+export const getAttributeDisplayValue = (
+  attribute: string,
+  value: unknown
+): null | string | ReactNode => {
+  const displayFn =
+    attributeToDisplayFn[attribute as keyof typeof attributeToDisplayFn];
+  if (!displayFn) {
+    return String(value);
+  }
+  return displayFn(value);
+};
+
 const resolvableAttributes = [
   'input',
   'output',
diff --git a/packages/web-shared/src/sidebar/events-list.tsx b/packages/web-shared/src/sidebar/events-list.tsx
index 02136c0..e291298 100644
--- a/packages/web-shared/src/sidebar/events-list.tsx
+++ b/packages/web-shared/src/sidebar/events-list.tsx
@@ -10,7 +10,7 @@ import {
 import { Alert, AlertDescription, AlertTitle } from '../components/ui/alert';
 import type { SpanEvent } from '../trace-viewer/types';
 import { convertEventsToSpanEvents } from '../workflow-traces/trace-span-construction';
-import { AttributeBlock } from './attribute-panel';
+import { AttributeBlock, getAttributeDisplayValue } from './attribute-panel';
 import { DetailCard } from './detail-card';
 
 export function EventsList({
@@ -104,26 +104,33 @@ export function EventsList({
               >
                 {Object.entries(event.attributes)
                   .filter(([key]) => key !== 'eventData')
-                  .map(([key, value]) => (
-                    <div
-                      key={key}
-                      className="flex items-center justify-between px-2.5 py-1.5"
-                      style={{ borderColor: 'var(--ds-gray-300)' }}
-                    >
-                      <span
-                        className="text-[11px] font-medium"
-                        style={{ color: 'var(--ds-gray-500)' }}
+                  .map(([key, value]) => {
+                    const displayValue = getAttributeDisplayValue(key, value);
+                    // Skip attributes that should not be displayed (returns null)
+                    if (displayValue === null) {
+                      return null;
+                    }
+                    return (
+                      <div
+                        key={key}
+                        className="flex items-center justify-between px-2.5 py-1.5"
+                        style={{ borderColor: 'var(--ds-gray-300)' }}
                       >
-                        {key}
-                      </span>
-                      <span
-                        className="text-[11px] font-mono"
-                        style={{ color: 'var(--ds-gray-1000)' }}
-                      >
-                        {String(value)}
-                      </span>
-                    </div>
-                  ))}
+                        <span
+                          className="text-[11px] font-medium"
+                          style={{ color: 'var(--ds-gray-500)' }}
+                        >
+                          {key}
+                        </span>
+                        <span
+                          className="text-[11px] font-mono"
+                          style={{ color: 'var(--ds-gray-1000)' }}
+                        >
+                          {displayValue}
+                        </span>
+                      </div>
+                    );
+                  })}
               </div>
               {/* Event data section */}
               {eventError && (

Analysis

Event attributes bypass custom formatters in events-list.tsx

What fails: Event attributes in packages/web-shared/src/sidebar/events-list.tsx lines 119-124 display raw String(value) instead of applying custom attribute formatters, causing date attributes to display as raw ISO strings instead of formatted dates, and hiding attributes like ownerId/projectId to display incorrectly.

How to reproduce:

  1. Display a workflow event with a date attribute (e.g., createdAt: "2025-11-28T17:47:00.000Z")
  2. Observe the Events panel in the sidebar
  3. Expected: Date should display as formatted (e.g., "11/28/2025, 5:47:00 PM")
  4. Actual (before fix): Displays raw ISO string "2025-11-28T17:47:00.000Z"

Result:

  • Date attributes (createdAt, startedAt, updatedAt, completedAt, retryAfter, resumeAt) displayed as raw ISO strings instead of localized dates
  • Hidden attributes (ownerId, projectId, environment, executionContext) displayed as values instead of being hidden
  • Loses formatting applied by attributeToDisplayFn lookup table in AttributeBlock component

Expected: Per the attribute formatting logic, the attributeToDisplayFn provides custom formatters for event attributes to ensure consistent display across the UI. Date attributes should use toLocaleString() for user-friendly formatting, and certain sensitive attributes should be hidden.

Fix implemented:

  1. Exported getAttributeDisplayValue() utility from attribute-panel.tsx that applies the attribute formatters
  2. Updated events-list.tsx to import and use this utility for formatting event attribute values
  3. This restores the custom formatting while maintaining the inline display layout

Copy link
Member

@VaguelySerious VaguelySerious left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

@VaguelySerious
Copy link
Member

@karthikscale3 before I can merge this, I'll need you to sign off your commits, by e.g. creating a new commit with the -s flag in git. You can also set up git to automatically include the sign-off flag for you on every commit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants