Skip to content
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
da0bb84
Svelte5
Alex-Tideman Jun 5, 2025
b9d8bdc
Add search-attributes tab, memo tab, user metadata tab
Alex-Tideman Jun 5, 2025
bd41961
add tests
GraceGardner Jun 30, 2025
c8af4e8
rm console logs
GraceGardner Jun 30, 2025
6f8511d
rm inspect
GraceGardner Jun 30, 2025
34dd7f4
rm unused mock data
GraceGardner Jun 30, 2025
5bc9a1f
add typing to overrideTheme
GraceGardner Jun 30, 2025
8715bb4
Merge branch 'main' into user-metadata
GraceGardner Jun 30, 2025
a0d54a2
center divs
GraceGardner Jun 30, 2025
dc9a041
add metadata-tab to translate
GraceGardner Jul 1, 2025
3a0aff2
add markdown override-theme to go
GraceGardner Jul 1, 2025
d9445ae
add banner
GraceGardner Jul 16, 2025
dd02933
fix function
GraceGardner Jul 22, 2025
99623ee
rm consols
GraceGardner Jul 22, 2025
e9451b6
Merge branch 'main' into user-metadata
GraceGardner Jul 22, 2025
fe713b7
update event display, fix markdown, make summary and details and curr…
GraceGardner Jul 28, 2025
f18c994
quick tweak to view height
GraceGardner Jul 28, 2025
27d1ab3
fix errors caused by runes mode/legacy mismatch
GraceGardner Jul 28, 2025
c269080
fix conflicts/merge main
GraceGardner Jul 28, 2025
a8026c9
<<Merge branch 'main' into user-metadata
GraceGardner Jul 29, 2025
1b07d4c
add summary back in and remove event id
GraceGardner Jul 29, 2025
31ae005
Do some refactoring, move events into the left side
Alex-Tideman Jul 29, 2025
ba71313
move memo into component
GraceGardner Jul 29, 2025
9690395
mv search attr into component
GraceGardner Jul 29, 2025
7e09057
updates from feedback
GraceGardner Jul 31, 2025
cf5b784
Merge branch 'main' into user-metadata
GraceGardner Aug 5, 2025
dc2a742
put usermetadata into single component
GraceGardner Aug 5, 2025
7b109cc
clean up metadata events
GraceGardner Aug 5, 2025
e0159a0
rm ('Metadata groups:', metadataGroups);
GraceGardner Aug 5, 2025
805f0ca
Style updates
Alex-Tideman Aug 6, 2025
67f5def
Move tab
Alex-Tideman Aug 6, 2025
bd3d51e
standardize the time stamp with other time formats
GraceGardner Aug 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions server/server/route/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ func SetRenderRoute(e *echo.Echo, publicPath string) {
e.GET(renderPath, func(c echo.Context) error {
content := c.QueryParam("content")
theme := c.QueryParam("theme")
overrideTheme := c.QueryParam("overrideTheme")

finalTheme := theme
if theme != "" && overrideTheme != "" {
finalTheme = fmt.Sprintf("%s-%s", theme, overrideTheme)
}

// Process markdown to HTML
renderedHTML := processMarkdown(content)
Expand All @@ -175,7 +181,7 @@ func SetRenderRoute(e *echo.Echo, publicPath string) {
}{
Content: template.HTML(renderedHTML),
Nonce: nonce,
Theme: theme,
Theme: finalTheme,
CSS: `*,
body {
margin: 0;
Expand Down Expand Up @@ -311,7 +317,43 @@ func SetRenderRoute(e *echo.Echo, publicPath string) {

body[data-theme='dark'] a {
color: #8098f9;
}`,
}

body[data-theme='light-background'] {
background-color: #f8fafc;
color: #121416;
}

body[data-theme='light-background']a {
color: #444ce7;
}

body[data-theme='dark-background'] {
background-color: #141414;
color: #f8fafc;
}
body[data-theme='dark-background'] a {
color: #8098f9;
}

body[data-theme='light-primary'] {
background-color: #fff;
color: #121416;
}
body[data-theme='light-primary']a {
color: #444ce7;
}

body[data-theme='dark-primary'] {
background-color: #000;
color: #f8fafc;
}

body[data-theme='dark-primary']a {
color: #8098f9;
}
`,

}

// Set headers
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/bottom-nav-links.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

{#if open}
<div
class="flex h-full flex-col flex-col-reverse justify-start gap-6 overflow-auto px-4 py-8"
class="flex h-full flex-col-reverse justify-start gap-6 overflow-auto px-4 py-8"
>
{#each linkList as item}
{#if item.divider}
Expand Down
42 changes: 42 additions & 0 deletions src/lib/components/workflow/metadata/metadata-events.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script lang="ts">
import MetadataDecoder from '$lib/components/event/metadata-decoder.svelte';
import WorkflowStatus from '$lib/components/workflow-status.svelte';
import { translate } from '$lib/i18n/translate';
import { groupEvents } from '$lib/models/event-groups';
import { fullEventHistory } from '$lib/stores/events';
import { workflowRun } from '$lib/stores/workflow-run';
const { workflow } = $derived($workflowRun);
const metadataGroups = $derived(
groupEvents(
$fullEventHistory,
'ascending',
workflow?.pendingActivities,
workflow?.pendingNexusOperations,
).filter((group) => group.userMetadata?.summary),
);
</script>

{#if !metadataGroups.length}
<div class="px-6 text-secondary/70">
<p class="text-sm italic">No events with metadata</p>
</div>
{/if}
<div class="flex flex-col gap-2">
{#each metadataGroups as group}
<div
class="flex items-center justify-between gap-4 border-b border-subtle px-3 pb-1 text-lg"
>
<div class="flex items-center gap-2">
<p class="w-32 min-w-32 text-sm font-medium">{group.label}</p>
<MetadataDecoder
value={group.userMetadata.summary}
fallback={translate('events.decode-failed')}
let:decodedValue
>
<span class="text-sm">{decodedValue}</span>
</MetadataDecoder>
</div>
<WorkflowStatus status={group.finalClassification} />
</div>
{/each}
</div>
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
<script lang="ts">
import { page } from '$app/stores';
import { onMount } from 'svelte';
import { page } from '$app/state';
import AccordionLight from '$lib/holocene/accordion/accordion-light.svelte';
import Button from '$lib/holocene/button.svelte';
import Icon from '$lib/holocene/icon/icon.svelte';
import Markdown from '$lib/holocene/monaco/markdown.svelte';
import Tooltip from '$lib/holocene/tooltip.svelte';
import { translate } from '$lib/i18n/translate';
import { getWorkflowMetadata } from '$lib/services/query-service';
import { authUser } from '$lib/stores/auth-user';
import { workflowRun } from '$lib/stores/workflow-run';
$: ({ namespace } = $page.params);
$: ({ workflow } = $workflowRun);
$: currentDetails = $workflowRun?.metadata?.currentDetails || '';
$: closedWithoutDetails = !workflow.isRunning && !currentDetails;
const { namespace } = $derived(page.params);
const { workflow } = $derived($workflowRun);
const currentDetails = $derived($workflowRun?.metadata?.currentDetails || '');
let loading = false;
let loading = $state(false);
let lastFetched = $state<Date | null>(null);
const fetchCurrentDetails = async () => {
if (loading) return;
loading = true;
try {
const { settings } = $page.data;
const { settings } = page.data;
const metadata = await getWorkflowMetadata(
{
namespace,
Expand All @@ -35,40 +36,63 @@
$authUser?.accessToken,
);
$workflowRun.metadata = metadata;
lastFetched = new Date();
} catch (error) {
console.error('Error fetching current details:', error);
} finally {
loading = false;
}
};
onMount(() => {
fetchCurrentDetails();
});
const handleKeydown = (event) => {
if (event.key === 'r' || event.key === 'R') {
event.preventDefault();
fetchCurrentDetails();
}
};
</script>

<AccordionLight
let:open
onToggle={closedWithoutDetails ? fetchCurrentDetails : undefined}
icon={closedWithoutDetails ? 'retry' : undefined}
>
<div slot="title" class="flex w-full items-center gap-2 p-2 text-xl">
<Icon name="flag" class="text-brand" width={32} height={32} />
{translate('workflows.current-details')}
{#if loading}{translate('common.loading')}{/if}
<svelte:window onkeydown={handleKeydown} />

<div class="flex h-full flex-1 flex-col border-l border-subtle">
<div class="surface-information w-full px-6 py-2">
<div class="flex items-center justify-between">
<h3>{translate('workflows.current-details')}</h3>
<div class="flex flex-row items-center gap-2 lg:flex-col xl:flex-row">
<p class="hidden sm:block">
Press the <span
class="mx-1 rounded bg-subtle px-1 text-sm font-medium leading-4"
>R</span
> for freshness
</p>
<div class="flex items-center sm:hidden">
<p>Press for freshness</p>
<Button
variant="ghost"
on:click={fetchCurrentDetails}
disabled={loading}
>
<Icon name="retry" />
</Button>
</div>
{#if lastFetched}
<p class="text-xs text-secondary">
{lastFetched.toLocaleTimeString()}
</p>
{/if}
</div>
</div>
</div>
{#if open}
<div class="surface-background h-full">
{#key currentDetails}
<Markdown content={currentDetails} />
<Markdown
className="p-3"
overrideTheme="background"
content={currentDetails}
/>
{/key}
{/if}
<svelte:fragment slot="action">
{#if workflow.isRunning}
<Tooltip text={translate('workflows.update-details')} left>
<Button
variant="ghost"
on:click={fetchCurrentDetails}
disabled={loading}
>
<Icon name="retry" />
</Button>
</Tooltip>
{/if}
</svelte:fragment>
</AccordionLight>
</div>
</div>
25 changes: 25 additions & 0 deletions src/lib/components/workflow/metadata/workflow-memo.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<script lang="ts">
import PayloadDecoder from '$lib/components/event/payload-decoder.svelte';
import CodeBlock from '$lib/holocene/code-block.svelte';
import { translate } from '$lib/i18n/translate';
import { workflowRun } from '$lib/stores/workflow-run';

const { workflow } = $derived($workflowRun);
</script>

<div class="mt-4 flex flex-col gap-2">
<h3>{translate('common.memo')}</h3>
{#if workflow?.memo}
<PayloadDecoder value={{ memo: workflow.memo }} key="memo">
{#snippet children(decodedValue)}
<CodeBlock
content={decodedValue}
copyIconTitle={translate('common.copy-icon-title')}
copySuccessIconTitle={translate('common.copy-success-icon-title')}
/>
{/snippet}
</PayloadDecoder>
{:else}
<p>{translate('events.empty-memo-attributes')}</p>
{/if}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<script lang="ts">
import PayloadDecoder from '$lib/components/event/payload-decoder.svelte';
import CodeBlock from '$lib/holocene/code-block.svelte';
import { translate } from '$lib/i18n/translate';
import { workflowRun } from '$lib/stores/workflow-run';

const { workflow } = $derived($workflowRun);
</script>

<div class="mt-4 flex flex-col gap-2">
<h3>
{translate('events.attribute-group.search-attributes')}
</h3>
{#if workflow?.searchAttributes}
<PayloadDecoder
value={{ searchAttributes: workflow.searchAttributes }}
key="searchAttributes"
>
{#snippet children(decodedValue)}
<CodeBlock
content={decodedValue}
copyIconTitle={translate('common.copy-icon-title')}
copySuccessIconTitle={translate('common.copy-success-icon-title')}
/>
{/snippet}
</PayloadDecoder>
{:else}
<p>{translate('events.empty-search-attributes')}</p>
{/if}
</div>
Original file line number Diff line number Diff line change
@@ -1,29 +1,53 @@
<script lang="ts">
import AccordionLight from '$lib/holocene/accordion/accordion-light.svelte';
import Icon from '$lib/holocene/icon/icon.svelte';
import Markdown from '$lib/holocene/monaco/markdown.svelte';
import { translate } from '$lib/i18n/translate';
import { workflowRun } from '$lib/stores/workflow-run';

$: summary = $workflowRun?.userMetadata?.summary;
$: details = $workflowRun?.userMetadata?.details;
$: hasUserMetadata = summary || details;
import MetadataEvents from './metadata-events.svelte';

const summary = $derived($workflowRun?.userMetadata?.summary);
const details = $derived($workflowRun?.userMetadata?.details);
</script>

{#if hasUserMetadata}
<AccordionLight let:open>
<div slot="title" class="flex w-full items-center gap-2 p-2 text-xl">
<Icon name="info" class="text-brand" width={32} height={32} />{translate(
'workflows.summary-and-details',
)}
<div class="flex h-full flex-1 flex-col bg-primary">
<div>
<div class="surface-information w-full px-6 py-2">
<h3 data-testid="user-metadata-summary-heading">
{translate('workflows.summary')}
</h3>
</div>
{#if open && summary}
<h3>{translate('workflows.summary')}</h3>
<Markdown content={summary} />
{#if summary}
<Markdown className="p-3" overrideTheme="primary" content={summary} />
{:else}
<div class="py-6 pl-6 text-secondary/70">
<p class="text-sm italic">
{translate('workflows.no-summary-available')}
</p>
</div>
{/if}
{#if open && details}
<h3>{translate('workflows.details')}</h3>
<Markdown content={details} />
</div>
<div>
<div class="surface-information w-full px-6 py-2">
<h3 data-testid="user-metadata-summary-heading">
{translate('workflows.details')}
</h3>
</div>
{#if details}
<Markdown className="p-3" overrideTheme="primary" content={details} />
{:else}
<div class="py-6 pl-6 text-secondary/70">
<p class="text-sm italic">
{translate('workflows.no-details-available')}
</p>
</div>
{/if}
</AccordionLight>
{/if}
</div>
<div>
<div class="surface-information w-full px-6 py-2">
<h3 data-testid="user-metadata-summary-heading">Events with Metadata</h3>
</div>
<div class="py-6">
<MetadataEvents />
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script>
import WorkflowCurrentDetails from '$lib/components/workflow/metadata/workflow-current-details.svelte';
import WorkflowSummaryAndDetails from '$lib/components/workflow/metadata/workflow-summary-and-details.svelte';
</script>

<div class="flex flex-col bg-primary lg:flex-row">
<WorkflowSummaryAndDetails />
<WorkflowCurrentDetails />
</div>
4 changes: 1 addition & 3 deletions src/lib/holocene/empty-state.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
class="my-12 flex w-full flex-col items-center justify-start gap-2 text-primary {$$props.class}"
data-testid={$$props.testId}
>
<span
class="surface-secondary flex h-16 w-16 items-center justify-center rounded-full"
>
<span class=" flex h-16 w-16 items-center justify-center rounded-full">
<Icon name={icon} class="block h-full w-full" /></span
>
<p class="text-xl font-medium">{title}</p>
Expand Down
Loading
Loading