Skip to content

refactor: replace PayloadDecoder and MetadataDecoder with unified Payload component#3299

Open
rossedfort wants to merge 24 commits intomainfrom
refactor-payload-component
Open

refactor: replace PayloadDecoder and MetadataDecoder with unified Payload component#3299
rossedfort wants to merge 24 commits intomainfrom
refactor-payload-component

Conversation

@rossedfort
Copy link
Copy Markdown
Contributor

@rossedfort rossedfort commented Apr 13, 2026

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

  • PayloadCodeBlock — renders a , replaces (~24 call sites). Uses decodeEventAttributes + parsePayloadAttributes for full event attribute tree decoding.
  • PayloadSummary — renders a or , replaces . Uses decodeUserMetadata (correct path for single raw Payloads — avoids double-decoding with codec servers).
  • PayloadInline — renders a truncated inline code block, replaces .
  • PayloadDecoder — headless decode-only component that passes decoded value to a child snippet.

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

  • PayloadSummary now uses decodeUserMetadata instead of decodeEventAttributes — the previous path would double-decode raw Payloads when a codec server is configured.
  • All four components use $effect instead of onMount, so decoded values update reactively when props change rather than only on mount.
  • Added onDecode callback to PayloadSummary (was missing, needed by timeline graph row).

Screenshots (if applicable) 📸

Design Considerations 🎨

Testing 🧪

How was this tested 👻

Steps for others to test: 🚶🏽‍♂️🚶🏽‍♀️

  • check out this branch, run pnpm dev, pnpm codec-server, and pnpm run-workflows.
  • check the payload-coverage-workflow and user-metadata-workflow to ensure all payloads are decoded

Optionally in addition to the above:

  1. in a separate terminal in the ui repo, run git worktree add /path/to/worktree main, cd /path/to/worktree, cp /path/to/ui/.env /path/to/worktree, pnpm i.
  2. change the VITE_API env variable in .env to "http://localhost:8081"
  3. change preview.port in vite.config.ts to 3031.
  4. Then run pnpm build:local and pnpm preview:local
  5. open http://localhost:3001 to spot-check differences between main and this branch.

Checklists

Draft Checklist

Merge Checklist

Issue(s) closed

Docs

Any docs updates needed?

…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.
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
holocene Ready Ready Preview, Comment Apr 24, 2026 5:13pm

Request Review

let success;
let error = $state('');
let loading = $state(false);
let failure = $state<
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Property 'failure' does not exist on type 'IOutcome | null | undefined'.

let failure = $state<
UpdateWorkflowResponse['outcome']['failure'] | undefined
>(undefined);
let success = $state<
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Property 'success' does not exist on type 'IOutcome | null | undefined'.

@temporal-cicd
Copy link
Copy Markdown
Contributor

temporal-cicd Bot commented Apr 13, 2026

Warnings
⚠️

📊 Strict Mode: 125 errors in 22 files (12.4% of 1005 total)

src/lib/services/data-encoder.ts (5)
  • L32:27: Type 'PotentialPayloads' is not assignable to type 'IPayloads'.
  • L49:8: Element implicitly has an 'any' type because expression of type '"Authorization"' can't be used to index type '{ 'Content-Type': string; 'X-Namespace': string; }'.
  • L52:8: Element implicitly has an 'any' type because expression of type '"Authorization-Extras"' can't be used to index type '{ 'Content-Type': string; 'X-Namespace': string; }'.
  • L56:6: Type 'PotentialPayloads' is not assignable to type 'IPayloads'.
  • L103:2: Type 'PotentialPayloads' is not assignable to type 'IPayloads'.
