Repository: temporalio/ui
Pull request #296 (2022-03-10 20:49:29)

Fix issue with pulling from query parameters in event history view
Grabs the `searchParams` from the correct `url` object as opposed to `params`.

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>36c87eb</code>
</td></tr>
<tr><td><strong>Status:</strong></td><td>&nbsp;✅&nbsp; Deploy successful!</td></tr>
<tr><td><strong>Preview URL:</strong></td><td>
<a href='https://989a4b03.ui-c3x.pages.dev'>https://989a4b03.ui-c3x.pages.dev</a>
</td></tr>
</table>

[View logs](https://dash.cloudflare.com/?to=/:account/pages/view/temporal-pizza/989a4b03-097a-4a1d-87ad-4d0be0611782)


Patch:
diff --git a/cypress/integration/check-redirects.spec.js b/cypress/integration/check-redirects.spec.js
new file mode 100644
index 00000000..a7d9fb10
--- /dev/null
+++ b/cypress/integration/check-redirects.spec.js
@@ -0,0 +1,11 @@
+/// <reference types="cypress" />
+
+describe('Workflow Executions List', () => {
+  it('should redirect ', () => {
+    cy.visit('/');
+    cy.url().should(
+      'include',
+      '/namespaces/default/workflows?time-range=24+hours',
+    );
+  });
+});
diff --git a/src/lib/components/event.svelte b/src/lib/components/event.svelte
index 1e41ffe6..6773eba9 100644
--- a/src/lib/components/event.svelte
+++ b/src/lib/components/event.svelte
@@ -30,7 +30,7 @@
   class:pending
   class:active={$page.params.id === event.id}
 >
-  <article class="flex gap-4 items-center p-4">
+  <article class="flex gap-4 items-center p-4 w-full">
     <p class="w-5 text-center text-gray-500">{id}</p>
     <div class="w-full">
       <h2 class="mb-2 {tag}">
diff --git a/src/lib/components/select/namespace-select.svelte b/src/lib/components/select/namespace-select.svelte
index 416b991b..0d66f08a 100644
--- a/src/lib/components/select/namespace-select.svelte
+++ b/src/lib/components/select/namespace-select.svelte
@@ -11,7 +11,7 @@
     (namespace) => namespace.namespaceInfo.name,
   );
 
