Repository: temporalio/ui
Pull request #269 (2022-02-22 21:39:06)

Beta badge
<!--- Note to EXTERNAL Contributors -->
<!-- Thanks for opening a PR! 
If it is a significant code change, please **make sure there is an open issue** for this. 
We work best with you when we have accepted the idea first before you code. -->

<!--- For ALL Contributors 👇 -->

## What was changed
<!-- Describe what has changed in this PR -->

## Why?
<!-- Tell your future self why have you made these changes -->

## Checklist
<!--- add/delete as needed --->

1. Closes <!-- add issue number here -->

2. How was this tested:
<!--- Please describe how you tested your changes/how we can test them -->

3. Any docs updates needed?
<!--- update README if applicable
      or point out where to update docs.temporal.io -->



Patch:
diff --git a/src/events.d.ts b/src/events.d.ts
index f74ccfaf..dee76233 100644
--- a/src/events.d.ts
+++ b/src/events.d.ts
@@ -314,6 +314,7 @@ type PendingActivityInfo = import('$types').PendingActivityInfo;
 interface PendingActivity extends PendingActivityInfo {
   state: 'Unspecified' | 'Scheduled' | 'Started' | 'CancelRequested';
   activityType: { name: string };
+  id: typeof PendingActivityInfo.activityId;
 }
 
 type EventType =
