Skip to content
Open
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
b3f5e95
Testing out api
Alex-Tideman Oct 10, 2025
6f1b4d2
Add worker-info component
Alex-Tideman Dec 5, 2025
2b15a34
Add worker-info to Workers tab
Alex-Tideman Dec 5, 2025
e992c50
Add worker-table if new api fails
Alex-Tideman Dec 5, 2025
1dfd237
Add workers list page
Alex-Tideman Dec 8, 2025
1eadb99
Make filterable a prop
Alex-Tideman Dec 8, 2025
96bddae
Merge branch 'main' into worker-insights
Alex-Tideman Jan 12, 2026
567aa2d
Refactor workers page to designs
Alex-Tideman Jan 12, 2026
48ef22a
New worker nav items
Alex-Tideman Feb 5, 2026
89985d6
Dont use url params
Alex-Tideman Feb 5, 2026
9e3f91f
Fix merge conflicts
Alex-Tideman Feb 5, 2026
89675ee
Merge branch 'main' into worker-insights
laurakwhit Feb 20, 2026
722bd81
Clean up types and remove Shutdown status
laurakwhit Feb 21, 2026
213c0e3
Merge branch 'main' into worker-insights
laurakwhit Feb 24, 2026
01bf37b
Merge branch 'main' into worker-insights
laurakwhit Feb 25, 2026
618b9c3
Merge branch 'main' into worker-insights
laurakwhit Feb 27, 2026
5fbbbc4
Merge branch 'main' into worker-insights
laurakwhit Mar 3, 2026
004bf4d
Small fixes and improvements
laurakwhit Mar 4, 2026
cddca19
Add filtering to workers table
laurakwhit Mar 4, 2026
cb9bda3
Update no workers polling alert
laurakwhit Mar 5, 2026
abd41a2
Worker details page updates
laurakwhit Mar 6, 2026
ddb1637
Add Go dependency warning for usage stats
laurakwhit Mar 6, 2026
feab31c
Add poll success rate
laurakwhit Mar 13, 2026
57d319b
Merge branch 'main' into worker-insights
laurakwhit Mar 13, 2026
081e4e4
Update nav to workers
laurakwhit Mar 13, 2026
b3d2ce1
Fix type and test
laurakwhit Mar 13, 2026
657db82
Routing, page, and component updates
laurakwhit Mar 14, 2026
42a6a41
UI and accesibility updates
laurakwhit Mar 16, 2026
5d18478
Hide/show alerts
laurakwhit Mar 17, 2026
3588500
Fix strict errors
laurakwhit Mar 18, 2026
871a4d9
Fix routes when switching Namespaces
laurakwhit Mar 18, 2026
9ef56c7
Small fixes
laurakwhit Mar 19, 2026
fc1d01d
Merge branch 'main' into worker-insights
laurakwhit Mar 19, 2026
38e0f61
Add useFallback prop for workers tables
laurakwhit Mar 19, 2026
5d06873
Merge branch 'main' into worker-insights
laurakwhit Mar 25, 2026
52f3f59
Filter updates
laurakwhit Mar 25, 2026
aa6de43
Don't include null conditions in workers filters
laurakwhit Mar 26, 2026
1bec9b3
Update empty states and other fixes
laurakwhit Mar 26, 2026
067fff0
Merge branch 'main' into worker-insights
laurakwhit Mar 26, 2026
db0c481
Make task queue a filter in standalone activity details
laurakwhit Mar 26, 2026
2e9268b
Add worker integration tests
laurakwhit Mar 27, 2026
fa65d19
Add tooltip copy for slot supplier kind and autoscaling badges
laurakwhit Mar 27, 2026
9fbba25
Update todo comments
laurakwhit Apr 2, 2026
cd16d59
Merge branch 'main' into worker-insights
laurakwhit Apr 2, 2026
ed0d9e6
Pass hrefs to workers layout
laurakwhit Apr 2, 2026
d45a808
Add version check to SDK warning
laurakwhit Apr 2, 2026
047c35c
UI updates from bug bash
laurakwhit Apr 3, 2026
eb330be
Add outdated worker data alert with refresh
laurakwhit Apr 3, 2026
6c1a324
Merge branch 'main' into worker-insights
laurakwhit Apr 3, 2026
cd8d13a
Remove diagnostics section and add workflow cache link
laurakwhit Apr 6, 2026
525e8d0
UI updates
laurakwhit Apr 7, 2026
517b5a3
Merge branch 'main' into worker-insights
laurakwhit Apr 7, 2026
9f73651
Remove LastHeartbeatTime from supported worker search attributes
laurakwhit Apr 7, 2026
3950fff
Set h-dvh for main layout
laurakwhit Apr 7, 2026
9dfe04c
Use new workers field on ListWorkersResponse if it exists
laurakwhit Apr 8, 2026
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ go.work.sum
.claude/*
!.claude/skills/
.sisyphus/*
.omc
.omc
54 changes: 25 additions & 29 deletions src/lib/components/lines-and-dots/workflow-details.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { translate } from '$lib/i18n/translate';
import { fetchWorkflow } from '$lib/services/workflow-service';
import { isCloud } from '$lib/stores/advanced-visibility';
import { fullEventHistory } from '$lib/stores/events';
import { fullEventHistory, sdkInfo } from '$lib/stores/events';
import {
relativeTime,
timeFormat,
Expand All @@ -19,8 +19,6 @@
formatDuration,
} from '$lib/utilities/format-time';
import { getBuildIdFromVersion } from '$lib/utilities/get-deployment-build-id';
import { getSDKandVersion } from '$lib/utilities/get-sdk-version';
import { isWorkflowTaskCompletedEvent } from '$lib/utilities/is-event-type';
import {
routeForSchedule,
routeForTaskQueue,
Expand Down Expand Up @@ -81,16 +79,12 @@
],
);
let totalActions = $derived(
$fullEventHistory.reduce((acc, e) => e.billableActions + acc, 0).toString(),
$fullEventHistory
.reduce((acc, e) => (e?.billableActions ?? 0) + acc, 0)
.toString(),
);

const workflowCompletedTasks = $derived(
$fullEventHistory.filter(isWorkflowTaskCompletedEvent),
);

const { sdk, version: sdkVersion } = $derived(
getSDKandVersion(workflowCompletedTasks),
);
const { sdk, version: sdkVersion } = $derived($sdkInfo);

const fetchLatestRun = async () => {
const result = await fetchWorkflow({
Expand Down Expand Up @@ -166,18 +160,20 @@
href={routeForWorkflowsWithQuery({
namespace,
query: `WorkflowType="${workflow?.name}"`,
})}
}) ?? ''}
iconName="filter"
/>

<DetailListLabel>{translate('common.task-queue')}</DetailListLabel>
<DetailListLinkValue
text={workflow?.taskQueue}
href={routeForTaskQueue({
namespace,
queue: workflow?.taskQueue,
})}
/>
{#if workflow?.taskQueue}
<DetailListLabel>{translate('common.task-queue')}</DetailListLabel>
<DetailListLinkValue
text={workflow.taskQueue}
href={routeForTaskQueue({
namespace,
queue: workflow.taskQueue,
})}
/>
{/if}

{#if workflow?.priority}
{@const { priorityKey, fairnessKey } = workflow.priority}
Expand Down Expand Up @@ -214,11 +210,11 @@
copyableText={versioningBuildId}
text={versioningBuildId}
href={deploymentVersion
? routeForWorkflowsWithQuery({
? (routeForWorkflowsWithQuery({
namespace,
query: `TemporalWorkerDeploymentVersion="${deploymentVersion}"`,
})
: undefined}
}) ?? '')
: ''}
iconName={deploymentVersion ? 'filter' : undefined}
/>
{/if}
Expand All @@ -234,7 +230,7 @@
href={routeForWorkflowsWithQuery({
namespace,
query: `TemporalWorkflowVersioningBehavior="${versioningBehavior}"`,
})}
}) ?? ''}
iconName="filter"
/>
{/if}
Expand All @@ -252,15 +248,15 @@
})}
/>
{/if}
{#if parent}
{#if parent?.workflowId && parent?.runId}
<DetailListLabel>{translate('workflows.parent-workflow')}</DetailListLabel
>
<DetailListLinkValue
text={parent?.workflowId}
text={parent.workflowId}
href={routeForWorkflow({
namespace,
workflow: parent?.workflowId,
run: parent?.runId,
workflow: parent.workflowId,
run: parent.runId,
})}
/>
{/if}
Expand Down Expand Up @@ -305,7 +301,7 @@
{/if}

{#if sdk && sdkVersion}
<DetailListLabel>SDK</DetailListLabel>
<DetailListLabel>{translate('workflows.sdk')}</DetailListLabel>
<DetailListValue>
<SdkLogo {sdk} version={sdkVersion} />
</DetailListValue>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<script lang="ts">
import type { Writable } from 'svelte/store';

import Button from '$lib/holocene/button.svelte';
import Icon from '$lib/holocene/icon/icon.svelte';
import Tooltip from '$lib/holocene/tooltip.svelte';
import type { SearchAttributeFilter } from '$lib/models/search-attribute-filters';
import type { SearchAttributeOption } from '$lib/stores/search-attributes';

import type { StatusAttribute } from './types.ts';

import Filter from './filter.svelte';
import ManualQuery from './manual-query.svelte';

interface Props {
filters: Writable<SearchAttributeFilter[]>;
options: SearchAttributeOption[];
id: string;
statusAttribute?: StatusAttribute;
onManualSearch?: (query: string) => void;
}

let { filters, options, id, statusAttribute, onManualSearch }: Props =
$props();

let viewManualQuery = $state(false);
</script>

<div>
<div
class="flex w-full flex-wrap items-center justify-between gap-2 border border-subtle bg-primary p-1.5"
>
<div class="flex grow items-center justify-start gap-4 px-2">
<Icon name="filter-lines" class="text-primary-text h-4 w-4 shrink-0" />
<Filter {filters} {options} {id} {statusAttribute} />
</div>
<div class="flex items-center gap-1">
<Tooltip
text={viewManualQuery ? 'Hide raw query' : 'View raw query'}
left
>
<Button
variant="ghost"
size="xs"
leadingIcon="json"
active={viewManualQuery}
data-testid="toggle-manual-query"
on:click={() => (viewManualQuery = !viewManualQuery)}
/>
</Tooltip>
</div>
</div>
{#if viewManualQuery}
<ManualQuery {filters} {id} onSearch={onManualSearch} />
{/if}
</div>
131 changes: 131 additions & 0 deletions src/lib/components/shared-search-attribute-filter/filter-list.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<script lang="ts">
import type { Writable } from 'svelte/store';

import { getContext } from 'svelte';

import { page } from '$app/state';

import DropdownFilterChip from '$lib/components/workflow/filter-bar/dropdown-filter-chip.svelte';
import Button from '$lib/holocene/button.svelte';
import { translate } from '$lib/i18n/translate';
import type { SearchAttributeFilter } from '$lib/models/search-attribute-filters';
import { createFilter } from '$lib/utilities/query/to-list-workflow-filters';
import { updateQueryParamsFromFilter } from '$lib/utilities/query/to-list-workflow-filters';

import type { StatusAttribute } from './types.ts';

import {
SEARCH_ATTRIBUTE_FILTER_CONTEXT,
type SearchAttributeFilterContext,
} from './filter.svelte';
import StatusFilterChip from './status-filter-chip.svelte';

interface Props {
filters: Writable<SearchAttributeFilter[]>;
statusAttribute?: StatusAttribute;
}

let { filters, statusAttribute }: Props = $props();

const isStatusFilter = (f: SearchAttributeFilter) =>
statusAttribute ? f.attribute === statusAttribute : false;

const { filter, activeQueryIndex, chipOpenIndex } =
getContext<SearchAttributeFilterContext>(SEARCH_ATTRIBUTE_FILTER_CONTEXT);

let totalFiltersInView = $state(10);

const firstExecutionStatusIndex = $derived(
$filters.findIndex((filter) => isStatusFilter(filter)),
);
const visibleFilters = $derived($filters.slice(0, totalFiltersInView));
const statusFilters = $derived(
statusAttribute
? $filters.filter((filter) => filter.attribute === statusAttribute)
: [],
);
const nonStatusFilters = $derived(
$filters.filter((filter) => !isStatusFilter(filter)),
);
const hasMoreFilters = $derived(totalFiltersInView < $filters.length);

function updateFilter(index: number, updatedFilter: SearchAttributeFilter) {
const next = [...$filters];
next[index] = updatedFilter;
$filters = next;
updateQueryParamsFromFilter(page.url, $filters);
}

function updateStatusFilters(
index: number,
updatedFilters: SearchAttributeFilter[],
) {
if (updatedFilters.length === 0) {
$filters = nonStatusFilters;
updateQueryParamsFromFilter(page.url, $filters);
} else {
const next = [...$filters];
next.splice(index, statusFilters.length, ...updatedFilters);
$filters = next;
updateQueryParamsFromFilter(page.url, $filters);
}
}

function removeFilter(index: number) {
const next = [...$filters];
next.splice(index, 1);
$filters = next;
updateQueryParamsFromFilter(page.url, $filters);

if (index === $filters.length && $filters.length > 0) {
const previousQuery = $filters[$filters.length - 1];
if (previousQuery) {
previousQuery.operator = '';
}
}

if (index === $activeQueryIndex) {
$activeQueryIndex = null;
$filter = createFilter();
} else if ($activeQueryIndex !== null && index < $activeQueryIndex) {
$activeQueryIndex -= 1;
}
}

function viewMoreFilters() {
if (hasMoreFilters) {
totalFiltersInView += 10;
}
}
</script>

{#if visibleFilters.length > 0}
<div class="flex flex-wrap items-center gap-2">
{#each visibleFilters as filterItem, i (filterItem.id)}
{#if statusAttribute && isStatusFilter(filterItem) && i === firstExecutionStatusIndex}
<StatusFilterChip
attribute={statusAttribute}
filters={statusFilters}
index={i}
openIndex={$chipOpenIndex}
onUpdate={(updatedStatusFilters) =>
updateStatusFilters(i, updatedStatusFilters)}
/>
{:else if !isStatusFilter(filterItem) && filterItem.attribute}
<DropdownFilterChip
filter={filterItem}
index={i}
openIndex={$chipOpenIndex}
onUpdate={(updatedFilter) => updateFilter(i, updatedFilter)}
onRemove={() => removeFilter(i)}
/>
{/if}
{/each}

{#if hasMoreFilters}
<Button variant="secondary" size="xs" on:click={viewMoreFilters}>
{translate('common.view-more')}
</Button>
{/if}
</div>
{/if}
Loading
Loading