Repository: temporalio/ui
Pull request #417 (2022-04-11 23:41:20)

Improve summaries; refactor views
- Prefer failure messages when present
- In compact view: use the last event for the summary.
- Reduce duplication for viewing events.

cypress[bot]: 
<p align="center">
  <br />
  <img src="https://assets.cypress.io/github-pr-comment-icons/cypress-logo.png" height="32" />
</p>

---

### Test summary
<a href="https://dashboard.cypress.io/projects/g7xfxw/runs/113/overview?utm_source=github"><img src="https://assets.cypress.io/github-pr-comment-icons/green-check-mark.png" width="14" height="14" title="Passed" /></a> <b title="Passed">28</b>  &bull; <a href="https://dashboard.cypress.io/projects/g7xfxw/runs/113/test-results?utm_source=github&statuses=%5B%7B%22value%22%3A%22FAILED%22%2C%22label%22%3A%22FAILED%22%7D%5D"><img src="https://assets.cypress.io/github-pr-comment-icons/red-x.png" width="14" height="14" title="Failed" /></a> <b title="Failed">0</b>  &bull; <img src="https://assets.cypress.io/github-pr-comment-icons/gray-circle.png" width="14" height="14" title="Tests that did not run due to a developer annotating a test with .skip" /> <b title="Pending">0</b> &bull; <img src="https://assets.cypress.io/github-pr-comment-icons/yellow-triangle.png" width="14" height="14" title="Tests that did not run due to a failure in a mocha hook" /> <b title="Skipped">0</b> 

---

### Run details
| | |
| --- | --- |
| **Project** | Temporal UI |
| **Status** | Passed |
| **Commit** | 7d739b6a38 <span style="cursor:help;" title="Your CI provider generated this commit by merging this branch into the target branch.">ℹ️</span> |
| **Started** | Apr 11, 2022 11:42 PM |
| **Ended** | Apr 11, 2022 11:44 PM |
| **Duration** | 01:19 <a href="https://on.cypress.io/parallelization?utm_source=github" title="Enable parallelization to reduce run duration">💡</a> |
| **OS** | Linux Ubuntu - 20.04 |
| **Browser** | Chrome 100 <img src="https://cdnjs.cloudflare.com/ajax/libs/browser-logos/48.0.4/chrome/chrome_32x32.png" width="16" height="16" /> |