diff --git a/src/global.d.ts b/src/global.d.ts
index 5c4ceb8c..c9f000e7 100644
--- a/src/global.d.ts
+++ b/src/global.d.ts
@@ -77,6 +77,7 @@ type Settings = {
   auth: {
     enabled: boolean;
   };
+  defaultNamespace: string;
 };
 
 type User = {
@@ -87,3 +88,5 @@ type User = {
 
 declare module '@crownframework/svelte-error-boundary';
 declare module '@sveltejs/svelte-virtual-list';
+
+type SelectOptionValue = number | string | boolean;
diff --git a/src/lib/components/badge.svelte b/src/lib/components/badge.svelte
new file mode 100644
index 00000000..b6f1aeaf
--- /dev/null
+++ b/src/lib/components/badge.svelte
@@ -0,0 +1,28 @@
+<script lang="ts">
+  type BadgeTypes = 'alpha' | 'beta';
+
+  export let type: BadgeTypes;
+</script>
+
+<div
+  class={`${type}     
+        rounded-sm
+        text-center 
+        inline-block
+        px-1
+        ml-1
+        text-sm
+        align-middle`}
+>
+  <slot />
+</div>
+
+<style lang="postcss">
+  .beta {
+    @apply bg-blue-100  text-blue-700  border-blue-700;
+  }
+
+  .alpha {
+    @apply bg-purple-100 text-purple-700 border-purple-700;
+  }
+</style>
diff --git a/src/lib/components/button.svelte b/src/lib/components/button.svelte
index 47449387..29034332 100644
--- a/src/lib/components/button.svelte
+++ b/src/lib/components/button.svelte
@@ -40,6 +40,7 @@
     class:large
     class:secondary
     class:destroy
+    class:disabled
     {disabled}
     >{#if loading}
       <span class="animate-spin"> <Icon {icon} scale={1} /></span>
@@ -59,7 +60,7 @@
   }
 
   .primary:disabled {
-    @apply text-purple-400 border-purple-400 cursor-not-allowed;
+    @apply text-purple-400 border-purple-400 cursor-not-allowed bg-gray-400;
   }
 
   .primary:hover:enabled {
@@ -71,7 +72,7 @@
   }
 
   .secondary:disabled {
-    @apply text-purple-400 border-purple-400 cursor-not-allowed;
+    @apply text-purple-400 border-purple-400 cursor-not-allowed bg-gray-400;
   }
 
   .secondary:hover:enabled {
@@ -83,7 +84,7 @@
   }
 
   .destroy:disabled {
-    @apply text-red-400 border-red-400 cursor-not-allowed;
+    @apply text-red-400 border-red-400 cursor-not-allowed bg-gray-400;
   }
 
   .destroy:hover:enabled {
diff --git a/src/lib/components/code-block.svelte b/src/lib/components/code-block.svelte
index 4f2bcadd..ff35b985 100644
--- a/src/lib/components/code-block.svelte
+++ b/src/lib/components/code-block.svelte
@@ -1,11 +1,13 @@
 <script lang="ts">
   import { onMount } from 'svelte';
+
   import Icon from 'svelte-fa';
   import { faCheck, faCopy } from '@fortawesome/free-solid-svg-icons';
 
   export let heading = '';
-  export let content: string | Parameters<typeof JSON.stringify>[0];
+  export let content: Parameters<typeof JSON.stringify>[0];
   export let copied = false;
+  export let framed = false;
   export let language = 'json';
 
   const isJSON = language === 'json';
@@ -19,9 +21,13 @@
       })
       .catch((error) => console.error(error));
 
-  const formatJSON = (jsonData: string) => {
-    const parsedData = JSON.parse(jsonData);
+  const formatJSON = (jsonData: string): string => {
+    if (!jsonData) return;
+
+    const parsedData =
+      typeof jsonData === 'string' ? JSON.parse(jsonData) : jsonData;
     const formated = JSON.stringify(parsedData, undefined, 2);
+
     return formated;
   };
 
@@ -31,7 +37,7 @@
 </script>
 
 {#if content || content === null}
-  <div class="relative w-full">
+  <div class="relative w-full" class:framed>
     <div id="clipboard" />
 
     {#if heading}
@@ -39,10 +45,12 @@
     {/if}
 
     <pre
-      class="p-4">
+      class="p-4"
+      class:rounded-2xl={framed}
+      class:h-full={framed}>
         <code class="language-{language}">
           {#if isJSON}
-            {formatJSON(JSON.stringify(content))}
+            {formatJSON(content)}
           {:else}
             {@html content}
           {/if}
@@ -58,3 +66,9 @@
     </button>
   </div>
 {/if}
+
+<style lang="postcss">
+  .framed {
+    @apply border-2 border-gray-300 rounded-2xl p-4 flex flex-col;
+  }
+</style>
diff --git a/src/lib/components/error-boundary.svelte b/src/lib/components/error-boundary.svelte
index 4829999f..8d24d26a 100644
--- a/src/lib/components/error-boundary.svelte
+++ b/src/lib/components/error-boundary.svelte
@@ -1,12 +1,11 @@
 <script lang="ts">
   import { networkError } from '$lib/stores/error';
-  import { isNetworkError } from '$lib/utilities/is-network-error';
   import Error from './error.svelte';
 
   export let error = null;
   export let onError = null;
 
-  let theError;
+  let theError: NetworkError | any;
 
   $: {
     if (error && $error) {
@@ -29,9 +28,6 @@
 {/if}
 
 <style>
-  .error {
-    border: 1px solid red;
-  }
   .trace {
     font-family: monospace;
   }
diff --git a/src/lib/components/event-table.svelte b/src/lib/components/event-table.svelte
index 642cea9e..42896787 100644
--- a/src/lib/components/event-table.svelte
+++ b/src/lib/components/event-table.svelte
@@ -1,54 +1,51 @@
 <script lang="ts">
-  import VirtualList from '@sveltejs/svelte-virtual-list';
-
   import type { EventGroups } from '$lib/models/events-group';
+  import Pagination from './pagination.svelte';
   import Event from './event.svelte';
 
   export let events: (HistoryEventWithId | PendingActivity)[] | EventGroups;
 </script>
 
-<section
-  class="flex flex-col border-2 border-gray-300 rounded-lg w-full event-history"
->
-  <div class="flex w-full">
-    <header class="table-header border-r-2 rounded-tl-lg w-1/3">
-      <h3>Summary</h3>
-      <slot name="filters" />
-    </header>
-    <header class="table-header rounded-tr-lg w-2/3">
-      <h3>Details</h3>
-    </header>
-  </div>
-  <div class="flex h-full overflow-y-hidden">
-    <div
-      class="flex flex-col h-full w-1/3 border-r-2 border-gray-300 rounded-bl-lg"
-    >
-      <div class="h-full rounded-bl-lg overflow-y-scroll">
-        <VirtualList items={events} let:item>
-          <Event event={item} />
-        </VirtualList>
-      </div>
+<Pagination items={[...events]} let:visibleItems>
+  <section
+    class="flex flex-col border-2 border-gray-300 rounded-lg w-full event-history mb-6"
+  >
+    <div class="flex w-full">
+      <header class="table-header border-r-2 rounded-tl-lg w-1/3">
+        <h3>Summary</h3>
+        <slot name="filters" />
+      </header>
+      <header class="table-header rounded-tr-lg w-2/3">
+        <h3>Details</h3>
+      </header>
     </div>
-    <div class="flex flex-col h-full w-2/3">
+    <div class="flex h-full overflow-y-hidden">
       <div
-        class="h-full  overflow-y-scroll overflow-x-hidden rounded-br-lg px-4"
+        class="flex flex-col h-full w-1/3 border-r-2 border-gray-300 rounded-bl-lg"
       >
-        <slot name="details">
-          <div class="flex items-center justify-center w-full h-full">
-            <p class="text-gray-600 italic">(Nothing selected.)</p>
-          </div>
-        </slot>
+        <div class="h-full rounded-bl-lg overflow-y-scroll">
+          {#each visibleItems as event (event.id)}
+            <Event {event} />
+          {/each}
+        </div>
+      </div>
+      <div class="flex flex-col h-full w-2/3">
+        <div
+          class="h-full  overflow-y-scroll overflow-x-hidden rounded-br-lg px-4"
+        >
+          <slot name="details">
+            <div class="flex items-center justify-center w-full h-full">
+              <p class="text-gray-600 italic">(Nothing selected.)</p>
+            </div>
+          </slot>
+        </div>
       </div>
     </div>
-  </div>
-</section>
+  </section>
+</Pagination>
 
 <style lang="postcss">
-  .event-history {
-    height: calc(100vh - 360px);
-  }
-
   .table-header {
-    @apply bg-gray-100 text-gray-800 font-semibold p-4 border-b-2 flex justify-between items-center;
+    @apply bg-gray-100 text-gray-800 font-semibold p-4 flex justify-between items-center border-b-2;
   }
 </style>
diff --git a/src/lib/components/event.svelte b/src/lib/components/event.svelte
index 1770b66a..6a2ebc89 100644
--- a/src/lib/components/event.svelte
+++ b/src/lib/components/event.svelte
@@ -66,4 +66,8 @@
   .pending .active {
     @apply bg-blue-50;
   }
+
+  a:last-child {
+    @apply border-b-0;
+  }
 </style>
diff --git a/src/lib/components/filter-input.svelte b/src/lib/components/filter-input.svelte
index 37691b75..32be3e64 100644
--- a/src/lib/components/filter-input.svelte
+++ b/src/lib/components/filter-input.svelte
@@ -26,7 +26,7 @@
   }
 </script>
 
-<div class="input-container ">
+<div class="input-container">
   <label for={id} class="hidden">{name}</label>
   <span
     ><Icon
diff --git a/src/lib/components/input-and-result.svelte b/src/lib/components/input-and-result.svelte
new file mode 100644
index 00000000..95f7b72f
--- /dev/null
+++ b/src/lib/components/input-and-result.svelte
@@ -0,0 +1,18 @@
+<script lang="ts">
+  import { getWorkflowStartedAndCompletedEvents } from '$lib/utilities/get-started-and-completed-events';
+  import CodeBlock from './code-block.svelte';
+
+  export let events: HistoryEventWithId[] | PromiseLike<HistoryEventWithId[]>;
+
+  $: inputAndResult = getWorkflowStartedAndCompletedEvents(events);
+</script>
+
+<section class="flex flex-col gap-4">
+  {#await inputAndResult then { input, result }}
+    <h3 class="text-lg font-medium">Input & Results</h3>
+    <div class="flex gap-4">
+      <CodeBlock heading="Input" content={input} framed />
+      <CodeBlock heading="Result" content={result} framed />
+    </div>
+  {/await}
+</section>
diff --git a/src/lib/components/pagination.svelte b/src/lib/components/pagination.svelte
new file mode 100644
index 00000000..4a799e11
--- /dev/null
+++ b/src/lib/components/pagination.svelte
@@ -0,0 +1,81 @@
+<script lang="ts">
+  import Icon from 'svelte-fa';
+  import { faAngleLeft, faAngleRight } from '@fortawesome/free-solid-svg-icons';
+
+  import { page } from '$app/stores';
+
+  import FilterSelect from './select/filter-select.svelte';
+
+  type T = $$Generic<Array>;
+
+  export let key: string = null;
+  export let options = ['25', '50', '100'];
+  export let items: T;
+
+  const queryKey = key || 'per-page';
+
+  let pageNumber = 1;
+  let visibleItems: T = items.slice(0, 0);
+
+  $: queryKeyValue = $page.query.get(queryKey);
+  $: perPage = queryKeyValue || '25';
+  $: pageRange = Number(perPage);
+
+  $: previousEnabled = pageNumber > 1;
+  $: nextEnabled = pageNumber * pageRange < items.length;
+
+  $: startingIndex = pageRange * (pageNumber - 1);
+  $: endingIndex = Math.min(startingIndex + pageRange, items.length);
+
+  $: {
+    visibleItems = items.slice(startingIndex, endingIndex);
+  }
+
+  $: {
+    if (!options.includes(perPage.toString())) {
+      options = [perPage.toString(), ...options];
+    }
+  }
+</script>
+
+<div class="flex flex-col gap-4">
+  <nav class="flex justify-end gap-8">
+    <div class="flex gap-2 items-center justify-center">
+      <p class="w-fit text-right">Per Page</p>
+      <FilterSelect
+        label="Per Page"
+        parameter={queryKey}
+        value={perPage}
+        {options}
+      />
+    </div>
+    <div class="flex gap-6 items-center justify-center">
+      <button
+        class="caret"
+        disabled={!previousEnabled}
+        on:click={() => pageNumber--}
+      >
+        <Icon icon={faAngleLeft} />
+      </button>
+      <p>{startingIndex + 1}–{endingIndex} of {items.length}</p>
+      <button
+        class="caret"
+        disabled={!nextEnabled}
+        on:click={() => pageNumber++}
+      >
+        <Icon icon={faAngleRight} />
+      </button>
+    </div>
+  </nav>
+  <slot {visibleItems} />
+</div>
+
+<style lang="postcss">
+  .caret {
+    @apply text-gray-500;
+  }
+
+  .caret:disabled {
+    @apply text-gray-300 cursor-not-allowed;
+  }
+</style>
diff --git a/src/lib/components/select/filter-select.svelte b/src/lib/components/select/filter-select.svelte
index a0c7c41a..12d73317 100644
--- a/src/lib/components/select/filter-select.svelte
+++ b/src/lib/components/select/filter-select.svelte
@@ -2,15 +2,19 @@
   import { goto } from '$app/navigation';
   import { page } from '$app/stores';
   import { updateQueryParameters } from '$lib/utilities/update-query-parameters';
+
   import Select from './select.svelte';
+  import Option from './option.svelte';
 
   export let label: string = null;
-  export let value: string;
+  export let value: SelectOptionValue;
+  export let options: SelectOptionValue[] = [];
   export let parameter: string = null;
 
-  let _value = (parameter && $page.query.get(parameter)) || value;
-
   const id = `${parameter || label}-filter`;
+  const parameterValue = parameter && $page.query.get(parameter);
+
+  let _value = parameterValue || (value && value.toString());
 
   $: {
     updateQueryParameters({
@@ -23,8 +27,10 @@
   }
 </script>
 
-<div class="flex flex-col items-start justify-center">
-  <Select {id} bind:value={_value}>
-    <slot />
-  </Select>
-</div>
+<Select {id} bind:value={_value} {...$$props}>
+  <slot>
+    {#each options as option}
+      <Option value={option} />
+    {/each}
+  </slot>
+</Select>
diff --git a/src/lib/components/select/namespace-select.svelte b/src/lib/components/select/namespace-select.svelte
index 072d2d6e..7d68bfc7 100644
--- a/src/lib/components/select/namespace-select.svelte
+++ b/src/lib/components/select/namespace-select.svelte
@@ -17,8 +17,10 @@
   }
 </script>
 
-<Select dark bind:value={selectedNamespace} on:change={switchNamespace}>
-  {#each namespaces as namespace}
-    <Option value={namespace}>{namespace}</Option>
-  {/each}
-</Select>
+<div class="w-full">
+  <Select dark bind:value={selectedNamespace} on:change={switchNamespace}>
+    {#each namespaces as namespace}
+      <Option value={namespace}>{namespace}</Option>
+    {/each}
+  </Select>
+</div>
diff --git a/src/lib/components/select/option.svelte b/src/lib/components/select/option.svelte
index 14c1a197..f876c3d4 100644
--- a/src/lib/components/select/option.svelte
+++ b/src/lib/components/select/option.svelte
@@ -1,5 +1,5 @@
 <script lang="ts">
-  export let value: string | boolean = null;
+  export let value: SelectOptionValue = null;
 </script>
 
-<option {value} class="border-0"><slot /></option>
+<option {value} class="border-0"><slot>{value}</slot></option>
diff --git a/src/lib/components/select/select.svelte b/src/lib/components/select/select.svelte
index a7c73dd0..9d29bcb9 100644
--- a/src/lib/components/select/select.svelte
+++ b/src/lib/components/select/select.svelte
@@ -1,23 +1,30 @@
 <script lang="ts">
+  import Option from './option.svelte';
+
   export let id: string = null;
-  export let value: string | boolean;
+  export let value: SelectOptionValue;
+  export let label: string = null;
   export let dark: boolean = false;
   export let arrow: boolean = false;
+
+  export let options: SelectOptionValue[] = [];
 </script>
 
-<div
-  class:arrow
-  class="relative flex flex-col items-start justify-center border-gray-100 w-full"
->
+<div>
+  <label class="hidden" for={id}>{label}</label>
   <select
-    class="inline border-2 text-base px-2 w-full h-10 rounded-lg"
+    class={`inline border-2 text-base px-2 h-10 rounded-lg w-full ${$$props.class}`}
     class:dark
     class:remove={arrow}
     {id}
     bind:value
     on:change
   >
-    <slot />
+    <slot>
+      {#each options as option}
+        <Option value={option} />
+      {/each}
+    </slot>
   </select>
 </div>
 
diff --git a/src/lib/components/terminate-workflow.svelte b/src/lib/components/terminate-workflow.svelte
index feb4715f..5fde0efa 100644
--- a/src/lib/components/terminate-workflow.svelte
+++ b/src/lib/components/terminate-workflow.svelte
@@ -1,18 +1,19 @@
 <script lang="ts">
-  import { terminateWorkflow } from '$lib/services/terminate-service';
-  import { notifications } from '$lib/stores/notifications';
-  import { handleError } from '$lib/utilities/handle-error';
+  import { goto } from '$app/navigation';
 
   import type { WorkflowExecution } from '$lib/models/workflow-execution';
 
+  import { routeFor } from '$lib/utilities/route-for';
+  import { handleError } from '$lib/utilities/handle-error';
+  import { terminateWorkflow } from '$lib/services/terminate-service';
+  import { notifications } from '$lib/stores/notifications';
+
   import Button from '$lib/components/button.svelte';
-  import { getAppContext } from '$lib/utilities/get-context';
 
   export let workflow: WorkflowExecution;
   export let namespace: string;
 
   let reason = '';
-  const { refresh } = getAppContext('workflow');
 
   const isEligibleForTermination = (workflow: WorkflowExecution) =>
     String(workflow.status) === 'Running';
@@ -20,7 +21,13 @@
   const handleSuccessfulTermination = () => {
     reason = '';
     notifications.add('success', 'Workflow Terminated');
-    refresh();
+    goto(
+      routeFor('workflow', {
+        namespace,
+        workflowId: workflow.id,
+        runId: workflow.runId,
+      }),
+    );
   };
 
   const terminate = () => {
diff --git a/src/lib/components/toggle-button.svelte b/src/lib/components/toggle-button.svelte
index 02f83f04..9dc3ae6f 100644
--- a/src/lib/components/toggle-button.svelte
+++ b/src/lib/components/toggle-button.svelte
@@ -3,6 +3,7 @@
   import { page } from '$app/stores';
 
   import type { IconDefinition } from '@fortawesome/free-solid-svg-icons';
+
   import { appendQueryParameters } from '$lib/utilities/append-query-parameters';
   import { getAppContext } from '$lib/utilities/get-context';
 
diff --git a/src/lib/models/events-group.ts b/src/lib/models/events-group.ts
index f1683b4c..6d53c407 100644
--- a/src/lib/models/events-group.ts
+++ b/src/lib/models/events-group.ts
@@ -155,7 +155,7 @@ export class EventGroups {
   }
 
   static from = (
-    events: HistoryEventWithId[],
+    events: HistoryEventWithId[] = [],
     groups = new EventGroups(),
   ): EventGroups => {
     for (const event of events) {
@@ -168,8 +168,11 @@ export class EventGroups {
   };
 
   constructor(event?: CompactEvent | HistoryEventWithId[]) {
-    if (Array.isArray(event)) return EventGroups.from(event, this);
-    if (event) this.add(event);
+    if (Array.isArray(event)) {
+      EventGroups.from(event, this);
+    } else if (event) {
+      this.add(event);
+    }
   }
 
   get(id: string | number | Long): EventsGroup {
diff --git a/src/lib/models/workflow-execution.ts b/src/lib/models/workflow-execution.ts
index a136495b..d81dab88 100644
--- a/src/lib/models/workflow-execution.ts
+++ b/src/lib/models/workflow-execution.ts
@@ -25,6 +25,15 @@ type WorkflowExecutionAPIResponse = Optional<
   'executionConfig' | 'pendingActivities' | 'pendingChildren'
 >;
 
+const toPendingActivities = (
+  pendingActivity: PendingActivityInfo[] = [],
+): PendingActivity[] => {
+  return pendingActivity.map((activity) => {
+    const id = `pending-${activity.activityId}`;
+    return { ...activity, id } as unknown as PendingActivity;
+  });
+};
+
 export const toWorkflowExecution = (
   response?: WorkflowExecutionAPIResponse,
 ): WorkflowExecution => {
@@ -37,8 +46,9 @@ export const toWorkflowExecution = (
   const historyEvents = response.workflowExecutionInfo.historyLength;
   const url = `/workflows/${id}/${runId}`;
   const taskQueue = response?.executionConfig?.taskQueue?.name;
-  const pendingActivities: PendingActivity[] =
-    (response.pendingActivities as unknown as PendingActivity[]) || [];
+  const pendingActivities: PendingActivity[] = toPendingActivities(
+    response.pendingActivities,
+  );
 
   return {
     name,
diff --git a/src/lib/services/settings-service.ts b/src/lib/services/settings-service.ts
index 354b7c31..3bd56b28 100644
--- a/src/lib/services/settings-service.ts
+++ b/src/lib/services/settings-service.ts
@@ -1,8 +1,9 @@
 import { requestFromAPI } from '$lib/utilities/request-from-api';
 import { routeForApi } from '$lib/utilities/route-for-api';
+import type { SettingsResponse } from '$types';
 
 export const fetchSettings = async (request = fetch): Promise<Settings> => {
-  const settings: { Auth: { Enabled: boolean } } = await requestFromAPI(
+  const settings: SettingsResponse = await requestFromAPI(
     routeForApi('settings'),
     { request },
   );
@@ -11,5 +12,6 @@ export const fetchSettings = async (request = fetch): Promise<Settings> => {
     auth: {
       enabled: !!settings?.Auth?.Enabled,
     },
+    defaultNamespace: settings?.DefaultNamespace ?? 'default',
   };
 };
diff --git a/src/lib/stores/refreshable.ts b/src/lib/stores/refreshable.ts
deleted file mode 100644
index 071c08a5..00000000
--- a/src/lib/stores/refreshable.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { writable } from 'svelte/store';
-
-import type { Readable } from 'svelte/store';
-
-type SetIntervalType = typeof setInterval;
-type Timer = ReturnType<SetIntervalType>;
-type Timeout = Parameters<SetIntervalType>[1];
-
-export interface Refreshable<T> extends Readable<PromiseLike<T>> {
-  refresh: () => void;
-}
-
-export const refreshable = <T>(
-  callback: () => PromiseLike<T>,
-  initialData: PromiseLike<T> | T = callback(),
-  timeout: Timeout = 10000,
-): Refreshable<T> => {
-  let interval: Timer;
-
-  const refresh = () => {
-    callback().then((data: T) => store.set(Promise.resolve(data)));
-  };
-
-  const cleanUp = () => clearInterval(interval);
-
-  const setUp = () => {
-    interval = setInterval(refresh, timeout);
-    return cleanUp;
-  };
-
-  const store = writable<PromiseLike<T>>(Promise.resolve(initialData), setUp);
-
-  return {
-    subscribe: store.subscribe,
-    refresh,
-  };
-};
diff --git a/src/lib/stores/settings.ts b/src/lib/stores/settings.ts
index f61ad36e..27713ea6 100644
--- a/src/lib/stores/settings.ts
+++ b/src/lib/stores/settings.ts
@@ -2,11 +2,7 @@ import { writable } from 'svelte/store';
 
 import { fetchSettings } from '$lib/services/settings-service';
 
-export const settings = writable<Settings>({
-  auth: {
-    enabled: false,
-  },
-});
+export const settings = writable<Settings | null>(null);
 
 export const loadSettings = async (): Promise<void> => {
   const settingsRes = await fetchSettings();
diff --git a/src/lib/utilities/get-context.ts b/src/lib/utilities/get-context.ts
index eedc6dff..7947a5a9 100644
--- a/src/lib/utilities/get-context.ts
+++ b/src/lib/utilities/get-context.ts
@@ -1,12 +1,8 @@
-import type { WorkflowExecution } from '$lib/models/workflow-execution';
-import type { Refreshable } from '$lib/stores/refreshable';
 import type { DescribeNamespaceResponse } from '$types';
 import { getContext } from 'svelte';
 
-export function getAppContext(key: 'workflow'): Refreshable<WorkflowExecution>;
 export function getAppContext(key: 'group'): boolean;
 export function getAppContext(key: 'namespaces'): DescribeNamespaceResponse[];
-export function getAppContext(key: 'events'): EventualHistoryEvents;
 
 export function getAppContext(key: string): unknown {
   return getContext(key);
diff --git a/src/lib/utilities/get-started-and-completed-events.ts b/src/lib/utilities/get-started-and-completed-events.ts
index b9246fcd..bd836e91 100644
--- a/src/lib/utilities/get-started-and-completed-events.ts
+++ b/src/lib/utilities/get-started-and-completed-events.ts
@@ -3,32 +3,38 @@ type WorkflowEvents = {
   result: string;
 };
 
-export const getWorkflowStartedAndCompletedEvents = (
-  events: HistoryEvent[],
-): WorkflowEvents => {
-  const workflowStartedEvent: WorkflowExecutionStartedEvent = events?.find(
-    (event) => {
-      return !!event.workflowExecutionStartedEventAttributes;
-    },
-  );
+export const getWorkflowStartedAndCompletedEvents = async (
+  events: HistoryEventWithId[] | PromiseLike<HistoryEventWithId[]>,
+): Promise<WorkflowEvents> => {
+  events = await events;
 
-  const workflowCompletedEvent: WorkflowExecutionCompletedEvent = events?.find(
-    (event) => {
-      return !!event.workflowExecutionCompletedEventAttributes;
-    },
-  );
+  let input: string;
+  let result;
 
-  // I changed this to be a string to appease the compiler. But I _think_ these should already
-  // be decoded through the toEventHistory. This function is currently not being used and the values below
-  // needs to be verified.
-  return {
-    input: JSON.stringify(
-      workflowStartedEvent.workflowExecutionStartedEventAttributes?.input
+  const workflowStartedEvent: HistoryEventWithId = events?.find((event) => {
+    return !!event.workflowExecutionStartedEventAttributes;
+  });
+
+  const workflowCompletedEvent: HistoryEventWithId = events?.find((event) => {
+    return !!event.workflowExecutionCompletedEventAttributes;
+  });
+
+  if (workflowStartedEvent) {
+    input = JSON.stringify(
+      workflowStartedEvent?.workflowExecutionStartedEventAttributes?.input
         ?.payloads ?? '',
-    ),
-    result: JSON.stringify(
-      workflowCompletedEvent.workflowExecutionCompletedEventAttributes?.result
+    );
+  }
+
+  if (workflowCompletedEvent) {
+    result = JSON.stringify(
+      workflowCompletedEvent?.workflowExecutionCompletedEventAttributes?.result
         ?.payloads ?? '',
-    ),
+    );
+  }
+
+  return {
+    input,
+    result,
   };
 };
diff --git a/src/lib/utilities/get-visible-events.ts b/src/lib/utilities/get-visible-events.ts
index 2b70ed8d..7a0f135f 100644
--- a/src/lib/utilities/get-visible-events.ts
+++ b/src/lib/utilities/get-visible-events.ts
@@ -1,9 +1,10 @@
 import type { WorkflowExecution } from '$lib/models/workflow-execution';
+
 import { eventTypeInCategory } from './get-event-categorization';
 
 export const getVisibleEvents = async (
-  eventsRequest: EventualHistoryEvents,
-  workflowRequest: PromiseLike<WorkflowExecution>,
+  eventsRequest: EventualHistoryEvents | HistoryEventWithId[],
+  workflowRequest: PromiseLike<WorkflowExecution> | WorkflowExecution,
   category: EventTypeCategory,
 ): Promise<(HistoryEventWithId | PendingActivity)[]> => {
   const events = await eventsRequest;
diff --git a/src/lib/utilities/list-workflow-query.ts b/src/lib/utilities/list-workflow-query.ts
index 8d425a44..b996f801 100644
--- a/src/lib/utilities/list-workflow-query.ts
+++ b/src/lib/utilities/list-workflow-query.ts
@@ -1,4 +1,4 @@
-import { isDuration, isDurationString, toDate } from './to-duration';
+import { isDuration, isDurationString, toDate, tomorrow } from './to-duration';
 
 type QueryKey =
   | 'WorkflowId'
@@ -55,7 +55,7 @@ const toQueryStatement = (key: FilterKey, value: FilterValue): string => {
   const queryKey = queryKeys[key];
 
   if (isDuration(value) || isDurationString(value)) {
-    return `${queryKey} > "${toDate(value)}"`;
+    return `${queryKey} BETWEEN "${toDate(value)}" AND "${tomorrow()}"`;
   }
 
   return `${queryKey}="${value}"`;
diff --git a/src/lib/utilities/to-duration.ts b/src/lib/utilities/to-duration.ts
index 00618d9a..7ada0018 100644
--- a/src/lib/utilities/to-duration.ts
+++ b/src/lib/utilities/to-duration.ts
@@ -1,4 +1,4 @@
-import { formatISO, sub } from 'date-fns';
+import { formatISO, sub, add } from 'date-fns';
 
 type DurationKey = typeof durationKeys;
 
@@ -104,3 +104,7 @@ export const fromDate = (targetDate: string | Date): Duration => {
 
   return { seconds: difference / 1000 };
 };
+
+export const tomorrow = (): string => {
+  return formatISO(add(new Date(), { hours: 24 }));
+};
diff --git a/src/lib/utilities/update-query-parameters.ts b/src/lib/utilities/update-query-parameters.ts
index 54ecaea8..e2f21242 100644
--- a/src/lib/utilities/update-query-parameters.ts
+++ b/src/lib/utilities/update-query-parameters.ts
@@ -3,7 +3,7 @@ import { appendQueryParameters } from './append-query-parameters';
 
 type UpdateQueryParams = {
   parameter: string;
-  value?: string;
+  value?: string | number;
   query: URLSearchParams;
   path: string;
   goto: typeof goto;
@@ -20,7 +20,7 @@ export const updateQueryParameters = async ({
   goto,
 }: UpdateQueryParams): Promise<typeof value> => {
   if (value) {
-    query.set(parameter, value);
+    query.set(parameter, value.toString());
   } else {
     query.delete(parameter);
   }
diff --git a/src/routes/_header.svelte b/src/routes/_header.svelte
index 75ab8f1a..5f91ead7 100644
--- a/src/routes/_header.svelte
+++ b/src/routes/_header.svelte
@@ -7,6 +7,7 @@
   import DataConverterStatus from '$lib/components/data-converter-status.svelte';
   import { settings } from '$lib/stores/settings';
   import { user } from '$lib/stores/user';
+
   import NavigationLink from './_navigation-link.svelte';
 </script>
 
@@ -37,7 +38,7 @@
     >
       Report Bug/Give Feedback
     </a>
-    {#if $settings.auth?.enabled}
+    {#if $settings?.auth?.enabled}
       {#if $user?.email}
         <button
           class="header-button min-w-min"
diff --git a/src/routes/index.svelte b/src/routes/index.svelte
index 6f385431..06969400 100644
--- a/src/routes/index.svelte
+++ b/src/routes/index.svelte
@@ -1,5 +1,10 @@
-<script context="module" lang="ts">
-  export async function load() {
-    return { status: 302, redirect: '/namespaces/default/workflows' };
+<script lang="ts">
+  import { settings } from '$lib/stores/settings';
+  import { goto } from '$app/navigation';
+
+  $: {
+    if ($settings?.defaultNamespace) {
+      goto(`/namespaces/${$settings.defaultNamespace}`, { replaceState: true });
+    }
   }
 </script>
diff --git a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/__layout.svelte b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/__layout.svelte
index dd0e03a7..ddd0b9c8 100644
--- a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/__layout.svelte
+++ b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/__layout.svelte
@@ -1,5 +1,7 @@
 <script context="module" lang="ts">
   import type { LoadInput } from '@sveltejs/kit';
+  import type { WorkflowExecution } from '$lib/models/workflow-execution';
+
   import { fetchWorkflow } from '$lib/services/workflow-service';
 
   export async function load({ page }: LoadInput) {
@@ -11,27 +13,23 @@
       runId,
     };
 
+    const workflow = await fetchWorkflow(parameters, fetch);
+
     return {
-      props: { parameters, namespace },
+      props: { workflow, namespace },
+      stuff: { workflow },
     };
   }
 </script>
 
 <script lang="ts">
-  import { setContext } from 'svelte';
-  import { refreshable } from '$lib/stores/refreshable';
-
   import Header from './_header.svelte';
 
-  export let parameters: Parameters<typeof fetchWorkflow>[0];
+  export let workflow: WorkflowExecution;
   export let namespace: string;
-
-  let workflow = refreshable(() => fetchWorkflow(parameters));
-
-  $: setContext('workflow', workflow);
 </script>
 
 <main class="flex flex-col gap-6 h-full">
-  <Header {namespace} />
+  <Header {namespace} {workflow} />
   <slot />
 </main>
diff --git a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/_header.svelte b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/_header.svelte
index ea1fbc70..ce3e2832 100644
--- a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/_header.svelte
+++ b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/_header.svelte
@@ -2,42 +2,40 @@
   import Icon from 'svelte-fa';
   import { faChevronLeft } from '@fortawesome/free-solid-svg-icons';
 
+  import type { WorkflowExecution } from '$lib/models/workflow-execution';
+
   import WorkflowStatus from '$lib/components/workflow-status.svelte';
   import TerminateWorkflow from '$lib/components/terminate-workflow.svelte';
   import Tabs from './_tabs.svelte';
-  import { getAppContext } from '$lib/utilities/get-context';
 
   export let namespace: string;
-
-  let workflow = getAppContext('workflow');
+  export let workflow: WorkflowExecution;
 </script>
 
-{#await $workflow then workflow}
-  <header class="flex flex-col gap-4">
-    <main class="flex flex-col gap-1 relative">
-      <a
-        href="/namespaces/{namespace}/workflows"
-        class="absolute top-2 back-to-workflows"
-        style="left: -1.5rem"
-      >
-        <Icon icon={faChevronLeft} />
-      </a>
-      <div class="flex justify-between items-center">
-        <h1 class="text-2xl">
-          {workflow.name}
-          <WorkflowStatus status={workflow?.status} />
-        </h1>
-        <TerminateWorkflow {workflow} {namespace} />
-      </div>
-      <p class="text-md">
-        <span>Workflow ID</span>
-        <span class="font-medium">{workflow.id}</span>
-      </p>
-      <p class="text-md">
-        <span>Run ID</span>
-        <span class="font-medium">{workflow.runId}</span>
-      </p>
-    </main>
-    <Tabs {workflow} />
-  </header>
-{/await}
+<header class="flex flex-col gap-4">
+  <main class="flex flex-col gap-1 relative">
+    <a
+      href="/namespaces/{namespace}/workflows"
+      class="absolute top-2 back-to-workflows"
+      style="left: -1.5rem"
+    >
+      <Icon icon={faChevronLeft} />
+    </a>
+    <div class="flex justify-between items-center">
+      <h1 class="text-2xl">
+        {workflow.name}
+        <WorkflowStatus status={workflow?.status} />
+      </h1>
+      <TerminateWorkflow {workflow} {namespace} />
+    </div>
+    <p class="text-md">
+      <span>Workflow ID</span>
+      <span class="font-medium">{workflow.id}</span>
+    </p>
+    <p class="text-md">
+      <span>Run ID</span>
+      <span class="font-medium">{workflow.runId}</span>
+    </p>
+  </main>
+  <Tabs {workflow} />
+</header>
diff --git a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/__layout.svelte b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/__layout.svelte
index 82201dfe..0c419561 100644
--- a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/__layout.svelte
+++ b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/__layout.svelte
@@ -2,6 +2,8 @@
   import type { LoadInput } from '@sveltejs/kit';
   import type { WorkflowParameters } from '$lib/utilities/route-for';
 
+  import { fetchEvents } from '$lib/services/events-service';
+
   export async function load({ page }: LoadInput) {
     const { workflow: workflowId, run: runId, namespace } = page.params;
     const parameters = { namespace, executionId: workflowId, runId };
@@ -11,14 +13,17 @@
     return {
       props: {
         workflow: { workflowId, runId, namespace },
+        events,
         parameters,
       },
+      stuff: {
+        events,
+      },
     };
   }
 </script>
 
 <script lang="ts">
-  import { setContext } from 'svelte';
   import {
     faCode,
     faLayerGroup,
@@ -26,21 +31,19 @@
   } from '@fortawesome/free-solid-svg-icons';
 
   import { routeFor } from '$lib/utilities/route-for';
-  import { fetchEvents } from '$lib/services/events-service';
-  import { refreshable } from '$lib/stores/refreshable';
 
   import ExportHistory from '$lib/components/export-history.svelte';
   import ToggleButton from '$lib/components/toggle-button.svelte';
   import ToggleButtons from '$lib/components/toggle-buttons.svelte';
+  import InputAndResults from '$lib/components/input-and-result.svelte';
 
   export let workflow: WorkflowParameters;
   export let parameters: Parameters<typeof fetchEvents>[0];
-
-  let events = refreshable(() => fetchEvents(parameters));
-  $: setContext('events', $events);
+  export let events: HistoryEventWithId[];
 </script>
 
 <section class="flex flex-col gap-4">
+  <InputAndResults {events} />
   <nav class="flex gap-4 justify-between items-end">
     <h3 class="text-lg font-medium">Event History</h3>
     <div class="flex gap-4">
diff --git a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/__layout.svelte b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/__layout.svelte
index b7bf743b..cd4c1dce 100644
--- a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/__layout.svelte
+++ b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/__layout.svelte
@@ -1,15 +1,28 @@
+<script lang="ts" context="module">
+  import type { LoadInput } from '@sveltejs/kit';
+
+  export const load = async ({ stuff }: LoadInput) => {
+    const { events } = stuff;
+
+    console.log({ events });
+
+    return {
+      props: { events },
+    };
+  };
+</script>
+
 <script lang="ts">
   import { EventGroups } from '$lib/models/events-group';
   import EventTable from '$lib/components/event-table.svelte';
-  import { getAppContext } from '$lib/utilities/get-context';
 
-  export let events = getAppContext('events');
+  export let events: HistoryEventWithId[];
+
+  const activities = EventGroups.from(events);
 </script>
 
-{#await EventGroups.fromPromise(events) then activities}
-  <EventTable events={activities}>
-    <div slot="details" class="w-full h-full py-4">
-      <slot />
-    </div>
-  </EventTable>
-{/await}
+<EventTable events={activities}>
+  <div slot="details" class="w-full h-full py-4">
+    <slot />
+  </div>
+</EventTable>
diff --git a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/activity-[eventId]/__layout.svelte b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/activity-[eventId]/__layout.svelte
index f42fc4cf..dbeab177 100644
--- a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/activity-[eventId]/__layout.svelte
+++ b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/activity-[eventId]/__layout.svelte
@@ -2,7 +2,7 @@
   import type { EventParameter } from '$lib/utilities/route-for';
   import type { LoadInput } from '@sveltejs/kit';
 
-  export async function load({ page }: LoadInput) {
+  export async function load({ page, stuff }: LoadInput) {
     const {
       workflow: workflowId,
       run: runId,
@@ -10,8 +10,11 @@
       eventId,
     } = page.params;
 
+    const { events } = stuff;
+
     return {
       props: {
+        events,
         params: {
           workflowId,
           runId,
@@ -27,16 +30,15 @@
   import { EventGroups, EventsGroup } from '$lib/models/events-group';
   import { routeFor } from '$lib/utilities/route-for';
   import { page } from '$app/stores';
-  import { getAppContext } from '$lib/utilities/get-context';
 
-  let events = getAppContext('events');
+  export let events: HistoryEventWithId[];
   export let params: EventParameter;
 
-  const getEventsGroup = async (
-    events: EventualHistoryEvents,
+  const getEventsGroup = (
+    events: HistoryEventWithId[],
     id: string,
-  ): Promise<{ group: EventsGroup; events: HistoryEventWithId[] }> => {
-    const groups = await EventGroups.fromPromise(events);
+  ): { group: EventsGroup; events: HistoryEventWithId[] } => {
+    const groups = EventGroups.from(events);
     const group = groups.get(id);
 
     return {
diff --git a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/activity-[eventId]/events/[id].svelte b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/activity-[eventId]/events/[id].svelte
index 96014446..f6bd9645 100644
--- a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/activity-[eventId]/events/[id].svelte
+++ b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/compact/activity-[eventId]/events/[id].svelte
@@ -1,20 +1,27 @@
-<script lang="ts">
-  import { page } from '$app/stores';
+<script lang="ts" context="module">
+  import type { LoadInput } from '@sveltejs/kit';
 
-  import EventDetails from '$lib/components/event-details.svelte';
-  import { getAppContext } from '$lib/utilities/get-context';
+  export const load = async ({ stuff, page }: LoadInput) => {
+    const { events } = stuff;
+
+    const event: HistoryEventWithId = events.find(
+      (event: HistoryEventWithId) => event.id === page.params.id,
+    );
+
+    if (!event) {
+      return { status: 404 };
+    }
 
-  const findEvent = async (
-    data: EventualHistoryEvents,
-    id: string,
-  ): Promise<HistoryEventWithId> => {
-    return data.then((events) => events.find((event) => event.id === id));
+    return {
+      props: { attributes: event.attributes },
+    };
   };
+</script>
+
+<script lang="ts">
+  import EventDetails from '$lib/components/event-details.svelte';
 
-  let events = getAppContext('events');
-  $: event = findEvent(events, $page.params.id);
+  export let attributes: EventAttribute;
 </script>
 
-{#await event then { attributes }}
-  <EventDetails {attributes} />
-{/await}
+<EventDetails {attributes} />
diff --git a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/__layout.svelte b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/__layout.svelte
index 672c3021..c1969a45 100644
--- a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/__layout.svelte
+++ b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/__layout.svelte
@@ -1,17 +1,29 @@
+<script lang="ts" context="module">
+  import type { LoadInput } from '@sveltejs/kit';
+  import type { WorkflowExecution } from '$lib/models/workflow-execution';
+
+  export const load = async ({ stuff }: LoadInput) => {
+    const { workflow, events } = stuff;
+
+    return {
+      props: { workflow, events },
+    };
+  };
+</script>
+
 <script lang="ts">
   import { getVisibleEvents } from '$lib/utilities/get-visible-events';
 
   import FilterSelect from '$lib/components/select/filter-select.svelte';
   import Option from '$lib/components/select/option.svelte';
   import EventTable from '$lib/components/event-table.svelte';
-  import { getAppContext } from '$lib/utilities/get-context';
 
   let category: EventTypeCategory = null;
 
-  let workflow = getAppContext('workflow');
-  let events = getAppContext('events');
+  export let workflow: WorkflowExecution;
+  export let events: HistoryEventWithId[];
 
-  $: eventsAndActivities = getVisibleEvents(events, $workflow, category);
+  const eventsAndActivities = getVisibleEvents(events, workflow, category);
 </script>
 
 {#await eventsAndActivities then events}
diff --git a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/event-[id].svelte b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/event-[id].svelte
index 96014446..94115af2 100644
--- a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/event-[id].svelte
+++ b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/event-[id].svelte
@@ -1,20 +1,28 @@
-<script lang="ts">
-  import { page } from '$app/stores';
+<script lang="ts" context="module">
+  import type { LoadInput } from '@sveltejs/kit';
 
-  import EventDetails from '$lib/components/event-details.svelte';
-  import { getAppContext } from '$lib/utilities/get-context';
+  export const load = async ({ stuff, page }: LoadInput) => {
+    const { events } = stuff;
+    const { id } = page.params;
+
+    const event: HistoryEventWithId = events.find(
+      (event: HistoryEventWithId) => event.id === id,
+    );
+
+    if (!event) {
+      return { status: 404 };
+    }
 
-  const findEvent = async (
-    data: EventualHistoryEvents,
-    id: string,
-  ): Promise<HistoryEventWithId> => {
-    return data.then((events) => events.find((event) => event.id === id));
+    return {
+      props: { attributes: event.attributes },
+    };
   };
+</script>
+
+<script lang="ts">
+  import EventDetails from '$lib/components/event-details.svelte';
 
-  let events = getAppContext('events');
-  $: event = findEvent(events, $page.params.id);
+  export let attributes: EventAttribute;
 </script>
 
-{#await event then { attributes }}
-  <EventDetails {attributes} />
-{/await}
+<EventDetails {attributes} />
diff --git a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/pending-[id].svelte b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/pending-[id].svelte
index 96d19afe..d4b0fe72 100644
--- a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/pending-[id].svelte
+++ b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/full/pending-[id].svelte
@@ -1,21 +1,29 @@
+<script lang="ts" context="module">
+  import type { LoadInput } from '@sveltejs/kit';
+  import type { WorkflowExecution } from '$lib/models/workflow-execution';
+
+  export const load = async ({ stuff }: LoadInput) => {
+    const { workflow, events } = stuff;
+
+    return {
+      props: { workflow, events },
+    };
+  };
+</script>
+
 <script lang="ts">
   import { page } from '$app/stores';
   import EventDetails from '$lib/components/event-details.svelte';
 
-  import type { WorkflowExecution } from '$lib/models/workflow-execution';
-  import { getAppContext } from '$lib/utilities/get-context';
-
-  const findActivity = async (
-    workflow: PromiseLike<WorkflowExecution>,
+  const findActivity = (
+    workflow: WorkflowExecution,
     id: string,
-  ): Promise<PendingActivity> => {
-    return workflow.then(({ pendingActivities }) => {
-      return pendingActivities.find((activity) => activity.activityId === id);
-    });
+  ): PendingActivity => {
+    return workflow.pendingActivities.find((activity) => activity.id === id);
   };
 
-  let workflow = getAppContext('workflow');
-  $: pendingActivity = findActivity($workflow, $page.params.id);
+  export let workflow: WorkflowExecution;
+  const pendingActivity = findActivity(workflow, $page.params.id);
 </script>
 
 {#await pendingActivity then activity}
diff --git a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/json.svelte b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/json.svelte
index aa0d4e42..08f746bf 100644
--- a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/json.svelte
+++ b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/history/json.svelte
@@ -1,10 +1,19 @@
+<script lang="ts" context="module">
+  import type { LoadInput } from '@sveltejs/kit';
+
+  export const load = async ({ stuff }: LoadInput) => {
+    const { events } = stuff;
+
+    return {
+      props: { events },
+    };
+  };
+</script>
+
 <script lang="ts">
   import CodeBlock from '$lib/components/code-block.svelte';
-  import { getAppContext } from '$lib/utilities/get-context';
 
-  let events = getAppContext('events');
+  export let events: HistoryEventWithId[];
 </script>
 
-{#await events then content}
-  <CodeBlock {content} />
-{/await}
+<CodeBlock content={events} />
diff --git a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/stack-trace.svelte b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/stack-trace.svelte
index 21296fbb..95f5a0c5 100644
--- a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/stack-trace.svelte
+++ b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/stack-trace.svelte
@@ -1,17 +1,19 @@
 <script context="module" lang="ts">
+  import type { WorkflowExecution } from '$lib/models/workflow-execution';
   import type { LoadInput } from '@sveltejs/kit';
 
-  export async function load({ page }: LoadInput) {
-    const { namespace, workflow: id, run: runId } = page.params;
-    const workflow = { id, runId };
+  export async function load({ page, stuff }: LoadInput) {
+    const { namespace } = page.params;
+    const { workflow } = stuff;
 
-    const stackTrace = getWorkflowStackTrace({
+    const stackTrace = await getWorkflowStackTrace({
       workflow,
       namespace,
     });
 
     return {
       props: {
+        workflow,
         namespace,
         stackTrace,
       },
@@ -27,12 +29,11 @@
   import CodeBlock from '$lib/components/code-block.svelte';
   import Button from '$lib/components/button.svelte';
   import EmptyState from '$lib/components/empty-state.svelte';
-  import { getAppContext } from '$lib/utilities/get-context';
 
   export let namespace: string;
   export let stackTrace: string;
+  export let workflow: WorkflowExecution;
 
-  let workflow = getAppContext('workflow');
   let currentdate = new Date();
   let isLoading = false;
 
@@ -40,7 +41,7 @@
     isLoading = true;
 
     stackTrace = await getWorkflowStackTrace({
-      workflow: $workflow,
+      workflow,
       namespace,
     });
 
@@ -49,22 +50,20 @@
   };
 </script>
 
-{#await $workflow then workflow}
-  <section>
-    {#if String(workflow.status) === 'Running'}
-      <div class="flex items-center gap-4">
-        <Button on:click={refreshStackTrace} icon={faRedo} loading={isLoading}>
-          Refresh
-        </Button>
-        <p>Stack Trace at {currentdate.toLocaleTimeString()}</p>
+<section>
+  {#if String(workflow.status) === 'Running'}
+    <div class="flex items-center gap-4">
+      <Button on:click={refreshStackTrace} icon={faRedo} loading={isLoading}>
+        Refresh
+      </Button>
+      <p>Stack Trace at {currentdate.toLocaleTimeString()}</p>
+    </div>
+    {#await stackTrace then result}
+      <div class="flex items-start h-full">
+        <CodeBlock content={result} language="text" />
       </div>
-      {#await stackTrace then result}
-        <div class="flex items-start h-full">
-          <CodeBlock content={result} language="text" />
-        </div>
-      {/await}
-    {:else}
-      <EmptyState title="No Stack Traces Found" />
-    {/if}
-  </section>
-{/await}
+    {/await}
+  {:else}
+    <EmptyState title="No Stack Traces Found" />
+  {/if}
+</section>
diff --git a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/workers.svelte b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/workers.svelte
index 15768958..9bb93bd4 100644
--- a/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/workers.svelte
+++ b/src/routes/namespaces/[namespace]/workflows/[workflow]/[run]/workers.svelte
@@ -1,46 +1,41 @@
 <script context="module" lang="ts">
   import type { LoadInput } from '@sveltejs/kit';
+  import type { WorkflowExecution } from '$lib/models/workflow-execution';
 
   import { getPollers } from '$lib/services/pollers-service';
+  import type { GetPollersResponse } from '$lib/services/pollers-service';
 
-  export async function load({ page }: LoadInput) {
+  export async function load({ page, stuff }: LoadInput) {
     const { namespace } = page.params;
+    const { workflow } = stuff;
+    const { taskQueue } = workflow as WorkflowExecution;
+
+    const workers = await getPollers({ queue: taskQueue, namespace });
 
     return {
-      props: { namespace },
+      props: { workflow, workers, taskQueue, namespace },
     };
   }
 </script>
 
 <script lang="ts">
-  import { refreshable } from '$lib/stores/refreshable';
-
   import WorkersTable from '$lib/components/workers-table.svelte';
   import WorkersRow from '$lib/components/workers-row.svelte';
   import EmptyState from '$lib/components/empty-state.svelte';
-  import { getAppContext } from '$lib/utilities/get-context';
 
   export let namespace: string;
-
-  let workflow = getAppContext('workflow');
-
-  $: pollers = refreshable(async () => {
-    let { taskQueue } = await $workflow;
-    return getPollers({ queue: taskQueue, namespace });
-  });
+  export let workflow: WorkflowExecution;
+  export let workers: GetPollersResponse;
+  export let taskQueue: string;
 </script>
 
-{#await $workflow then { taskQueue }}
-  <section class="flex flex-col gap-4">
-    <h3 class="text-lg font-medium">Task Queue: {taskQueue}</h3>
-    {#await $pollers then workers}
-      {#each workers.pollers as poller}
-        <WorkersTable>
-          <WorkersRow {poller} />
-        </WorkersTable>
-      {:else}
-        <EmptyState title={'No Workers Found'} />
-      {/each}
-    {/await}
-  </section>
-{/await}
+<section class="flex flex-col gap-4">
+  <h3 class="text-lg font-medium">Task Queue: {taskQueue}</h3>
+  {#each workers.pollers as poller}
+    <WorkersTable>
+      <WorkersRow {poller} />
+    </WorkersTable>
+  {:else}
+    <EmptyState title={'No Workers Found'} />
+  {/each}
+</section>
diff --git a/src/routes/namespaces/[namespace]/workflows/index.svelte b/src/routes/namespaces/[namespace]/workflows/index.svelte
index e691ce87..b75ec009 100644
--- a/src/routes/namespaces/[namespace]/workflows/index.svelte
+++ b/src/routes/namespaces/[namespace]/workflows/index.svelte
@@ -1,5 +1,8 @@
 <script context="module" lang="ts">
   import type { LoadInput } from '@sveltejs/kit';
+  import type { CombinedWorkflowExecutionsResponse } from '$lib/services/workflow-service';
+
+  import { fetchAllWorkflows } from '$lib/services/workflow-service';
 
   export async function load({ page, fetch }: LoadInput) {
     const isAdvancedSearch = page.query.has('query');
@@ -14,17 +17,18 @@
     const executionStatus = page.query.get('status') as WorkflowStatus;
     const query = page.query.get('query');
 
-    const parameters: FilterParameters = {
+    const parameters: ValidWorkflowParameters = {
       workflowId,
       workflowType,
       timeRange,
       executionStatus,
       query,
     };
-    const initialData = await fetchAllWorkflows(namespace, parameters, fetch);
+
+    const workflows = await fetchAllWorkflows(namespace, parameters, fetch);
 
     return {
-      props: { initialData, namespace, parameters, isAdvancedSearch },
+      props: { workflows, namespace, parameters, isAdvancedSearch },
     };
   }
 </script>
@@ -32,18 +36,15 @@
 <script lang="ts">
   import VirtualList from '@sveltejs/svelte-virtual-list';
 
-  import { fetchAllWorkflows } from '$lib/services/workflow-service';
-  import { refreshable } from '$lib/stores/refreshable';
-
   import WorkflowsSummaryTable from './_workflows-summary-table.svelte';
   import WorkflowsSummaryRow from './_workflows-summary-row.svelte';
   import WorkflowFilters from './_workflow-filters.svelte';
   import EmptyState from '$lib/components/empty-state.svelte';
   import WorkflowsLoadingState from './_workflows-loading.svelte';
+  import Badge from '$lib/components/badge.svelte';
 
   export let namespace: string;
-  export let initialData: ReturnType<typeof fetchAllWorkflows>;
-  export let parameters: FilterParameters;
+  export let workflows: CombinedWorkflowExecutionsResponse;
   export let isAdvancedSearch: boolean;
 
   let timeFormat: TimeFormat = 'UTC';
@@ -51,16 +52,11 @@
   const errorMessage = isAdvancedSearch
     ? 'Please check your syntax and try again.'
     : 'If you have filters applied, try adjusting them.';
-
-  $: data = refreshable(
-    () => fetchAllWorkflows(namespace, parameters),
-    initialData,
-  );
 </script>
 
-<h2 class="text-2xl">Workflows</h2>
+<h2 class="text-2xl">Workflows <Badge type="beta">Beta</Badge></h2>
 <WorkflowFilters bind:timeFormat />
-{#await $data}
+{#await workflows}
   <WorkflowsLoadingState />
 {:then { workflows }}
   {#if workflows.length}
diff --git a/src/routes/namespaces/index.svelte b/src/routes/namespaces/index.svelte
index 242548b7..06969400 100644
--- a/src/routes/namespaces/index.svelte
+++ b/src/routes/namespaces/index.svelte
@@ -1,5 +1,10 @@
-<script context="module" lang="ts">
-  export async function load() {
-    return { status: 302, redirect: '/namespaces/default' };
+<script lang="ts">
+  import { settings } from '$lib/stores/settings';
+  import { goto } from '$app/navigation';
+
+  $: {
+    if ($settings?.defaultNamespace) {
+      goto(`/namespaces/${$settings.defaultNamespace}`, { replaceState: true });
+    }
   }
 </script>
diff --git a/src/types/index.ts b/src/types/index.ts
index efbaae88..7f02a392 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -125,3 +125,9 @@ export type TaskQueueStatus = temporal.api.taskqueue.v1.ITaskQueueStatus;
 // google
 
 export type Timestamp = google.protobuf.ITimestamp;
+
+// extra APIs
+export type SettingsResponse = {
+  Auth: { Enabled: boolean };
+  DefaultNamespace: string;
+};


Test patch:
diff --git a/src/lib/utilities/is-network-error.test.ts b/src/lib/utilities/is-network-error.test.ts
index a0c47c52..c1cfe5b6 100644
--- a/src/lib/utilities/is-network-error.test.ts
+++ b/src/lib/utilities/is-network-error.test.ts
@@ -7,28 +7,28 @@ const networkErr = {
 };
 
 describe(isNetworkError, () => {
-  it('Should infer a networkErrorr error with the correct shape', () => {
+  it('Should infer a networkError error with the correct shape', () => {
     try {
       throw networkErr;
     } catch (err) {
       expect(isNetworkError(err)).toBeTruthy();
     }
   });
-  it('Should not infer a networkErrorr error with the incorrecrt shape', () => {
+  it('Should not infer a networkError error with the incorrecrt shape', () => {
     try {
       throw { somethingElse: '' };
     } catch (err) {
       expect(isNetworkError(err)).toBeFalsy();
     }
   });
-  it("Should not infer a networkErrorr when it's a js error", () => {
+  it("Should not infer a networkError when it's a js error", () => {
     try {
       throw new Error('error');
     } catch (err) {
       expect(isNetworkError(err)).toBeFalsy();
     }
   });
-  it("Should not infer a networkErrorr when it's a promise", async () => {
+  it("Should not infer a networkError when it's a promise", async () => {
     try {
       await Promise.reject();
     } catch (err) {
diff --git a/src/lib/utilities/list-workflow-query.test.ts b/src/lib/utilities/list-workflow-query.test.ts
index 24b87a99..a8aa760f 100644
--- a/src/lib/utilities/list-workflow-query.test.ts
+++ b/src/lib/utilities/list-workflow-query.test.ts
@@ -12,11 +12,14 @@ describe(toListWorkflowQuery, () => {
 
   it('should convert an timeRange with a Duration as a value', () => {
     jest.useFakeTimers().setSystemTime(new Date('2020-01-01').getTime());
+    const tomorrow = '2020-01-02T00:00:00Z';
     const twentyFourHoursEarlier = '2019-12-31T00:00:00Z';
 
     const query = toListWorkflowQuery({ timeRange: { hours: 24 } });
 
-    expect(query).toBe(`StartTime > "${twentyFourHoursEarlier}"`);
+    expect(query).toBe(
+      `StartTime BETWEEN "${twentyFourHoursEarlier}" AND "${tomorrow}"`,
+    );
   });
 
   it('should convert an two values using an "and"', () => {