src/lib/utilities/decode-payload.ts (25)
  • L81:35: Argument of type '{ [k: string]: Uint8Array; } | null | undefined' is not assignable to parameter of type 'Record<string, unknown>'.
  • L84:9: 'payloadOrPayloads.payloads' is possibly 'null' or 'undefined'.
  • L85:28: Argument of type '{ [k: string]: Uint8Array; } | null | undefined' is not assignable to parameter of type 'Record<string, unknown>'.
  • L111:45: Argument of type '{ [k: string]: Uint8Array; } | null | undefined' is not assignable to parameter of type 'Record<string, unknown>'.
  • L124:45: Argument of type '{ [k: string]: Uint8Array; } | null | undefined' is not assignable to parameter of type 'Record<string, unknown>'.
  • L158:19: No overload matches this call.
  • L159:6: 'searchAttributes' is of type 'unknown'.
  • L159:52: Argument of type 'unknown' is not assignable to parameter of type 'IPayload'.
  • L167:19: No overload matches this call.
  • L168:6: 'memo' is of type 'unknown'.
  • L168:40: Argument of type 'unknown' is not assignable to parameter of type 'IPayload'.
  • L176:19: No overload matches this call.
  • L177:6: 'header' is of type 'unknown'.
  • L177:42: Argument of type 'unknown' is not assignable to parameter of type 'IPayload'.
  • L186:19: No overload matches this call.
  • L187:6: 'queryResult' is of type 'unknown'.
  • L187:47: Argument of type 'unknown' is not assignable to parameter of type 'IPayload'.
  • L268:62: Argument of type 'IPayload | null | undefined' is not assignable to parameter of type 'IPayload | IPayload[]'.
  • L280:54: 'payloads' is possibly 'null' or 'undefined'.
  • L280:54: Argument of type 'IPayload[] | null | undefined' is not assignable to parameter of type 'unknown[]'.
  • L326:57: 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 ... | { ...; }'.
  • L327:29: 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 ... | { ...; }'.
  • L329:8: 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 ... | { ...; }'.
  • L331:21: 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 ... | { ...; }'.
  • L333:10: 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 ... | { ...; }'.
src/lib/utilities/get-single-attribute-for-event.ts (11)
  • L130:13: 'getStackTrace' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
  • L234:35: No overload matches this call.
  • L239:20: Type 'object | null' is not assignable to type 'string | Record<string, unknown> | IPayloads | IPayload'.
  • L241:53: 'value' is possibly 'null'.
  • L241:53: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
  • L243:25: 'value' is possibly 'undefined'.
  • L273:19: Function lacks ending return statement and return type does not include 'undefined'.
  • L274:44: No overload matches this call.
  • L312:41: Argument of type 'unknown' is not assignable to parameter of type 'IPayload'.
  • L328:46: No overload matches this call.
  • L341:34: 'event.attempt' is possibly 'null' or 'undefined'.
src/lib/components/payload/decode-payload-value.ts (5)
  • L23:34: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'IPayloads | IPayload | WorkflowEvent | IUserMetadata | IWorkflowExecutionStartedEventAttributes | ... 59 more ... | Record<...>'.
  • L23:55: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'IPayloads | IPayload | WorkflowEvent | IUserMetadata | IWorkflowExecutionStartedEventAttributes | ... 59 more ... | Record<...>'.
  • L35:4: Argument of type 'WorkflowEvent | EventAttribute | IMemo | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.
  • L37:33: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
  • L38:31: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
src/lib/services/workflow-service.ts (21)
  • L194:6: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
  • L256:4: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
  • L295:45: Argument of type 'unknown' is not assignable to parameter of type 'WorkflowExecutionAPIResponse | undefined'.
  • L428:28: No overload matches this call.
  • L648:4: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
  • L654:10: Argument of type '(response?: WorkflowExecutionAPIResponse) => WorkflowExecution' is not assignable to parameter of type '(value: unknown) => WorkflowExecution | PromiseLike'.
  • L684:4: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'ISearchAttributes'.
  • L760:37: Argument of type 'SearchAttributeInput[]' is not assignable to parameter of type '{ type: "Unspecified" | "Keyword" | "Text" | "Int" | "Double" | "Bool" | "KeywordList" | "Datetime"; label: string; value?: any; }[]'.
  • L823:8: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
  • L839:6: 'startEvent.attributes.input' is possibly 'null' or 'undefined'.
  • L839:6: Element implicitly has an 'any' type because expression of type '0' can't be used to index type 'IPayloads | (IPayload & IPayloads)'.
  • L844:8: 'workflow' is possibly 'undefined'.
  • L846:8: 'workflow' is possibly 'undefined'.
  • L854:8: 'workflow' is possibly 'undefined'.
  • L856:8: 'workflow' is possibly 'undefined'.
  • L1030:20: Argument of type 'WorkflowExecution | undefined' is not assignable to parameter of type 'WorkflowExecution'.
  • L1069:28: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
  • L1097:10: Property 'executions' does not exist on type 'WithoutNextPageToken'.
  • L1097:41: Argument of type '(token: string) => Promise' is not assignable to parameter of type '(token?: NextPageToken | undefined) => Promise'.
  • L1141:6: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
  • L1170:6: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
