-
Notifications
You must be signed in to change notification settings - Fork 129
DT-3523 - standalone activities UI #3124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
* WIP - start standalone activity * change routes, add duration input, fix imports * use queryparams for initial form values * clean up - update go api module - clean up api routes - add placeholder page for activity execution details - add support for query params to pre-fill form * add page components * add integration tests
* standalone activity details * decode and refactor * clean up * clean up * add page titles * add default param * remove pause, update and reset buttons * fix pnpm lock * add error state * increase toast duration
* Add standalone activities UI * Upgrade to svelte5 * Don't allow onclick on button until we migrate it to Svelte5 * Remove batch functionality * Fix up some table stuff * Add filterable/copiable cells * Add Start Activity Like this One
* add terminate and cancel to activity details page * update api
* design scrub * fix i18n * rename and reorganize * fix poller
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
| loading = true; | ||
| try { | ||
| const { count, groups } = await fetchActivityCountByStatus({ | ||
| namespace, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ Type 'string | null' is not assignable to type 'string'.
| query, | ||
| }).catch((_e) => { | ||
| return { count: '0', groups: [] }; | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
| }).catch((_e) => { | ||
| return { count: '0', groups: [] }; | ||
| }); | ||
| $activityCount.count = parseInt(count); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ Argument of type 'never[] | { count: string; groupValues: IPayloads; }[] | undefined' is not assignable to parameter of type 'never[] | undefined'.
| const fetchNewCounts = async () => { | ||
| try { | ||
| const { count, groups } = await fetchActivityCountByStatus({ | ||
| namespace, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ Type 'string | null' is not assignable to type 'string'.
| query, | ||
| }).catch((_e) => { | ||
| return { count: '0', groups: [] }; | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
|
|
||
| this.onUpdate(activityExecution); | ||
|
|
||
| if (activityExecution.info.status === 'ACTIVITY_EXECUTION_STATUS_RUNNING') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ 'activityExecution' is possibly 'undefined'.
| this.onUpdate(activityExecution); | ||
|
|
||
| if (activityExecution.info.status === 'ACTIVITY_EXECUTION_STATUS_RUNNING') { | ||
| this.runId = activityExecution.runId; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ 'activityExecution' is possibly 'undefined'.⚠️ Type 'string | undefined' is not assignable to type 'string'.
| if ( | ||
| polledActivityExecution && | ||
| !isEmptyObject(polledActivityExecution) | ||
| ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ Type 'string | undefined' is not assignable to type 'string'.
| if (error instanceof Error && error.name === 'AbortError') { | ||
| return; | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ Argument of type 'unknown' is not assignable to parameter of type 'Error'.
| <ErrorComponent {error} /> | ||
| {:else} | ||
| <StandaloneActivityLayout | ||
| {poller} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ Type 'ActivityExecution | undefined' is not assignable to type 'ActivityExecution'.
| disabled={!isRunning} | ||
| size="sm" | ||
| > | ||
| {translate('standalone-activities.request-cancellation')} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| disabled={!isRunning} | ||
| data-testid="terminate-button" | ||
| > | ||
| {translate('standalone-activities.terminate')} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| </script> | ||
|
|
||
| <div class="flex shrink flex-wrap items-center justify-start gap-2"> | ||
| <ActivityDropdownFilterList /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| {#each systemActivityViews as view} | ||
| {@render queryButton({ | ||
| ...view, | ||
| active: query === view.query, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| > | ||
| <h5>{translate('standalone-activities.form-timeouts-heading')}</h5> | ||
|
|
||
| <DurationInput |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| {:else if label === 'Close Time'} | ||
| <Timestamp dateTime={activity.closeTime} /> | ||
| {:else if label === 'Execution Duration'} | ||
| {#if activity.executionDuration} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| </td> | ||
| {/if} | ||
|
|
||
| <style lang="postcss"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: Maybe we can avoid adding more postcss if possible 🙏
| goto( | ||
| routeForStartStandaloneActivity({ | ||
| namespace, | ||
| activityId: activityExecutionInfo.activityId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ Type 'string | null | undefined' is not assignable to type 'string | undefined'.
| <DetailListLabel>Activity Type</DetailListLabel> | ||
| <DetailListLinkValue | ||
| copyable | ||
| iconName="filter" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ Type 'string | null | undefined' is not assignable to type 'string'.
server/go.mod
Outdated
| github.com/stretchr/testify v1.10.0 | ||
| github.com/urfave/cli/v2 v2.3.0 | ||
| go.temporal.io/api v1.57.0 | ||
| go.temporal.io/api v1.61.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we bump this to the latest v1.62.0?
| const handleCopy = (e: Event) => { | ||
| const sharableViewUrl = | ||
| new URL(page.url.href) + | ||
| '&savedQuery=' + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ Argument of type 'string | undefined' is not assignable to parameter of type 'string | number | boolean'.
| <RetryPolicyInput | ||
| bind:initialInterval={$form.initialInterval} | ||
| bind:backoffCoefficient={$form.backoffCoefficient} | ||
| bind:maximumInterval={$form.maximumInterval} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ Type 'undefined' is not assignable to type 'string'.
|
|
||
| if (index === $activeQueryIndex) { | ||
| $activeQueryIndex = null; | ||
| $filter = emptyFilter(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ '$activeQueryIndex' is possibly 'null'.
| if (index === $activeQueryIndex) { | ||
| $activeQueryIndex = null; | ||
| $filter = emptyFilter(); | ||
| } else if (index < $activeQueryIndex) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ '$activeQueryIndex' is possibly 'null'.
| {#if isStatusFilter(activityFilter) && i === firstExecutionStatusIndex} | ||
| <StatusDropdownFilterChip | ||
| filters={executionStatusFilters} | ||
| index={i} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ Type 'number | null' is not assignable to type 'number | undefined'.
| {:else if !isStatusFilter(activityFilter) && activityFilter.attribute} | ||
| <DropdownFilterChip | ||
| filter={activityFilter} | ||
| index={i} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ Type 'number | null' is not assignable to type 'number | undefined'.
src/lib/components/standalone-activities/start-standalone-activity-form/form.svelte
Show resolved
Hide resolved
src/lib/components/standalone-activities/start-standalone-activity-form/form.svelte
Show resolved
Hide resolved
src/lib/components/standalone-activities/start-standalone-activity-form/form.svelte
Show resolved
Hide resolved
| let refreshTime = $state(new Date()); | ||
|
|
||
| const refreshTimeFormatted = $derived( | ||
| formatDate(refreshTime, $timeFormat, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change request: If you use the $timestamp store, this'll be reactive for 12/24 hour format change to.
| } | ||
| }); | ||
|
|
||
| $effect(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ Type 'string | null' is not assignable to type 'string'.
andrewzamojc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried out the branch locally and was able to start/stop a standalone activity and view its details. The decoding steps in the PR worked too. Looking pretty good to me 👍










Description & motivation 💭
Screenshots (if applicable) 📸
Design Considerations 🎨
Testing 🧪
How was this tested 👻
Steps for others to test: 🚶🏽♂️🚶🏽♀️
Run temporal server from a local build
make binsandmake startdefaultnamespace, runtemporal operator namespace create --namespace defaultdefaultnamespace, runtemporal operator search-attribute create --namespace default --name MySearchAttribute --type KeywordRun the UI against a local build of temporal server
standalone-activitiesbranch in the ui repocd server/ && make buildcd .. && pnpm dev:local-temporalRun some sample workflows in the samples-go repo
cd temporal-fixtures/stuck-workflows/go run worker/main.gogo run starter/main.goStart a Standalone Activity
stuck-workflowsStuckWorkflowActivityStart to Close Timeoutfield with some long duration,1 hourfor examplehttp://localhost:3000/namespaces/default/activities/<activity_id>/detailsTo test Activities with Payloads + Codec Server
In the
samples-gorepo:cd codec-servergo run ./codec-server -web=http://localhost:3000 -port=8088go run worker/main.gogo run starter/main.goIn the UI
http://localhost:8088codecserverActivityhttp://localhost:3000/namespaces/default/activities/<activity_id>/detailsand ensure payloads are being decoded.Checklists
Draft Checklist
Merge Checklist
Issue(s) closed
Docs
Any docs updates needed?