refactor: replace PayloadDecoder and MetadataDecoder with unified Payload component#3299
Merged
Conversation
…load component Consolidates two divergent payload display components into a single `<Payload />` component at `src/lib/components/payload.svelte`. Previously, `payload-decoder.svelte` (Svelte 5 runes, required a `children` snippet, always decoded full attribute trees) and `metadata-decoder.svelte` (Svelte 4 options API with slot syntax, decoded single payloads to truncated summary strings) served different display purposes but used inconsistent APIs and decoding paths across 65+ call sites. The new component unifies both under a single `mode` prop: - `code-block` (default): renders a CodeBlock with the decoded value, replacing all PayloadDecoder + CodeBlock snippet patterns - `summary`: truncates to 120 chars and renders a Badge, replacing all MetadataDecoder usages - `inline-truncated`: renders the compact .payload pre block used in event detail rows - `children` snippet: escape hatch for callers that need custom rendering (schedule input, timeline SVG text elements) Both old components used a single decoding path internally (cloneAllPotentialPayloadsWithCodec -> decodePayloadAttributes -> stringifyWithBigInt). MetadataDecoder previously used a separate decodeSingleReadablePayloadWithCodec path; the new component uses the same unified path for consistency. The component is written in Svelte 5 runes throughout and imports from $app/state instead of $app/stores, matching the newer direction of the codebase. Migrated files: - src/lib/components/event/event-card.svelte - src/lib/components/event/event-details-row.svelte (+ moved .payload CSS) - src/lib/components/event/event-metadata-expanded.svelte - src/lib/components/event/event-summary-row.svelte - src/lib/components/lines-and-dots/svg/group-details-text.svelte - src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte - src/lib/components/schedule/schedule-form/schedule-input-payload.svelte - src/lib/components/standalone-activities/activity-input-and-outcome.svelte - src/lib/components/workflow/client-actions/update-confirmation-modal.svelte - src/lib/components/workflow/input-and-results-payload.svelte - src/lib/components/workflow/metadata/metadata-events.svelte - src/lib/components/workflow/pending-activity/pending-activity-card.svelte - src/lib/components/workflow/workflow-json-navigator.svelte - src/lib/pages/standalone-activity-details.svelte - src/lib/pages/standalone-activity-search-attributes.svelte - src/lib/pages/workflow-memo.svelte - src/lib/pages/workflow-metadata.svelte - src/lib/pages/workflow-search-attributes.svelte All 1730 tests pass.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| let success; | ||
| let error = $state(''); | ||
| let loading = $state(false); | ||
| let failure = $state< |
Contributor
There was a problem hiding this comment.
⚠️ Property 'failure' does not exist on type 'IOutcome | null | undefined'.
| let failure = $state< | ||
| UpdateWorkflowResponse['outcome']['failure'] | undefined | ||
| >(undefined); | ||
| let success = $state< |
Contributor
There was a problem hiding this comment.
⚠️ Property 'success' does not exist on type 'IOutcome | null | undefined'.
Contributor
|
Moves payload.svelte into src/lib/components/payload/ and adds a USAGE.md report documenting all 31 call sites grouped by feature area. Updates all 17 import paths accordingly.
… components Replace the 14-prop multi-mode payload.svelte with four single-purpose components: PayloadCodeBlock, PayloadSummary, PayloadDecoder, and PayloadInline. Each component carries only the props relevant to its render mode, eliminating dead props at call sites. Also updates the decode paths to use the renamed decode-payload.ts API (decodeEventAttributes, parsePayloadAttributes) following the #3302 cleanup.
Replace decodeEventAttributes with decodeUserMetadata — the correct decode path for a single raw Payload (Phase 2 codec only, no attribute tree walking). Also add onDecode callback prop, called after a successful decode, consistent with PayloadCodeBlock.
…lue utility Remove 3-way duplication of getInitialValue/onMount decode logic from payload-code-block, payload-decoder, and payload-inline by extracting getInitialPayloadValue and decodePayloadValue into src/lib/utilities/decode-payload-value.ts.
Components now re-decode when value or fieldName props change after mount, fixing the reactivity gap that caused stale decoded content when parent components updated their payload bindings.
laurakwhit
reviewed
May 12, 2026
Replace $effect+$state async pattern with $derived promise + $effect cleanup to ensure all reactive deps (value, fallback, prefix, maxSummaryLength) are tracked synchronously. Use $effect cleanup function to cancel stale promise callbacks on re-run, preventing race conditions when value changes rapidly. Remove unused onDecode prop.
|
|
||
| export const decodePayloadsAndParseDataToJSON = async ( | ||
| payloads: Payloads | null | undefined, | ||
| ): Promise<unknown[]> => { |
Contributor
There was a problem hiding this comment.
⚠️ Type 'null' is not assignable to type 'unknown[]'.
| export const decodePayloadsAndParseDataToJSON = async ( | ||
| payloads: Payloads | null | undefined, | ||
| ): Promise<unknown[]> => { | ||
| if (!payloads) return null; |
Contributor
There was a problem hiding this comment.
⚠️ Argument of type 'IPayload[] | null | undefined' is not assignable to parameter of type 'unknown[]'.
| return decoded?.[0] ?? clone; | ||
| } | ||
|
|
||
| for (const key of Object.keys(clone)) { |
Contributor
There was a problem hiding this comment.
⚠️ Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ payloads?: IPayload[] | null | undefined; } | { id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | ... 12 more ... | "CancelRequested"; ... 70 more ...; eventId: string; } | ... 61 more ... | { ...; }'.
laurakwhit
approved these changes
May 13, 2026
3 tasks
tegan-temporal
pushed a commit
that referenced
this pull request
May 18, 2026
…load component (#3299) * refactor: replace PayloadDecoder and MetadataDecoder with unified Payload component Consolidates two divergent payload display components into a single `<Payload />` component at `src/lib/components/payload.svelte`. Previously, `payload-decoder.svelte` (Svelte 5 runes, required a `children` snippet, always decoded full attribute trees) and `metadata-decoder.svelte` (Svelte 4 options API with slot syntax, decoded single payloads to truncated summary strings) served different display purposes but used inconsistent APIs and decoding paths across 65+ call sites. The new component unifies both under a single `mode` prop: - `code-block` (default): renders a CodeBlock with the decoded value, replacing all PayloadDecoder + CodeBlock snippet patterns - `summary`: truncates to 120 chars and renders a Badge, replacing all MetadataDecoder usages - `inline-truncated`: renders the compact .payload pre block used in event detail rows - `children` snippet: escape hatch for callers that need custom rendering (schedule input, timeline SVG text elements) Both old components used a single decoding path internally (cloneAllPotentialPayloadsWithCodec -> decodePayloadAttributes -> stringifyWithBigInt). MetadataDecoder previously used a separate decodeSingleReadablePayloadWithCodec path; the new component uses the same unified path for consistency. The component is written in Svelte 5 runes throughout and imports from $app/state instead of $app/stores, matching the newer direction of the codebase. Migrated files: - src/lib/components/event/event-card.svelte - src/lib/components/event/event-details-row.svelte (+ moved .payload CSS) - src/lib/components/event/event-metadata-expanded.svelte - src/lib/components/event/event-summary-row.svelte - src/lib/components/lines-and-dots/svg/group-details-text.svelte - src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte - src/lib/components/schedule/schedule-form/schedule-input-payload.svelte - src/lib/components/standalone-activities/activity-input-and-outcome.svelte - src/lib/components/workflow/client-actions/update-confirmation-modal.svelte - src/lib/components/workflow/input-and-results-payload.svelte - src/lib/components/workflow/metadata/metadata-events.svelte - src/lib/components/workflow/pending-activity/pending-activity-card.svelte - src/lib/components/workflow/workflow-json-navigator.svelte - src/lib/pages/standalone-activity-details.svelte - src/lib/pages/standalone-activity-search-attributes.svelte - src/lib/pages/workflow-memo.svelte - src/lib/pages/workflow-metadata.svelte - src/lib/pages/workflow-search-attributes.svelte All 1730 tests pass. * remove unused component, fix css * refactor: move Payload component into payload/ directory Moves payload.svelte into src/lib/components/payload/ and adds a USAGE.md report documenting all 31 call sites grouped by feature area. Updates all 17 import paths accordingly. * docs: add Payload component improvement suggestions * docs: add decode-payload usage report and refactoring recommendations * refactor(payload): split Payload component into focused mode-specific components Replace the 14-prop multi-mode payload.svelte with four single-purpose components: PayloadCodeBlock, PayloadSummary, PayloadDecoder, and PayloadInline. Each component carries only the props relevant to its render mode, eliminating dead props at call sites. Also updates the decode paths to use the renamed decode-payload.ts API (decodeEventAttributes, parsePayloadAttributes) following the #3302 cleanup. * fix(payload-summary): use decodeUserMetadata and add onDecode prop Replace decodeEventAttributes with decodeUserMetadata — the correct decode path for a single raw Payload (Phase 2 codec only, no attribute tree walking). Also add onDecode callback prop, called after a successful decode, consistent with PayloadCodeBlock. * refactor(payload): extract shared decode logic into decode-payload-value utility Remove 3-way duplication of getInitialValue/onMount decode logic from payload-code-block, payload-decoder, and payload-inline by extracting getInitialPayloadValue and decodePayloadValue into src/lib/utilities/decode-payload-value.ts. * fix(payload): replace onMount with \$effect for reactive value updates Components now re-decode when value or fieldName props change after mount, fixing the reactivity gap that caused stale decoded content when parent components updated their payload bindings. * add workflow with user metadata * remove unnecessary props from payload code block * fix summary display * add improvements * fix heading levels * add multi input workflow * get rid of fieldName prop and fix most of the call sites * fix remaining type errors * fix tests * rm inspect * rm console.log * fix CR feedback * remove bad key * fix export * remove unused type * cleanup unused stuff * fix possibly duplicate key * add language prop to PayloadCodeBlock * add copyIconTitle and copySuccessIconTitle to codeblock instance * refactor(payload): fix reactivity and race condition in payload-summary Replace $effect+$state async pattern with $derived promise + $effect cleanup to ensure all reactive deps (value, fallback, prefix, maxSummaryLength) are tracked synchronously. Use $effect cleanup function to cancel stale promise callbacks on re-run, preventing race conditions when value changes rapidly. Remove unused onDecode prop. * early return if no payloads in decode utils
laurakwhit
added a commit
that referenced
this pull request
May 21, 2026
Auto-generated version bump from 2.49.1 to 2.50.0 Bump type: minor Changes included: - [`29832bec`](29832be) Use initiatedEvent for startChildFailed event grouping (#3342) - [`91a01560`](91a0156) rm slash (#3343) - [`2e7b88d0`](2e7b88d) feat: Set Current Version action for worker deployment versions (#3319) - [`b2685f3b`](b2685f3) Add relative path prefix support to routeFor utilities (#3292) - [`9c888c0c`](9c888c0) fix: validate connection modal status, retry button, and copy nits (#3347) - [`38989c48`](38989c4) revert: restore original create worker deployment copy (#3348) - [`90e1fe58`](90e1fe5) Common Errors for Event History (#3306) - [`f479e4e2`](f479e4e) Show current duration for pending timeline events (#3346) - [`65a7ff0d`](65a7ff0) Add refresh button to workers list view (#3349) - [`219cfee4`](219cfee) Fix null conditionals in search attribute filter (#3351) - [`08bd2f01`](08bd2f0) Add support for adding caller Namespace even if it's not in list of allowed Namespace options for Nexus endpoint (#3167) - [`d424a78a`](d424a78) refactor(DT-3906): Add knip (#3350) - [`e828b14f`](e828b14) Remove icon (#3357) - [`252a755c`](252a755) Add Java to list of support versions for worker heartbeats (#3362) - [`0f446c7a`](0f446c7) refactor(DT-3906): Simple Svelte 5 migrations (#3359) - [`63db5b72`](63db5b7) feat(DT-3657): Support shift click for bulk selection in workflow table (#3344) - [`389d57bf`](389d57b) Enable Svelte 5 runes on files not using legacy features (#3363) - [`f4b87e1d`](f4b87e1) Update components/workflow to Svelte 5 syntax (#3361) - [`3e2cce43`](3e2cce4) refactor(DT-3906): More Svelte 5 Migrations (trivial ones) (#3364) - [`15adcd73`](15adcd7) refactor(DT-3906): UI svelte 5 migrate components/events (#3365) - [`031fb867`](031fb86) refactor(DT-3906): Migrate stories to Svelte 5 syntax (#3366) - [`4eac9d2a`](4eac9d2) Scope group hover to tooltip component only (#3379) - [`eeace5c3`](eeace5c) chore: upgrade TypeScript to v6.0.3 (#3371) - [`cb80efdd`](cb80efd) refactor(DT-3906): More trivial migrations (#3367) - [`6cc395bf`](6cc395b) refactor(DT-3906): migrate holocene primitives + layout components to Svelte 5 runes (#3377) - [`40a029ea`](40a029e) refactor(DT-3906): UI Svelte 5 Migrations medium (#3368) - [`7dc29ba6`](7dc29ba) refactor(DT-3906): Delete unused Svelte 4 scaffolding (carved from #3370 - Part 1) (#3372) - [`34a8547e`](34a8547) refactor(DT-3906): Migrate workflow client-action modals to runes (carved from #3370 - Part 4) (#3375) - [`61090d7e`](61090d7) refactor(DT-3906): Migrate schedule view components to runes (carved from #3370 - Part 2) (#3373) - [`988e0479`](988e047) refactor(DT-3906): Migrate filter and input components to runes (carved from #3370 - Part 3) (#3374) - [`d8b78496`](d8b7849) refactor(DT-3906): Migrate workflows-summary table + relationships to runes (carved from #3370 - Part 5) (#3376) - [`ff86c004`](ff86c00) fix(DT-3968): Make Workflow Table Tooltips render in portal (#3383) - [`5e02642a`](5e02642) fix(DT-3967): Visibly toggle the view children button even with a parent has 0 (#3382) - [`1f2b1031`](1f2b103) Remove capability guard from Set Current Version menu item (#3386) - [`0d54dcb4`](0d54dcb) fix: portal maximizable to body to escape stacking context (#3385) - [`abf45438`](abf4543) chore(security): patch Dependabot alerts for axios, protobufjs, fast-uri, uuid, postcss, gomarkdown (#3388) - [`4500f5ea`](4500f5e) Upgrade GitHub actions (#3389) - [`4a8c0c5b`](4a8c0c5) fix(timeline): stabilize child workflow timeline width with scrollbar-gutter (#3329) - [`ead14c61`](ead14c6) Move Create Schedule button to header row (#3390) - [`e8638a2b`](e8638a2) Add top margin (#3392) - [`ef03dfce`](ef03dfc) refactor: replace PayloadDecoder and MetadataDecoder with unified Payload component (#3299) - [`89b9eafa`](89b9eaf) add loading state to payload code block (#3397) - [`ee3ae138`](ee3ae13) Update Schedules search attributes filter (#3396) - [`41fd4f1f`](41fd4f1) DT-3751 - download external payloads (#3345) - [`e4fee0b6`](e4fee0b) Fix codec server request URL (#3400) - [`966b3d0a`](966b3d0) Make input from schedule result actually a string and update tests (#3403) - [`48a014db`](48a014d) feat(history): show Nexus operation name in compact view (#3394) - [`9127c768`](9127c76) Refactor status counts and refresh button (#3402) - [`747ec109`](747ec10) Fix double loader button (#3407) - [`6ae961fc`](6ae961f) Payload rendering and error optimizations (#3401) - [`32c74a48`](32c74a4) add codec server error banner back to workflow layout (#3408) - [`f73c7ec9`](f73c7ec) Nxs operation/kt (#3406) - [`672bb04a`](672bb04) Bump Go 1.26.2→1.26.3, x/net v0.54.0, remove curl from runtime image (#3409) - [`1ee09fe3`](1ee09fe) chore(deps-dev): bump svelte from 5.55.1 to 5.55.7 (#3395) - [`565bb071`](565bb07) VLN-1352: remediate missing-dependency-cooldown (#3398) - [`25794ed8`](25794ed) Bump devalue to 5.8.1 (#3410) - [`b18d0060`](b18d006) Set color-scheme explicitly (#3358) - [`e7995b81`](e7995b8) chore: ensure the empty app.html respects the user's ligh/dark settings (#3353) - [`01d64038`](01d6403) fix: enable external payload download button with namespace level codec endpoint (#3420) - [`4cc44311`](4cc4431) Fix publicPath URL duplication when prefix appears as substring (#3393) Co-authored-by: laurakwhit <[email protected]>
edwardzhu0211
added a commit
to edwardzhu0211/ui
that referenced
this pull request
Jun 6, 2026
…ity detail The Standalone Activity detail page rendered failures with a plain CodeBlock and JSON.stringify, bypassing the codec entirely, in two places: - the Result panel (activity-input-and-outcome.svelte) for `outcome.failure` - the Last Failure panel (standalone-activity-details.svelte) for `info.lastFailure` As a result a failure's `encodedAttributes` payload (where the SDK's failure converter stores the error message and stack trace when configured with EncodeCommonAttributes) was shown as raw base64 instead of being decoded — even when a codec server was configured and the Input/Result decoded correctly. Render both with PayloadCodeBlock, which routes the object through decodeEventAttributes and recursively decodes both `payloads` and `encodedAttributes` via the codec server — matching how the workflow event-history view already renders failures, and completing the temporalio#3299 refactor that moved Input/Result to PayloadCodeBlock but missed the failure branch.
Alex-Tideman
pushed a commit
that referenced
this pull request
Jun 9, 2026
…ity detail (#3507) The Standalone Activity detail page rendered failures with a plain CodeBlock and JSON.stringify, bypassing the codec entirely, in two places: - the Result panel (activity-input-and-outcome.svelte) for `outcome.failure` - the Last Failure panel (standalone-activity-details.svelte) for `info.lastFailure` As a result a failure's `encodedAttributes` payload (where the SDK's failure converter stores the error message and stack trace when configured with EncodeCommonAttributes) was shown as raw base64 instead of being decoded — even when a codec server was configured and the Input/Result decoded correctly. Render both with PayloadCodeBlock, which routes the object through decodeEventAttributes and recursively decodes both `payloads` and `encodedAttributes` via the codec server — matching how the workflow event-history view already renders failures, and completing the #3299 refactor that moved Input/Result to PayloadCodeBlock but missed the failure branch.
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description & motivation 💭
The monolithic component handled 3 rendering modes plus a headless decode mode through a single 14-prop interface, where most props were irrelevant to any given call site. This refactor replaces it with four focused components, each with a minimal prop surface.
New components
Shared decode utility
Extracted the repeated decodeEventAttributes → parsePayloadAttributes → stringifyWithBigInt pipeline from PayloadCodeBlock, PayloadDecoder, and PayloadInline into src/lib/utilities/decode-payload-value.ts. Exports decodePayloadValue and getInitialPayloadValue with a DecodableValue union type.
Correctness fixes
Screenshots (if applicable) 📸
Design Considerations 🎨
Testing 🧪
How was this tested 👻
Steps for others to test: 🚶🏽♂️🚶🏽♀️
pnpm dev,pnpm codec-server, andpnpm run-workflows.Optionally in addition to the above:
git worktree add /path/to/worktree main,cd /path/to/worktree,cp /path/to/ui/.env /path/to/worktree,pnpm i.VITE_APIenv variable in.envto"http://localhost:8081"preview.portinvite.config.tsto3031.pnpm build:localandpnpm preview:localhttp://localhost:3001to spot-check differences betweenmainand this branch.Checklists
Draft Checklist
Merge Checklist
Issue(s) closed
Docs
Any docs updates needed?