src/lib/utilities/decode-local-activity.ts (2)
  • L49:6: Argument of type 'WorkflowEvent | EventAttribute | IMemo | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.
  • L54:41: Argument of type 'IPayload | undefined' is not assignable to parameter of type 'IPayload'.
src/lib/utilities/export-history.ts (2)
  • L32:50: Argument of type 'null' is not assignable to parameter of type '((key: string, value: { events: HistoryEvent[]; }) => { events: HistoryEvent[]; }) | undefined'.
  • L67:15: Argument of type '(IPayloads | IPayload | HistoryEvent | IUserMetadata | IWorkflowExecutionStartedEventAttributes | ... 41 more ... | undefined)[]' is not assignable to parameter of type 'HistoryEvent[]'.
src/lib/utilities/get-started-completed-and-task-failed-events.ts (6)
  • L88:6: Variable 'workflowStartedEvent' is used before being assigned.
  • L89:4: Type 'IPayloads | null' is not assignable to type 'IPayloads'.
  • L94:6: Variable 'workflowCompletedEvent' is used before being assigned.
  • L96:4: Type 'IPayloads | (IWorkflowExecutionFailedEventAttributes & { type: "workflowExecutionFailedEventAttributes"; }) | (IWorkflowExecutionTimedOutEventAttributes & { ...; }) | (IWorkflowExecutionTerminatedEventAttributes & { ...; }) | (IWorkflowExecutionCanceledEventAttributes & { ...; }) | null | undefined' is not assignable to type 'IPayloads | (EventAttribute & IWorkflowExecutionCompletedEventAttributes & { type: "workflowExecutionCompletedEventAttributes"; }) | ... 4 more ... | (EventAttribute & ... 1 more ... & { ...; })'.
  • L100:4: Variable 'input' is used before being assigned.
  • L101:4: Variable 'results' is used before being assigned.
src/routes/(app)/nexus/[id]/+layout.ts (1)
  • L24:4: 'endpoint.spec' is possibly 'undefined'.
src/lib/components/workflow/client-actions/update-confirmation-modal.svelte (4)
  • L40:38: Property 'failure' does not exist on type 'IOutcome | null | undefined'.
  • L43:38: Property 'success' does not exist on type 'IOutcome | null | undefined'.
  • L90:6: Type 'string | undefined' is not assignable to type 'string'.
  • L119:9: 'updateDefinitions.length' is possibly 'undefined'.
src/lib/components/event/event-card.svelte (11)
  • L141:37: Type 'string | null | undefined' is not assignable to type 'string'.
  • L141:48: 'link.workflowEvent' is possibly 'null' or 'undefined'.
  • L149:6: Type 'string | null | undefined' is not assignable to type 'string'.
  • L149:15: 'link.workflowEvent' is possibly 'null' or 'undefined'.
  • L152:10: 'link.workflowEvent' is possibly 'null' or 'undefined'.
  • L176:19: Parameter 'key' implicitly has an 'any' type.
  • L176:24: Parameter 'value' implicitly has an 'any' type.
  • L199:15: Parameter 'key' implicitly has an 'any' type.
  • L199:20: Parameter 'value' implicitly has an 'any' type.
  • L219:18: Parameter 'key' implicitly has an 'any' type.
  • L219:23: Parameter 'value' implicitly has an 'any' type.
src/lib/components/workflow/pending-activity/pending-activity-card.svelte (8)
  • L174:24: Type 'IPayloads | null | undefined' is not assignable to type 'object | PotentiallyDecodable'.
  • L224:20: Parameter 'timeDifference' implicitly has an 'any' type.
  • L241:8: Argument of type 'number | null | undefined' is not assignable to parameter of type 'number | null'.
  • L246:54: Argument of type 'number | null | undefined' is not assignable to parameter of type 'number'.
  • L31:26: 'activity.attempt' is possibly 'null' or 'undefined'.
  • L95:12: Argument of type 'number | null | undefined' is not assignable to parameter of type 'number'.
  • L97:14: Argument of type 'Duration | null' is not assignable to parameter of type 'string | Duration'.
  • L140:13: 'totalPending' is possibly 'undefined'.
