Skip to content

Commit 68208be

Browse files
Worker Versioning (#2576)
* Bump api version, add new page for deployments. WIP * More setup, add individual deployment page. WIP * Finish deployment and deployment version pages * Add trending icon * Return real data * Add Deployment columns to workflow list, add drained/inactive icons, add deployment details in workflow header * Remove search for now, better colors, add deployment column * Remove deployment details * Update snapshots * Update src/lib/pages/deployments.svelte Co-authored-by: Laura Whitaker <laura.whitaker@temporal.io> * Update src/lib/pages/deployments.svelte Co-authored-by: Laura Whitaker <laura.whitaker@temporal.io> * Update src/lib/components/deployments/version-table-row.svelte Co-authored-by: Laura Whitaker <laura.whitaker@temporal.io> * Update src/lib/utilities/route-for.ts Co-authored-by: Laura Whitaker <laura.whitaker@temporal.io> * Update src/lib/components/deployments/version-table-row.svelte Co-authored-by: Laura Whitaker <laura.whitaker@temporal.io> * Fix route * Add back versioning tab for v2 versioning * Add link for versioning docs * Change link url * Remove description text * Change text --------- Co-authored-by: Laura Whitaker <laura.whitaker@temporal.io>
1 parent 63036f8 commit 68208be

32 files changed

Lines changed: 971 additions & 17 deletions
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<script lang="ts">
2+
import { cva } from 'class-variance-authority';
3+
4+
import type { IconName } from '$lib/holocene/icon';
5+
import Icon from '$lib/holocene/icon/icon.svelte';
6+
import type { DeploymentStatus } from '$lib/types/deployments';
7+
8+
export let status: DeploymentStatus;
9+
export let version: string;
10+
export let label: string;
11+
12+
const icon: Record<DeploymentStatus, IconName> = {
13+
Current: 'heartbeat',
14+
Ramping: 'trending-up',
15+
Draining: 'trending-down',
16+
Drained: 'drained',
17+
Inactive: 'inactive',
18+
};
19+
20+
const deploymentStatus = cva(
21+
[
22+
'flex items-center gap-1 rounded-sm border border-subtle px-1 transition-colors',
23+
],
24+
{
25+
variants: {
26+
status: {
27+
Ramping: 'text-cyan-600 dark:text-cyan-400',
28+
Current: 'text-blue-600 dark:text-blue-400',
29+
Draining: 'text-yellow-600 dark:text-yellow-200',
30+
Drained: 'text-secondary',
31+
Inactive: 'text-secondary',
32+
},
33+
},
34+
},
35+
);
36+
</script>
37+
38+
<p class="flex items-center gap-2">
39+
<span class="rounded-sm border border-subtle px-1">
40+
{version}
41+
</span>
42+
<span class={deploymentStatus({ status })}>
43+
<Icon name={icon[status]} />{label}</span
44+
>
45+
</p>
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<script lang="ts">
2+
import { page } from '$app/stores';
3+
4+
import Link from '$lib/holocene/link.svelte';
5+
import { translate } from '$lib/i18n/translate';
6+
import type { ConfigurableTableHeader } from '$lib/stores/configurable-table-columns';
7+
import { relativeTime, timeFormat } from '$lib/stores/time-format';
8+
import type { WorkerDeploymentSummary } from '$lib/types/deployments';
9+
import { formatDate } from '$lib/utilities/format-date';
10+
import {
11+
routeForWorkerDeployment,
12+
routeForWorkflowsWithQuery,
13+
} from '$lib/utilities/route-for';
14+
15+
import DeploymentStatus from './deployment-status.svelte';
16+
17+
export let deployment: WorkerDeploymentSummary;
18+
export let columns: ConfigurableTableHeader[];
19+
</script>
20+
21+
<tr>
22+
{#each columns as { label } (label)}
23+
{#if label === translate('deployments.name')}
24+
<td class="p-2 text-left"
25+
><Link
26+
href={routeForWorkerDeployment({
27+
namespace: $page.params.namespace,
28+
deployment: deployment.name,
29+
})}>{deployment.name}</Link
30+
></td
31+
>
32+
{:else if label === translate('deployments.deployment-version')}
33+
<td class="whitespace-pre-line break-words p-2 text-left">
34+
<div class="flex flex-col gap-1">
35+
{#if deployment.routingConfig.rampingVersion}
36+
<DeploymentStatus
37+
status="Ramping"
38+
version={deployment.routingConfig.rampingVersion}
39+
label={translate('deployments.ramping-percentage', {
40+
percentage: deployment.routingConfig.rampingVersionPercentage,
41+
})}
42+
/>
43+
{/if}
44+
<DeploymentStatus
45+
status="Current"
46+
version={deployment.routingConfig.currentVersion}
47+
label={translate('deployments.current')}
48+
/>
49+
</div>
50+
</td>
51+
{:else if label === translate('deployments.deployed')}
52+
<td class="truncate p-2 text-left">
53+
<div class="flex flex-col gap-1">
54+
{#if deployment.routingConfig.rampingVersionChangedTime}
55+
<p>
56+
{formatDate(
57+
deployment.routingConfig.rampingVersionChangedTime,
58+
$timeFormat,
59+
{
60+
relative: $relativeTime,
61+
},
62+
)}
63+
</p>
64+
{/if}
65+
<p>
66+
{formatDate(deployment.createTime, $timeFormat, {
67+
relative: $relativeTime,
68+
})}
69+
</p>
70+
</div>
71+
</td>
72+
{:else if label === translate('deployments.workflows')}
73+
<td class="truncate p-2 text-center"
74+
><p>
75+
<Link
76+
icon="external-link"
77+
href={routeForWorkflowsWithQuery({
78+
namespace: $page.params.namespace,
79+
query: `TemporalWorkerDeployment="${deployment.name}"`,
80+
})}
81+
/>
82+
</p></td
83+
>
84+
{/if}
85+
{/each}
86+
</tr>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<script lang="ts">
2+
import { translate } from '$lib/i18n/translate';
3+
import { relativeTime, timeFormat } from '$lib/stores/time-format';
4+
import type { WorkerDeploymentVersionInfo } from '$lib/types/deployments';
5+
import { formatDate } from '$lib/utilities/format-date';
6+
7+
import WorkflowDetail from '../lines-and-dots/workflow-detail.svelte';
8+
9+
export let version: WorkerDeploymentVersionInfo;
10+
</script>
11+
12+
<div class="flex w-full flex-col gap-2 lg:flex-row lg:gap-8 xl:gap-16">
13+
<div class="flex w-full flex-col gap-2 lg:w-1/3 xl:w-1/4">
14+
<WorkflowDetail
15+
title={translate('common.status')}
16+
content={version.drainageInfo.status}
17+
/>
18+
<WorkflowDetail
19+
title={translate('deployments.rollout-started')}
20+
content={formatDate(version.createTime, $timeFormat, {
21+
relative: $relativeTime,
22+
})}
23+
/>
24+
</div>
25+
<div class="flex w-full flex-col gap-2 lg:w-1/3 xl:w-1/4">
26+
<WorkflowDetail title={translate('deployments.rollout-id')} content="-" />
27+
<WorkflowDetail title={translate('deployments.rollout-url')} content="-" />
28+
</div>
29+
</div>
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<script lang="ts">
2+
import { page } from '$app/stores';
3+
4+
import Link from '$lib/holocene/link.svelte';
5+
import { translate } from '$lib/i18n/translate';
6+
import type { ConfigurableTableHeader } from '$lib/stores/configurable-table-columns';
7+
import { relativeTime, timeFormat } from '$lib/stores/time-format';
8+
import type { RoutingConfig, VersionSummary } from '$lib/types/deployments';
9+
import type { DeploymentStatus as Status } from '$lib/types/deployments';
10+
import { formatDate } from '$lib/utilities/format-date';
11+
import { routeForWorkflowsWithQuery } from '$lib/utilities/route-for';
12+
import { fromScreamingEnum } from '$lib/utilities/screaming-enums';
13+
14+
import DeploymentStatus from './deployment-status.svelte';
15+
16+
export let routingConfig: RoutingConfig;
17+
export let version: VersionSummary;
18+
export let columns: ConfigurableTableHeader[];
19+
20+
$: isCurrent = version.version === routingConfig.currentVersion;
21+
$: isRamping = version.version === routingConfig.rampingVersion;
22+
$: drainageStatus = version.drainageStatus;
23+
24+
$: status = (
25+
isCurrent
26+
? translate('deployments.current')
27+
: isRamping
28+
? translate('deployments.ramping')
29+
: drainageStatus
30+
? fromScreamingEnum(drainageStatus, 'VersionDrainageStatus')
31+
: translate('common.inactive')
32+
) as Status;
33+
34+
$: statusLabel = isCurrent
35+
? translate('deployments.current')
36+
: isRamping
37+
? translate('deployments.ramping', {
38+
percentage: routingConfig.rampingVersionPercentage,
39+
})
40+
: drainageStatus
41+
? fromScreamingEnum(drainageStatus, 'VersionDrainageStatus')
42+
: translate('common.inactive');
43+
</script>
44+
45+
<tr>
46+
{#each columns as { label } (label)}
47+
{#if label === translate('deployments.version')}
48+
<td class="p-2 text-left">
49+
<DeploymentStatus
50+
{status}
51+
version={version.version}
52+
label={statusLabel}
53+
/>
54+
</td>
55+
{:else if label === translate('deployments.deployed')}
56+
<td class="whitespace-pre-line break-words p-2 text-left"
57+
>{formatDate(version?.createTime, $timeFormat, {
58+
relative: $relativeTime,
59+
})}</td
60+
>
61+
{:else if label === translate('deployments.workflows')}
62+
<td class="whitespace-pre-line break-words p-2 text-center"
63+
><p>
64+
<Link
65+
icon="external-link"
66+
href={routeForWorkflowsWithQuery({
67+
namespace: $page.params.namespace,
68+
query: `TemporalWorkerDeploymentVersion="${version.version}"`,
69+
})}
70+
/>
71+
</p></td
72+
>
73+
{/if}
74+
{/each}
75+
</tr>

src/lib/components/lines-and-dots/workflow-details.svelte

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import { formatDate } from '$lib/utilities/format-date';
88
import { formatDistanceAbbreviated } from '$lib/utilities/format-time';
99
import {
10+
routeForWorkerDeployment,
1011
routeForWorkers,
1112
routeForWorkflow,
1213
routeForWorkflowsWithQuery,
@@ -23,10 +24,26 @@
2324
end: workflow?.endTime || Date.now(),
2425
includeMilliseconds: true,
2526
});
27+
$: deployment =
28+
workflow?.searchAttributes?.indexedFields?.['TemporalWorkerDeployment'];
29+
$: deploymentVersion =
30+
workflow?.searchAttributes?.indexedFields?.[
31+
'TemporalWorkerDeploymentVersion'
32+
];
33+
$: deploymentBehavior =
34+
workflow?.searchAttributes?.indexedFields?.[
35+
'TemporalWorkflowVersioningBehavior'
36+
];
2637
</script>
2738

28-
<div class="flex w-full flex-col gap-2 xl:flex-row xl:gap-16">
29-
<div class="flex w-full flex-col gap-2 xl:w-1/3">
39+
<div
40+
class="flex w-full flex-col gap-2 {deployment
41+
? '2xl:flex-row 2xl:gap-8'
42+
: 'xl:flex-row xl:gap-8'}"
43+
>
44+
<div
45+
class="flex w-full flex-col gap-2 {deployment ? '2xl:w-1/4' : 'xl:w-1/3'}"
46+
>
3047
<WorkflowDetail
3148
title={translate('common.start')}
3249
tooltip={$relativeTime
@@ -57,7 +74,9 @@
5774
/>
5875
<WorkflowDetail content={elapsedTime} icon="clock" />
5976
</div>
60-
<div class="flex w-full flex-col gap-2 xl:w-1/3">
77+
<div
78+
class="flex w-full flex-col gap-2 {deployment ? '2xl:w-1/4' : 'xl:w-1/3'}"
79+
>
6180
<WorkflowDetail
6281
title={translate('common.run-id')}
6382
content={workflow?.runId}
@@ -83,7 +102,35 @@
83102
})}
84103
/>
85104
</div>
86-
<div class="flex w-full flex-col gap-2 xl:w-1/3">
105+
{#if deployment}
106+
<div class="flex w-full flex-col gap-2 2xl:w-1/4">
107+
<WorkflowDetail
108+
title={translate('deployments.deployment')}
109+
content={deployment}
110+
href={routeForWorkerDeployment({
111+
namespace,
112+
deployment,
113+
})}
114+
/>
115+
{#if deploymentVersion}
116+
<WorkflowDetail
117+
title={translate('deployments.deployment-version')}
118+
content={workflow.searchAttributes.indexedFields[
119+
'TemporalWorkerDeploymentVersion'
120+
]}
121+
/>
122+
{/if}
123+
{#if deploymentBehavior}
124+
<WorkflowDetail
125+
title={translate('deployments.deployment-behavior')}
126+
content={deploymentBehavior}
127+
/>
128+
{/if}
129+
</div>
130+
{/if}
131+
<div
132+
class="flex w-full flex-col gap-2 {deployment ? '2xl:w-1/4' : 'xl:w-1/3'}"
133+
>
87134
{#if workflow?.parent}
88135
<WorkflowDetail
89136
title={translate('workflows.parent-workflow')}

src/lib/components/worker-table.svelte

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,18 @@
66
import Table from '$lib/holocene/table/table.svelte';
77
import { translate } from '$lib/i18n/translate';
88
import { type GetPollersResponse } from '$lib/services/pollers-service';
9+
import { isCloud } from '$lib/stores/advanced-visibility';
910
import { relativeTime, timeFormat } from '$lib/stores/time-format';
1011
import { formatDate } from '$lib/utilities/format-date';
1112
1213
import PollerIcon from './poller-icon.svelte';
1314
1415
export let workers: GetPollersResponse;
16+
17+
const getDeploymentName = (poller) => {
18+
const deployment = poller?.workerVersionCapabilities?.deploymentSeriesName;
19+
return deployment ?? '';
20+
};
1521
</script>
1622

1723
<h2 class="flex items-center gap-2" data-testid="workers">
@@ -25,6 +31,9 @@
2531
<TableHeaderRow slot="headers">
2632
<th class={'w-4/12'}>{translate('common.id')}</th>
2733
<th class={'w-3/12'}>{translate('workers.buildId')}</th>
34+
{#if !$isCloud}
35+
<th class={'w-3/12'}>{translate('deployments.deployment')}</th>
36+
{/if}
2837
<th class="w-2/12">{translate('workflows.last-accessed')}</th>
2938
<th class="w-2/12">
3039
<p class="text-center">
@@ -45,6 +54,14 @@
4554
{poller?.workerVersionCapabilities?.buildId ?? ''}
4655
</p>
4756
</td>
57+
{#if !$isCloud}
58+
{@const deployment = getDeploymentName(poller)}
59+
<td class="text-left" data-testid="worker-build-id">
60+
<p class="select-all break-all">
61+
{deployment ?? ''}
62+
</p>
63+
</td>
64+
{/if}
4865
<td class="text-left" data-testid="worker-last-access-time">
4966
<p class="select-all">
5067
{formatDate(poller.lastAccessTime, $timeFormat, {

src/lib/components/workflow/workflows-summary-configurable-table/table-body-cell.svelte

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,20 @@
113113
{content && typeof content === 'string'
114114
? formatDate(content, $timeFormat, { relative: $relativeTime })
115115
: ''}
116+
{:else if label === 'Deployment'}
117+
{@const content =
118+
workflow.searchAttributes?.indexedFields?.TemporalWorkerDeployment}
119+
{content && typeof content === 'string' ? content : ''}
120+
{:else if label === 'Deployment Version'}
121+
{@const content =
122+
workflow.searchAttributes?.indexedFields
123+
?.TemporalWorkerDeploymentVersion}
124+
{content && typeof content === 'string' ? content : ''}
125+
{:else if label === 'Versioning Behavior'}
126+
{@const content =
127+
workflow.searchAttributes?.indexedFields
128+
?.TemporalWorkflowVersioningBehavior}
129+
{content && typeof content === 'string' ? content : ''}
116130
{:else if isCustomSearchAttribute(label) && workflowIncludesSearchAttribute(workflow, label)}
117131
{@const content = workflow.searchAttributes.indexedFields[label]}
118132
{#if $customSearchAttributes[label] === SEARCH_ATTRIBUTE_TYPE.DATETIME && typeof content === 'string'}

0 commit comments

Comments
 (0)