[View run in Cypress Dashboard ➡️](https://dashboard.cypress.io/projects/g7xfxw/runs/113/overview?utm_source=github)





---

This comment has been generated by **cypress-bot** as a result of this project's GitHub integration settings. You can manage this integration in [this project's settings in the Cypress Dashboard](https://dashboard.cypress.io/projects/g7xfxw/settings?utm_source=github)


cloudflare-pages[bot]: ## Deploying with &nbsp;<a href="https://pages.dev"><img alt="Cloudflare Pages" src="https://user-images.githubusercontent.com/23264/106598434-9e719e00-654f-11eb-9e59-6167043cfa01.png" width="16"></a> &nbsp;Cloudflare Pages

<table><tr><td><strong>Latest commit:</strong> </td><td>
<code>144a7e0</code>
</td></tr>
<tr><td><strong>Status:</strong></td><td>⚡️&nbsp; Build in progress...</td></tr>
</table>

[View logs](https://dash.cloudflare.com/?to=/:account/pages/view/temporal-pizza/ef9242cb-c454-42d9-bd67-ef1db73c8aeb)


Patch:
diff --git a/src/lib/components/event/event-compact-row.svelte b/src/lib/components/event/event-compact-row.svelte
deleted file mode 100644
index e26a1935..00000000
--- a/src/lib/components/event/event-compact-row.svelte
+++ /dev/null
@@ -1,75 +0,0 @@
-<script lang="ts">
-  import EventSingleDetail from './event-single-detail.svelte';
-  import EventGroupDetails from './event-group-details.svelte';
-  import EventDetails from './event-details.svelte';
-
-  export let eventGroup: CompactEventGroups;
-
-  $: collapsed = true;
-  $: event = eventGroup.initialEvent;
-
-  const onLinkClick = () => {
-    collapsed = !collapsed;
-  };
-
-  const onEventClick = (id: string) => {
-    event = eventGroup.events.get(id);
-  };
-</script>
-
-<article class="row">
-  <div class="cell">
-    <div>
-      <span
-        class={collapsed ? 'link collapsed' : 'link expanded'}
-        on:click|stopPropagation={onLinkClick}>{eventGroup.name}</span
-      >
-      {#if !collapsed}
-        <div class="p-4">
-          <EventGroupDetails
-            {eventGroup}
-            eventId={event.id}
-            onClick={onEventClick}
-          />
-        </div>
-      {/if}
-    </div>
-  </div>
-  <div class="cell">
-    {#if collapsed}
-      <EventSingleDetail {eventGroup} />
-    {:else}
-      <EventDetails {event} />
-    {/if}
-  </div>
-</article>
-
-<style lang="postcss">
-  .cell {
-    @apply md:table-cell md:border-b-2 text-left p-2;
-  }
-
-  .row {
-    @apply no-underline p-2 text-sm border-b-2 items-center md:text-base md:table-row last-of-type:border-b-0;
-  }
-
-  .row:hover {
-    @apply bg-gray-50;
-  }
-
-  .link {
-    @apply text-gray-900 font-medium cursor-pointer;
-  }
-
-  .row:hover .collapsed {
-    @apply text-blue-700 border-b-2 border-blue-700;
-  }
-
-  .row:hover .expanded:hover {
-    @apply text-blue-700 border-b-2 border-blue-700;
-  }
-
-  .row:last-of-type .cell {
-    @apply border-b-0 first-of-type:rounded-bl-lg  last-of-type:rounded-br-lg;
-  }
-</style>
diff --git a/src/lib/components/event/event-compact-table.svelte b/src/lib/components/event/event-compact-table.svelte
deleted file mode 100644
index 4e015d3d..00000000
--- a/src/lib/components/event/event-compact-table.svelte
+++ /dev/null
@@ -1,34 +0,0 @@
-<script lang="ts">
-  import EventCategoryMenu from '$lib/components/event/event-category-menu.svelte';
-</script>
-
-<section class="compact-table">
-  <div class="table-header md:table-header-group">
-    <div class="md:table-row hidden">
-      <div class="table-header-cell w-3/12 rounded-tl-md">
-        Event Type<EventCategoryMenu compact />
-      </div>
-      <div class="table-header-cell w-1/2 rounded-tr-md">Event Details</div>
-    </div>
-  </div>
-  <div class="table-header md:hidden rounded-t-md">
-    <div class="table-header-cell">Compact<EventCategoryMenu compact /></div>
-  </div>
-  <div class="overflow-y-auto md:table-row-group">
-    <slot />
-  </div>
-</section>
-
-<style lang="postcss">
-  .compact-table {
-    @apply md:table border-gray-300 border-2 rounded-lg w-full;
-  }
-
-  .table-header {
-    @apply bg-gray-900 text-gray-100;
-  }
-
-  .table-header-cell {
-    @apply table-cell text-left p-3;
-  }
-</style>
diff --git a/src/lib/components/event/event-details-row.svelte b/src/lib/components/event/event-details-row.svelte
new file mode 100644
index 00000000..a20dac64
--- /dev/null
+++ b/src/lib/components/event/event-details-row.svelte
@@ -0,0 +1,32 @@
+<script lang="ts">
+  import { page } from '$app/stores';
+
+  import { format } from '$lib/utilities/format-camel-case';
+  import { routeForWorkflow } from '$lib/utilities/route-for';
+  import { shouldDisplayAsWorkflowLink } from '$lib/utilities/get-single-attribute-for-event';
+
+  import CodeBlock from '../code-block.svelte';
+  import TableLink from '$lib/components/table-link.svelte';
+
+  export let key: string;
+  export let value: string | Record<string, string>;
+
+  const { workflow, namespace } = $page.params;
+</script>
+
+<article
+  class="flex flex-col lg:flex-row gap-2 lg:gap-4 py-2 last:border-b-0 border-gray-200 first:pt-0 {$$props.class}"
+>
+  <h4 class="w-1/3 text-normal">{format(key)}</h4>
+  <div class="flex-grow w-full">
+    {#if typeof value === 'object'}
+      <CodeBlock content={value} />
+    {:else if shouldDisplayAsWorkflowLink(key)}
+      <TableLink href={routeForWorkflow({ namespace, workflow, run: value })}
+        >{value}</TableLink
+      >
+    {:else}
+      <p><span class="bg-gray-300 text-gray-700 px-2">{value}</span></p>
+    {/if}
+  </div>
+</article>
diff --git a/src/lib/components/event/event-details.svelte b/src/lib/components/event/event-details.svelte
index 36a6cfa6..49bfaac6 100644
--- a/src/lib/components/event/event-details.svelte
+++ b/src/lib/components/event/event-details.svelte
@@ -1,42 +1,23 @@
 <script lang="ts">
-  import { page } from '$app/stores';
-
-  import { format } from '$lib/utilities/format-camel-case';
-  import { routeForWorkflow } from '$lib/utilities/route-for';
   import {
+    getSingleAttributeForEvent,
     shouldDisplayAttribute,
-    shouldDisplayAsWorkflowLink,
   } from '$lib/utilities/get-single-attribute-for-event';
+  import EventDetailsRow from './event-details-row.svelte';
 
-  import CodeBlock from '$lib/components/code-block.svelte';
-  import TableLink from '$lib/components/table-link.svelte';
-
-  export let event: HistoryEventWithId;
-
-  const { workflow, namespace } = $page.params;
+  export let event: IterableEvent;
+  export let summaryEvent = event;
+  export let expanded = false;
 </script>
 
 <section>
-  {#each Object.entries(event.attributes) as [key, value] (key)}
-    {#if shouldDisplayAttribute(key, value)}
-      <article
-        class="flex gap-4 py-2 last:border-b-0 border-gray-200 first:pt-0 {$$props.class}"
-      >
-        <p class="w-96">{format(key)}</p>
-        <div class="w-full">
-          {#if typeof value === 'object'}
-            <CodeBlock content={value} />
-          {:else if shouldDisplayAsWorkflowLink(key)}
-            <TableLink
-              href={routeForWorkflow({ namespace, workflow, run: value })}
-            >
-              {value}
-            </TableLink>
-          {:else}
-            <p><span class="bg-gray-300 text-gray-700 px-2">{value}</span></p>
-          {/if}
-        </div>
-      </article>
-    {/if}
-  {/each}
+  {#if expanded}
+    {#each Object.entries(event.attributes) as [key, value] (key)}
+      {#if shouldDisplayAttribute(key, value)}
+        <EventDetailsRow {key} {value} />
+      {/if}
+    {/each}
+  {:else}
+    <EventDetailsRow {...getSingleAttributeForEvent(summaryEvent)} />
+  {/if}
 </section>
diff --git a/src/lib/components/event/event-group-details.svelte b/src/lib/components/event/event-group-details.svelte
index 4d8d48b2..7ce7b24b 100644
--- a/src/lib/components/event/event-group-details.svelte
+++ b/src/lib/components/event/event-group-details.svelte
@@ -1,18 +1,22 @@
 <script lang="ts">
   export let eventGroup: CompactEventGroup | null;
-  export let eventId: string;
-  export let onClick: (id: string) => void;
+  export let selectedId: string;
 </script>
 
-<section class="overflow-y-scroll max-h-full">
+<section class="overflow-y-scroll max-h-full p-4">
   {#if eventGroup}
     <nav class="flex flex-col mb-4">
       <ul class="gap-4 w-full items-start">
         {#each [...eventGroup.events] as [id, eventInGroup] (id)}
-          <li on:click|preventDefault|stopPropagation={() => onClick(id)}>
-            <span class="event-type" class:active={id === eventId}
+          <li
+            on:click|preventDefault|stopPropagation={() => {
+              selectedId = id;
+            }}
+          >
+            <span class="event-type" class:active={id === selectedId}
               >{eventInGroup.eventType}</span
             >
+            (#{id})
           </li>
         {/each}
       </ul>
diff --git a/src/lib/components/event/event-single-detail.svelte b/src/lib/components/event/event-single-detail.svelte
deleted file mode 100644
index 98130a27..00000000
--- a/src/lib/components/event/event-single-detail.svelte
+++ /dev/null
@@ -1,35 +0,0 @@
-<script lang="ts">
-  import { page } from '$app/stores';
-  import { routeForWorkflow } from '$lib/utilities/route-for';
-  import {
-    getSingleAttributeForEvent,
-    shouldDisplayAsWorkflowLink,
-  } from '$lib/utilities/get-single-attribute-for-event';
-  import CodeBlock from '../code-block.svelte';
-  import TableLink from '$lib/components/table-link.svelte';
-
-  export let event: HistoryEventWithId | null = null;
-  export let eventGroup: CompactEventGroup | null = null;
-
-  let { key, value } = getSingleAttributeForEvent({ event, eventGroup });
-  const { workflow, namespace } = $page.params;
-</script>
-
-<section>
-  <article
-    class="flex py-2 last:border-b-0 border-gray-200 first:pt-0 {$$props.class}"
-  >
-    <h4 class="w-96 flex-grow text-normal">{key}</h4>
-    <div class="flex-grow w-full">
-      {#if eventGroup}
-        <CodeBlock content={value} />
-      {:else if shouldDisplayAsWorkflowLink(key)}
-        <TableLink href={routeForWorkflow({ namespace, workflow, run: value })}
-          >{value}</TableLink
-        >
-      {:else}
-        <p><span class="bg-gray-300 text-gray-700 px-2">{value}</span></p>
-      {/if}
-    </div>
-  </article>
-</section>
diff --git a/src/lib/components/event/event-summary-row.svelte b/src/lib/components/event/event-summary-row.svelte
index 4170c729..035f623a 100644
--- a/src/lib/components/event/event-summary-row.svelte
+++ b/src/lib/components/event/event-summary-row.svelte
@@ -1,13 +1,26 @@
 <script lang="ts">
+  import { page } from '$app/stores';
+
+  import { getGroupForEvent, isEventGroup } from '$lib/models/group-events';
+
   import { formatDate } from '$lib/utilities/format-date';
 
   import EventDetails from './event-details.svelte';
-  import EventSingleDetail from './event-single-detail.svelte';
+  import EventGroupDetails from './event-group-details.svelte';
+
+  export let event: IterableEvent;
+  export let groups: CompactEventGroups;
+  export let expandAll = false;
+  export let compact = false;
+
+  let selectedId = event.id;
 
-  export let event: HistoryEventWithId;
-  export let expandAll: boolean = false;
+  let eventGroup = isEventGroup(event)
+    ? event
+    : getGroupForEvent(event, groups);
 
   $: expanded = expandAll;
+  $: currentEvent = compact ? eventGroup.events.get(selectedId) : event;
 
   const onLinkClick = () => {
     if (!expandAll) {
@@ -18,32 +31,35 @@
 
 <article class="row" id={event.id}>
   <div class="cell">
-    <a class="text-gray-500 text-normal mx-1" href="#{event.id}">{event.id}</a>
+    <a
+      class="text-gray-500 text-normal mx-1 text-lg md:text-base"
+      href="#{event.id}">{event.id}</a
+    >
     <span
-      class="mx-2"
+      class="md:mx-2 text-lg md:text-base font-semibold"
       class:link={!expandAll}
       on:click|stopPropagation={onLinkClick}>{event.name}</span
     >
+    {#if expanded && compact}
+      <EventGroupDetails {eventGroup} bind:selectedId />
+    {/if}
   </div>
   <div class="cell links font-medium md:font-normal">
     {formatDate(event?.eventTime)}
   </div>
+
   <div class="cell links">
-    {#if expanded}
-      <EventDetails {event} />
-    {:else}
-      <EventSingleDetail {event} />
-    {/if}
+    <EventDetails event={currentEvent} {expanded} summaryEvent={event} />
   </div>
 </article>
 
 <style lang="postcss">
   .cell {
-    @apply md:table-cell md:border-b-2 text-left p-1 pt-2;
+    @apply md:table-cell md:border-b-2 text-left py-1 px-3 pt-2;
   }
 
   .row {
-    @apply no-underline p-1 text-sm border-b-2 items-center md:text-base md:table-row last-of-type:border-b-0;
+    @apply no-underline py-3 text-sm border-b-2 items-center md:text-base md:table-row last-of-type:border-b-0;
   }
 
   .row:hover {
diff --git a/src/lib/components/event/event-summary-table.svelte b/src/lib/components/event/event-summary-table.svelte
index 82f91231..21f3201e 100644
--- a/src/lib/components/event/event-summary-table.svelte
+++ b/src/lib/components/event/event-summary-table.svelte
@@ -1,19 +1,22 @@
 <script lang="ts">
   import EventCategoryMenu from '$lib/components/event/event-category-menu.svelte';
+  export let compact = false;
+
+  let title = compact ? 'Event Type' : 'Workflow Events';
 </script>
 
-<section class="summary-table">
+<section class="event-table">
   <div class="table-header-row md:table-header-group">
     <div class="md:table-row hidden">
       <div class="table-header w-3/12 rounded-tl-md">
-        Workflow Events<EventCategoryMenu />
+        {title}<EventCategoryMenu {compact} />
       </div>
       <div class="table-header w-3/12">Date & Time</div>
       <div class="table-header w-1/2 rounded-tr-md">Event Details</div>
     </div>
   </div>
   <div class="table-header-row md:hidden rounded-t-md">
-    <div class="table-header">Summary<EventCategoryMenu /></div>
+    <div class="table-header">{title}<EventCategoryMenu {compact} /></div>
   </div>
   <div class="overflow-y-auto md:table-row-group">
     <slot />
@@ -21,15 +24,15 @@
 </section>
 
 <style lang="postcss">
-  .summary-table {
-    @apply md:table border-gray-300 border-2 rounded-lg w-full max-w-full;
+  .event-table {
+    @apply md:table border-gray-900 border-2 rounded-lg w-full;
   }
 
   .table-header-row {
-    @apply bg-gray-900 text-gray-100;
+    @apply bg-gray-900 text-gray-100 px-3;
   }
 
   .table-header {
-    @apply table-cell text-left p-3;
+    @apply md:table-cell table-cell text-left px-3 py-3;
   }
 </style>
diff --git a/src/lib/components/event/view/event-summary.svelte b/src/lib/components/event/event-summary.svelte
similarity index 65%
rename from src/lib/components/event/view/event-summary.svelte
rename to src/lib/components/event/event-summary.svelte
index fe835ad5..5ae393da 100644
--- a/src/lib/components/event/view/event-summary.svelte
+++ b/src/lib/components/event/event-summary.svelte
@@ -3,16 +3,18 @@
 
   import EventSummaryTable from '$lib/components/event/event-summary-table.svelte';
   import EventSummaryRow from '$lib/components/event/event-summary-row.svelte';
-  import EventEmptyRow from '../event-empty-row.svelte';
+  import EventEmptyRow from './event-empty-row.svelte';
 
-  export let items: HistoryEventWithId[];
+  export let items: IterableEvents;
+  export let groups: CompactEventGroups;
   export let expandAll = false;
+  export let compact = false;
 </script>
 
 <Pagination {items} floatId="event-view-toggle" let:visibleItems>
-  <EventSummaryTable>
+  <EventSummaryTable {compact}>
     {#each visibleItems as event (event.id)}
-      <EventSummaryRow {event} {expandAll} />
+      <EventSummaryRow {event} {groups} {expandAll} {compact} />
     {:else}
       <EventEmptyRow />
     {/each}
diff --git a/src/lib/components/event/view/event-compact.svelte b/src/lib/components/event/view/event-compact.svelte
deleted file mode 100644
index 36829d81..00000000
--- a/src/lib/components/event/view/event-compact.svelte
+++ /dev/null
@@ -1,25 +0,0 @@
-<script lang="ts">
-  import Pagination from '$lib/components/pagination.svelte';
-  import LoadingRow from '$lib/components/loading-row.svelte';
-
-  import EventCompactTable from '$lib/components/event/event-compact-table.svelte';
-  import EventCompactRow from '$lib/components/event/event-compact-row.svelte';
-  import EventEmptyRow from '../event-empty-row.svelte';
-
-  export let items: IterableEvents;
-</script>
-
-{#await items}
-  <LoadingRow />
-{:then items}
-  <Pagination {items} floatId="event-view-toggle" let:visibleItems>
-    <EventCompactTable>
-      {#each visibleItems as eventGroup (eventGroup.id)}
-        <EventCompactRow {eventGroup} />
-      {/each}
-      {#if !items?.length}
-        <EventEmptyRow />
-      {/if}
-    </EventCompactTable>
-  </Pagination>
-{/await}
diff --git a/src/lib/models/group-events/create-event-group.ts b/src/lib/models/group-events/create-event-group.ts
index 8e83cd36..570adb75 100644
--- a/src/lib/models/group-events/create-event-group.ts
+++ b/src/lib/models/group-events/create-event-group.ts
@@ -8,6 +8,7 @@ import {
   isWorkflowExecutionSignaledEvent,
   isTimerStartedEvent,
 } from '$lib/utilities/is-event-type';
+import { getLastEvent } from './get-last-event';
 
 export const getName = (event: CommonHistoryEvent): string => {
   if (!event) return;
@@ -70,6 +71,12 @@ const createGroupFor = <K extends keyof StartingEvents>(
     timestamp,
     category,
     classification,
+    get eventTime() {
+      return getLastEvent(this)?.eventTime;
+    },
+    get attributes() {
+      return getLastEvent(this)?.attributes;
+    },
   };
 };
 
diff --git a/src/lib/models/group-events/event-groups.d.ts b/src/lib/models/group-events/event-groups.d.ts
index 51e85906..5b4d2f3f 100644
--- a/src/lib/models/group-events/event-groups.d.ts
+++ b/src/lib/models/group-events/event-groups.d.ts
@@ -5,6 +5,8 @@ type CompactEventGroup<T = EventType, E = HistoryEventWithId, Id = E['id']> = {
   eventIds: Set<Id>;
   initialEvent: HistoryEventWithId;
   timestamp: HistoryEventWithId['timestamp'];
+  eventTime: HistoryEventWithId['eventTime'];
+  attributes: HistoryEventWithId['attributes'];
 } & Pick<HistoryEventWithId, 'timestamp' | 'classification' | 'category'>;
 
 type CompactEventGroups<
diff --git a/src/lib/models/group-events/index.ts b/src/lib/models/group-events/index.ts
index 0c3f7407..d072dee1 100644
--- a/src/lib/models/group-events/index.ts
+++ b/src/lib/models/group-events/index.ts
@@ -38,11 +38,13 @@ export const groupEvents = (
 export const isEventGroup = (
   eventOrGroup: unknown,
 ): eventOrGroup is CompactEventGroup => {
+  if (eventOrGroup === undefined || eventOrGroup === null) return false;
   return has(eventOrGroup, 'events');
 };
 
 export const isEventGroups = (
   eventsOrGroups: unknown[],
 ): eventsOrGroups is CompactEventGroups => {
+  if (eventsOrGroups === undefined || eventsOrGroups === null) return false;
   return eventsOrGroups.every(isEventGroup);
 };
diff --git a/src/lib/utilities/get-single-attribute-for-event.ts b/src/lib/utilities/get-single-attribute-for-event.ts
index 5cdb6b6f..57e4a85b 100644
--- a/src/lib/utilities/get-single-attribute-for-event.ts
+++ b/src/lib/utilities/get-single-attribute-for-event.ts
@@ -1,4 +1,7 @@
-type SummaryAttribute = { key: string; value: string };
+import { isEventGroup } from '$lib/models/group-events';
+import { getLastEvent } from '$lib/models/group-events/get-last-event';
+
+type SummaryAttribute = { key: string; value: string | Record<string, any> };
 
 const emptyAttribute: SummaryAttribute = { key: '', value: '' };
 
@@ -33,10 +36,14 @@ export const shouldDisplayAsWorkflowLink = (
   return false;
 };
 
+const capitalize = (word: string): string => {
+  return word[0].toUpperCase() + word.slice(1);
+};
+
 const formatSummaryValue = (key: string, value: unknown): SummaryAttribute => {
   if (typeof value === 'object') {
     const [firstKey] = Object.keys(value);
-    return { key: `${key}.${firstKey}`, value: value[firstKey] };
+    return { key: key + capitalize(firstKey), value: value[firstKey] };
   } else {
     return { key, value: value.toString() };
   }
@@ -45,14 +52,21 @@ const formatSummaryValue = (key: string, value: unknown): SummaryAttribute => {
 /**
  * A list of the keys that should be shown in the summary view.
  */
-const preferredSummaryKeys = ['activityType'] as const;
+const preferredSummaryKeys = [
+  'failure',
+  'input',
+  'activityType',
+  'parentInitiatedEventId',
+  'workflowType',
+  'taskQueue',
+] as const;
 
 /**
  * Returns that first event attribute that is eligible to be displayed.
  */
 const getFirstDisplayAttribute = ({
   attributes,
-}: HistoryEventWithId): { key: string; value: string } => {
+}: HistoryEventWithId): SummaryAttribute => {
   for (const [key, value] of Object.entries(attributes)) {
     if (shouldDisplayAttribute(key, value)) {
       return formatSummaryValue(key, value);
@@ -65,45 +79,35 @@ const getFirstDisplayAttribute = ({
  * preferred keys. If a preferred key is found, it will be returned.
  * Otherwise, it will return the first eligible event attribute.
  */
-const getPreferredSummaryAttribute = (
-  event: HistoryEventWithId,
-): SummaryAttribute => {
+const getSummaryAttribute = (event: HistoryEventWithId): SummaryAttribute => {
   const first = getFirstDisplayAttribute(event);
 
   for (const [key, value] of Object.entries(event.attributes)) {
     for (const preferredKey of preferredSummaryKeys) {
-      if (key === preferredKey) return formatSummaryValue(key, value);
+      if (key === preferredKey && shouldDisplayAttribute(key, value))
+        return formatSummaryValue(key, value);
     }
   }
 
   return first;
 };
 
-const getSummaryForEventGroup = (
+export const getSummaryForEventGroup = (
   eventGroup: CompactEventGroup,
 ): SummaryAttribute => {
-  let input = '';
-  const attributes = eventGroup.initialEvent.attributes;
+  const event = getLastEvent(eventGroup);
 
-  for (const [key, value] of Object.entries(attributes)) {
-    if (key === 'input') input = value;
-  }
-
-  return { key: 'input', value: input };
+  return getSummaryAttribute(event);
 };
 
-export const getSingleAttributeForEvent = ({
-  event,
-  eventGroup,
-}: {
-  event: HistoryEventWithId | null;
-  eventGroup: CompactEventGroup | null;
-}): SummaryAttribute => {
-  if (!event && !eventGroup) return emptyAttribute;
-
-  if (eventGroup) {
-    return getSummaryForEventGroup(eventGroup);
+export const getSingleAttributeForEvent = (
+  event: HistoryEventWithId | CompactEventGroup,
+): SummaryAttribute => {
+  if (!event) return emptyAttribute;
+
+  if (isEventGroup(event)) {
+    return getSummaryForEventGroup(event);
   }
 
-  return getPreferredSummaryAttribute(event);
+  return getSummaryAttribute(event);
 };
diff --git a/src/routes/import/events/history/compact/index.svelte b/src/routes/import/events/history/compact/index.svelte
index 331cc9d6..28284174 100644
--- a/src/routes/import/events/history/compact/index.svelte
+++ b/src/routes/import/events/history/compact/index.svelte
@@ -2,7 +2,7 @@
   import { page } from '$app/stores';
 
   import { importEventGroups } from '$lib/stores/import-events';
-  import CompactEvent from '$lib/components/event/view/event-compact.svelte';
+  import EventSummary from '$lib/components/event/event-summary.svelte';
 
   $: category = $page.url.searchParams.get('category') as EventTypeCategory;
   $: filteredEventGroups = $importEventGroups.filter(
@@ -13,4 +13,8 @@
   );
 </script>
 
-<CompactEvent items={filteredEventGroups} />
+<EventSummary
+  items={filteredEventGroups}
+  groups={$importEventGroups}
+  compact={true}
+/>
diff --git a/src/routes/import/events/history/full/index.svelte b/src/routes/import/events/history/full/index.svelte
index 9b0a40b6..067c1374 100644
--- a/src/routes/import/events/history/full/index.svelte
+++ b/src/routes/import/events/history/full/index.svelte
@@ -1,8 +1,8 @@
 <script lang="ts">
   import { page } from '$app/stores';
 
-  import { importEvents } from '$lib/stores/import-events';
-  import EventFullView from '$lib/components/event/view/event-summary.svelte';
+  import { importEvents, importEventGroups } from '$lib/stores/import-events';
+  import EventSummary from '$lib/components/event/event-summary.svelte';
 
   $: category = $page.url.searchParams.get('category') as EventTypeCategory;
   $: filteredEvents = $importEvents.filter((event) => {
@@ -11,4 +11,4 @@
   });
 </script>
 
-<EventFullView items={filteredEvents} expandAll />
+<EventSummary items={filteredEvents} groups={$importEventGroups} expandAll />
diff --git a/src/routes/import/events/history/summary/index.svelte b/src/routes/import/events/history/summary/index.svelte
index b8c6bece..74dc56cb 100644
--- a/src/routes/import/events/history/summary/index.svelte
+++ b/src/routes/import/events/history/summary/index.svelte
@@ -1,8 +1,8 @@
 <script lang="ts">
   import { page } from '$app/stores';
 
-  import { importEvents } from '$lib/stores/import-events';
-  import EventSummary from '$lib/components/event/view/event-summary.svelte';
+  import { importEvents, importEventGroups } from '$lib/stores/import-events';
+  import EventSummary from '$lib/components/event/event-summary.svelte';
 
   $: category = $page.url.searchParams.get('category') as EventTypeCategory;
   $: filteredEvents = $importEvents.filter((event) => {
@@ -11,4 +11,4 @@
   });
 </script>
 
-<EventSummary items={filteredEvents} />
+<EventSummary items={filteredEvents} groups={$importEventGroups} />
diff --git a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/index.svelte b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/index.svelte
index 32725007..6dcae3cd 100644
--- a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/index.svelte
+++ b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/index.svelte
@@ -22,9 +22,9 @@
 </script>
 
 <script lang="ts">
-  import CompactEvent from '$lib/components/event/view/event-compact.svelte';
+  import EventSummary from '$lib/components/event/event-summary.svelte';
 
   export let items: IterableEvents;
 </script>
 
-<CompactEvent {items} />
+<EventSummary {items} groups={items} compact={true} />
diff --git a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/index.svelte b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/index.svelte
index e4f72ef9..0769a5f8 100644
--- a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/index.svelte
+++ b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/index.svelte
@@ -7,19 +7,22 @@
     const category = url.searchParams.get('category');
 
     const items = getEventsInCategory(stuff.events, category);
+    const groups = stuff.eventGroups;
 
     return {
       props: {
         items,
+        groups,
       },
     };
   };
 </script>
 
 <script lang="ts">
-  import EventSummary from '$lib/components/event/view/event-summary.svelte';
+  import EventSummary from '$lib/components/event/event-summary.svelte';
 
   export let items: HistoryEventWithId[];
+  export let groups: CompactEventGroups;
 </script>
 
-<EventSummary {items} expandAll />
+<EventSummary {items} {groups} expandAll />
diff --git a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/summary/index.svelte b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/summary/index.svelte
index ecb680a0..31435f83 100644
--- a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/summary/index.svelte
+++ b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/summary/index.svelte
@@ -9,10 +9,12 @@
     const events = getEventsInCategory(stuff.events, category);
 
     let items: HistoryEventWithId[] = events;
+    const groups = stuff.eventGroups;
 
     return {
       props: {
         items,
+        groups,
       },
       stuff: {
         matchingEvents: events,
@@ -22,9 +24,10 @@
 </script>
 
 <script lang="ts">
-  import EventSummary from '$lib/components/event/view/event-summary.svelte';
+  import EventSummary from '$lib/components/event/event-summary.svelte';
 
   export let items: HistoryEventWithId[];
+  export let groups: CompactEventGroups;
 </script>
 
-<EventSummary {items} />
+<EventSummary {items} {groups} />


Test patch:
diff --git a/src/lib/utilities/get-single-attribute-for-event.test.ts b/src/lib/utilities/get-single-attribute-for-event.test.ts
index d9b1ac13..5f5c704b 100644
--- a/src/lib/utilities/get-single-attribute-for-event.test.ts
+++ b/src/lib/utilities/get-single-attribute-for-event.test.ts
@@ -114,10 +114,8 @@ describe(getSingleAttributeForEvent, () => {
   };
 
   it('should return "workflowType.name" if the workflow type exists', () => {
-    expect(
-      getSingleAttributeForEvent({ event: workflowEvent, eventGroup: null }),
-    ).toStrictEqual({
-      key: 'workflowType.name',
+    expect(getSingleAttributeForEvent(workflowEvent)).toStrictEqual({
+      key: 'workflowTypeName',
       value: 'RainbowStatusesWorkflow',
     });
   });
@@ -125,39 +123,27 @@ describe(getSingleAttributeForEvent, () => {
   it('should return "taskqueue.name" if the workflow type does not exists', () => {
     const event = { ...workflowEvent };
     event.attributes.workflowType = null;
-    expect(
-      getSingleAttributeForEvent({ event, eventGroup: null }),
-    ).toStrictEqual({ key: 'taskQueue.name', value: 'rainbow-statuses' });
+    expect(getSingleAttributeForEvent(event)).toStrictEqual({
+      key: 'taskQueueName',
+      value: 'rainbow-statuses',
+    });
   });
 
-  it('should return "parentInitiatedEventId" if the workflow type and task queue does not exists', () => {
+  it('should return "parentInitiatedEventId" if the workflow type and task queue does not exist', () => {
     const event = { ...workflowEvent };
     event.attributes.workflowType = null;
     event.attributes.taskQueue = null;
-    expect(
-      getSingleAttributeForEvent({ event, eventGroup: null }),
-    ).toStrictEqual({ key: 'parentInitiatedEventId', value: '0' });
+    expect(getSingleAttributeForEvent(event)).toStrictEqual({
+      key: 'parentInitiatedEventId',
+      value: '0',
+    });
   });
 
   it('should return empty key value object if none of the attributes display', () => {
-    expect(
-      getSingleAttributeForEvent({ event: null, eventGroup: null }),
-    ).toStrictEqual({ key: '', value: '' });
-  });
-
-  it('should return "input" if passed an event group', () => {
-    const event = { ...workflowEvent };
-    const value = {
-      payloads: [
-        {
-          Hey: 'from Mars',
-          At: '2022-04-04T11:50:28.151785-05:00',
-        },
-      ],
-    };
-    expect(
-      getSingleAttributeForEvent({ event, eventGroup: workflowEventGroup }),
-    ).toStrictEqual({ key: 'input', value });
+    expect(getSingleAttributeForEvent(null)).toStrictEqual({
+      key: '',
+      value: '',
+    });
   });
 });