src/lib/components/event/event-summary-row.svelte (5)
  • L134:6: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
  • L171:23: Parameter 'event' implicitly has an 'any' type.
  • L183:30: Parameter 'group' implicitly has an 'any' type.
  • L183:37: Parameter 'hoveredEventId' implicitly has an 'any' type.
  • L311:16: Type 'ITimestamp | null | undefined' is not assignable to type 'ITimestamp'.
src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte (7)
  • L95:20: 'distance' is possibly 'null'.
  • L95:31: 'workflowDistance' is possibly 'null'.
  • L106:20: 'distance' is possibly 'null'.
  • L106:31: 'workflowDistance' is possibly 'null'.
  • L146:29: 'activityTaskScheduled.attributes.attempt' is possibly 'null' or 'undefined'.
  • L239:12: 'pendingActivity.attempt' is possibly 'null' or 'undefined'.
  • L283:15: 'activityTaskScheduled' is possibly 'undefined'.
src/lib/components/schedule/schedule-form/schedule-input-payload.svelte (1)
  • L75:18: Type 'IPayloads | undefined' is not assignable to type 'object | PotentiallyDecodable'.
src/lib/components/standalone-activities/activity-input-and-outcome.svelte (1)
  • L18:22: Type 'IPayloads | undefined' is not assignable to type 'object | PotentiallyDecodable'.
src/lib/pages/standalone-activity-details.svelte (5)
  • L53:48: Argument of type 'number | undefined' is not assignable to parameter of type 'number | null'.
  • L81:14: Type 'string | undefined' is not assignable to type 'string'.
  • L86:14: Argument of type 'IFailure | undefined' is not assignable to parameter of type 'IFailure'.
  • L106:32: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
  • L221:30: Type '{ [k: string]: IPayload; } | null | undefined' is not assignable to type 'object | PotentiallyDecodable'.
src/lib/pages/standalone-activity-metadata.svelte (1)
  • L38:23: Argument of type 'IUserMetadata | undefined' is not assignable to parameter of type 'IUserMetadata'.
src/lib/pages/standalone-activity-search-attributes.svelte (1)
  • L10:22: Type 'Record<string, IPayload> | undefined' is not assignable to type 'object | PotentiallyDecodable'.
src/lib/pages/workflow-metadata.svelte (1)
  • L14:24: Type 'Record<string, string> | undefined' is not assignable to type 'object | PotentiallyDecodable'.
src/lib/pages/workflow-search-attributes.svelte (1)
  • L13:22: Type 'Record<string, string> | undefined' is not assignable to type 'object | PotentiallyDecodable'.
temporal/client.ts (1)
  • L38:3: Function lacks ending return statement and return type does not include 'undefined'.

Generated by 🚫 dangerJS against 86127b9

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.
'∞'}
{'• '}
{decodedValue}
{:else if retried}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'activityTaskScheduled' is possibly 'undefined'.