-  let selectedNamespace = $currentNamespace;
+  $: selectedNamespace = $currentNamespace;
 
   function switchNamespace() {
     goto('/namespaces/' + selectedNamespace);
diff --git a/src/lib/stores/namespace.ts b/src/lib/stores/namespace.ts
index 970d8730..9e1679cd 100644
--- a/src/lib/stores/namespace.ts
+++ b/src/lib/stores/namespace.ts
@@ -1,18 +1,21 @@
 import { browser } from '$app/env';
 import { page } from '$app/stores';
-import { derived } from 'svelte/store';
-import UrlPattern from 'url-pattern';
+import { namespaceUrlPattern } from '$lib/utilities/namespace-url-pattern';
+import { derived, get } from 'svelte/store';
+import { settings } from '$lib/stores/settings';
 
-const pattern = new UrlPattern('/namespaces/:namespace/*');
 const onlyInBrowser = <T>(fn: () => T): T => {
   if (browser) return fn();
 };
 
 export const namespace = derived(page, ($page) => {
-  const match = pattern.match($page.url.pathname);
+  const match = namespaceUrlPattern.match($page.url.pathname);
+
+  const defaultNamespace = get(settings).defaultNamespace;
+
   const namespace =
     onlyInBrowser(
-      () => localStorage.getItem('currentNamespace') || 'default',
+      () => localStorage.getItem('currentNamespace') || defaultNamespace,
     ) || 'default';
 
   if (match) {
diff --git a/src/lib/stores/settings.ts b/src/lib/stores/settings.ts
index 27713ea6..993e98dc 100644
--- a/src/lib/stores/settings.ts
+++ b/src/lib/stores/settings.ts
@@ -2,6 +2,9 @@ import { writable } from 'svelte/store';
 
 import { fetchSettings } from '$lib/services/settings-service';
 
+/**
+ * We await loadSettings this store in the main __layout so it should already be hydrated to any other part of the app
+ */
 export const settings = writable<Settings | null>(null);
 
 export const loadSettings = async (): Promise<void> => {
diff --git a/src/lib/utilities/namespace-url-pattern.ts b/src/lib/utilities/namespace-url-pattern.ts
new file mode 100644
index 00000000..d692d153
--- /dev/null
+++ b/src/lib/utilities/namespace-url-pattern.ts
@@ -0,0 +1,9 @@
+import UrlPattern from 'url-pattern';
+
+// The default for this lib doesn't include .-_ which are all valid characters for a cloud namespace
+const urlPatternOpts = { segmentValueCharset: '.a-zA-Z0-9_-' };
+
+export const namespaceUrlPattern = new UrlPattern(
+  '/namespaces/:namespace/*',
+  urlPatternOpts,
+);
diff --git a/src/routes/__layout.svelte b/src/routes/__layout.svelte
index 7cb449b7..99a38799 100644
--- a/src/routes/__layout.svelte
+++ b/src/routes/__layout.svelte
@@ -40,7 +40,7 @@
     loadCluster().catch(() =>
       notifications.add('error', 'Unable to fetch cluster info'),
     );
-    loadSettings();
+    await loadSettings();
 
     return {
       props: { namespaces },
diff --git a/src/routes/namespaces/[namespace]/archival/index.svelte b/src/routes/namespaces/[namespace]/archival/index.svelte
index 9697ea03..e920518b 100644
--- a/src/routes/namespaces/[namespace]/archival/index.svelte
+++ b/src/routes/namespaces/[namespace]/archival/index.svelte
@@ -2,15 +2,16 @@
   import type { Load } from '@sveltejs/kit';
 
   export const load: Load = async function ({ params, url, stuff }) {
-    const query = url.searchParams;
+    const { searchParams } = url;
 
-    if (!query.has('time-range')) query.set('time-range', '24 hours');
+    if (!searchParams.has('time-range'))
+      searchParams.set('time-range', '24 hours');
 
     const namespace = params.namespace;
-    const workflowId = query.get('workflow-id');
-    const workflowType = query.get('workflow-type');
-    const timeRange = query.get('time-range');
-    const executionStatus = query.get('status') as WorkflowStatus;
+    const workflowId = searchParams.get('workflow-id');
+    const workflowType = searchParams.get('workflow-type');
+    const timeRange = searchParams.get('time-range');
+    const executionStatus = searchParams.get('status') as WorkflowStatus;
 
     const parameters: ArchiveFilterParameters = {
       workflowId,
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 3d3d1d8c..b973ff81 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,9 +1,9 @@
 <script lang="ts" context="module">
   import type { Load } from '@sveltejs/kit';
 
-  export const load: Load = async function ({ params, stuff }) {
+  export const load: Load = async function ({ params, url, stuff }) {
     const { workflow, events } = stuff;
-    const category = params.category;
+    const category = url.searchParams.get('category');
 
     return {
       props: { workflow, events, category },


Test patch:
diff --git a/src/lib/utilities/namespace-url-pattern.test.ts b/src/lib/utilities/namespace-url-pattern.test.ts
new file mode 100644
index 00000000..8288953f
--- /dev/null
+++ b/src/lib/utilities/namespace-url-pattern.test.ts
@@ -0,0 +1,31 @@
+import { namespaceUrlPattern } from './namespace-url-pattern';
+
+describe('Namespace Url Pattern', () => {
+  it('Should match a namespace url', () => {
+    const result = namespaceUrlPattern.match('/namespaces/stuff/url');
+    expect(result).toBeTruthy();
+    expect(result).toEqual({
+      namespace: 'stuff',
+      _: 'url',
+    });
+  });
+
+  it('Should not match a non namespace url', () => {
+    const result = namespaceUrlPattern.match(
+      '/namespaces_butdifferent/stuff/url',
+    );
+    expect(result).toBeNull();
+  });
+
+  it('Should match a namespace with special characters in it like . _ -', () => {
+    const result = namespaceUrlPattern.match(
+      '/namespaces/sergey.temporal-dev_test/workflows/d643b6a9-b73d-4440-b1ec-91234bbc0a11/e8c0acc6-740e-428d-a2e2-c9bb7c081c9c/history/full',
+    );
+
+    expect(result).toBeTruthy();
+    expect(result).toEqual({
+      namespace: 'sergey.temporal-dev_test',
+      _: 'workflows/d643b6a9-b73d-4440-b1ec-91234bbc0a11/e8c0acc6-740e-428d-a2e2-c9bb7c081c9c/history/full',
+    });
+  });
+});