@rossedfort rossedfort marked this pull request as ready for review April 21, 2026 15:46
@rossedfort rossedfort requested a review from a team as a code owner April 21, 2026 15:46
value: DecodableValue,
fieldName: string,
): string => {
if (!value) return stringifyWithBigInt(value);
Copy link
Copy Markdown
Contributor

@temporal-cicd temporal-cicd Bot Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'IPayloads | IPayload | WorkflowEvent | IUserMetadata | IWorkflowExecutionStartedEventAttributes | ... 59 more ... | Record<...>'.
  • ⚠️ Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'IPayloads | IPayload | WorkflowEvent | IUserMetadata | IWorkflowExecutionStartedEventAttributes | ... 59 more ... | Record<...>'.

const convertedAttributes = await decodeEventAttributes(
value as PotentiallyDecodable | EventAttribute | WorkflowEvent | Memo,
);
const decodedAttributes = parsePayloadAttributes(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Argument of type 'WorkflowEvent | EventAttribute | IMemo | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.

);
const decodedAttributes = parsePayloadAttributes(
convertedAttributes,
) as object;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.

const decodedAttributes = parsePayloadAttributes(
convertedAttributes,
) as object;
const keyExists = fieldName && decodedAttributes?.[fieldName];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.

@@ -69,20 +73,22 @@
</script>

<div class="flex flex-col gap-1">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Type 'IPayloads | undefined' is not assignable to type 'object | PotentiallyDecodable'.

@@ -17,22 +16,14 @@
<div class="grid w-full grid-cols-2 gap-4 max-md:grid-cols-1">
<div class="flex flex-col gap-2">
<h5>Input</h5>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Type 'IPayloads | undefined' is not assignable to type 'object | PotentiallyDecodable'.

@@ -172,16 +172,7 @@
{translate('workflows.heartbeat-details')}
</p>
{#key activity.attempt}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Type 'IPayloads | null | undefined' is not assignable to type 'object | PotentiallyDecodable'.

{/if}
{#if $activityExecution.info.header}
<div class="space-y-2">
<p class="font-medium text-secondary">Header</p>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Type '{ [k: string]: IPayload; } | null | undefined' is not assignable to type 'object | PotentiallyDecodable'.

@@ -9,18 +8,7 @@

<div class="flex flex-col gap-2">
{#if searchAttributes}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Type 'Record<string, IPayload> | undefined' is not assignable to type 'object | PotentiallyDecodable'.

@@ -85,15 +87,14 @@ export const getWorkflowStartedCompletedAndTaskFailedEvents = (
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Variable 'workflowStartedEvent' is used before being assigned.

@@ -85,15 +87,14 @@ export const getWorkflowStartedCompletedAndTaskFailedEvents = (
}

if (workflowStartedEvent) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Type 'IPayloads | null' is not assignable to type 'IPayloads'.

);
null;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Variable 'workflowCompletedEvent' is used before being assigned.

}

if (workflowCompletedEvent) {
contAsNew = isWorkflowExecutionContinuedAsNewEvent(workflowCompletedEvent);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Type 'IPayloads | (IWorkflowExecutionFailedEventAttributes & { type: "workflowExecutionFailedEventAttributes"; }) | (IWorkflowExecutionTimedOutEventAttributes & { ...; }) | (IWorkflowExecutionTerminatedEventAttributes & { ...; }) | (IWorkflowExecutionCanceledEventAttributes & { ...; }) | null | undefined' is not assignable to type 'IPayloads | (EventAttribute & IWorkflowExecutionCompletedEventAttributes & { type: "workflowExecutionCompletedEventAttributes"; }) | ... 4 more ... | (EventAttribute & ... 1 more ... & { ...; })'.

results = getEventResult(workflowCompletedEvent);
}

return {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Variable 'input' is used before being assigned.

Comment thread src/lib/components/event/event-card.svelte Outdated
/>
</div>
{/snippet}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Parameter 'key' implicitly has an 'any' type.
  • ⚠️ Parameter 'value' implicitly has an 'any' type.

Copy link
Copy Markdown
Collaborator

@rossnelson rossnelson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! I left a couple minor comments.

startEvent?.attributes?.input,
)) as PotentiallyDecodable;
const decodedInput = await decodePayloadAndParseDataToJSON(
startEvent.attributes.input[0],
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like inputs has an additional level to get the actual payload.

Suggested change
startEvent.attributes.input[0],
startEvent.attributes.input?.payloads?.[0],

Before:
Image

After:

Image

export const decodeLocalActivity = async (
event: IterableEvent,
): Promise<SummaryAttribute | undefined> => {
console.log(event);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

X ?

class="overflow-hidden border border-subtle bg-code-block px-1 py-0.5 font-mono text-xs text-primary {className}"
>
<code>
<pre class="truncate">{decodedValue.slice(0, truncateAt)}</pre>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like this is expecting to truncate text but decoded value is actually an array?

Suggested change
<pre class="truncate">{decodedValue.slice(0, truncateAt)}</pre>
<pre class="truncate">{(decodedValue[0] ?? '').slice(0, truncateAt)}</pre>

Before:
Image

After:
Image

export const decodePayloadsAndParseDataToJSON = async (
payloads: Payloads | null | undefined,
): Promise<unknown[]> => {
const decoded = await decodePayloadsWithRemoteCodec(payloads.payloads);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function signature implies that payloads could be null or undefined.

Suggested change
const decoded = await decodePayloadsWithRemoteCodec(payloads.payloads);
const decoded = await decodePayloadsWithRemoteCodec(payloads?.payloads);

Comment on lines +37 to +54
$effect(() => {
if (!value) {
decodedValue = fallback;
return;
}
decodePayloadAndParseDataToJSON(value)
.then((result) => {
if (typeof result === 'string' && result) {
decodedValue = applyPrefix(result);
onDecode?.(decodedValue);
} else {
decodedValue = fallback;
}
})
.catch(() => {
decodedValue = fallback;
});
});
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edge case, but there could be a race condition here if the component is re-rendered while still decoding. Maybe cancel on effect cleanup?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants