fix: JSON Data Encoding#4911
Conversation
|
👋 Commands for maintainers:
|
There was a problem hiding this comment.
This review is more about me trying to understand what's going on in the code than anything else.
The PR seems to me like something that would work.
I'm wondering if there's a simpler solution that doesn't involve a special structure for handling JSON in the code and automatically converting the number values to strings.
Wouldn't it be simpler to explicitly convert those strings to numbers when we're creating the JSON structures instead of this special type and auto-convert logic?
Signed-off-by: André Calil <andre@calil.com.br>
Signed-off-by: André Calil <andre@calil.com.br>
Signed-off-by: André Calil <andre@calil.com.br>
## Summary - Restore the visual styles from commit 09cbca1 that were dropped during the merge of #4816: shorter (h-10) top and secondary headers, white secondary background, Tabs-based Canvas/Dashboard toggle, and icon-less Edit button. - Rewrite CanvasModeToggle to use the shared Tabs primitive (with the muted draft dot) while keeping Dashboard tab support added by #4875. - Remove the X close button from the tool sidebar's tab header so the Agent/Runs/Versions row matches the original design. - Always show the Runs and Versions tabs in the tool sidebar — they were hidden when editing a version because onToggleVersionControl / versionsContent were undefined. --------- Signed-off-by: Pedro F. Leao <pedroforestileao@gmail.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Pedro Leão <forestileao@users.noreply.github.com> Signed-off-by: André Calil <andre@calil.com.br>
Summary Re-applies the editing-sidebar UX changes from the reverted #4621, minus the two behaviors that led to the revert: - Skipped: the "show only installed integrations" filter — it hid categories during demos when the relevant integration wasn't yet connected. - Skipped: the icon-rerender flicker when expanding a category — block items now stay mounted inside <details> (the browser handles show/hide via CSS), and BlockItem is wrapped in React.memo. - Removed entirely: the + Integrations button + the connect-integrations modal, by request — including all related state, props, and the IntegrationGridSection component. Sidebar UX - Pointer-based resize for both BuildingBlocksSidebar (clamp 280–640px, default 460) and componentSidebar (clamp 300–800px, default 380). Width persisted to localStorage and clamped on read. - Categories in BuildingBlocksSidebar: Core → Debugging → Memory ordered first, the rest alphabetical. No more filtering by configured integrations. - CategorySection simplified — drops drag-preview cloning, hover state, the GripVerticalIcon, the integration-status Plug indicator, and the conditional ItemGroup mount. Icon helper logic extracted into resolveCategoryIcon / renderCategoryIcon. Canvas append handles - Single-channel append (handles.tsx): tightened position (right: -15, top: 18, drop transform: none). - Multi-channel append (multiRightHandle.tsx): per-channel layout. Channel-name text width is measured via canvas.measureText with the matching font; all rows align to the widest channel's line so the "+" buttons are flush regardless of name length. - appendHandle.tsx: new plus-hovered highlight state, horizontal nudge so the plus sits inside the connector, hover-driven border darken, preview offsets parameterised via CSS vars (--sp-append-preview-connector-offset-y, --sp-append-preview-offset-y). - canvas-reset.css: drops the old hitbox ::before, adds the plus-hovered rules to gate the hover styling. - RightSideControls spacing gap-1.5 → gap-2.5. CanvasPage / workflowv2 plumbing - Starter placeholder UX: clicking the floating Add Component button when nothing else is open now creates a free-positioned placeholder via onPlaceholderAdd({ position }) and opens the building-blocks sidebar over it. onPlaceholderAdd's sourceNodeId / sourceHandleId are now optional so this path doesn't need an edge. - handlePlaceholderAdd in workflowv2/index.tsx only adds an edge when both source fields are present. --------- Signed-off-by: Pedro F. Leao <pedroforestileao@gmail.com> Signed-off-by: André Calil <andre@calil.com.br>
Signed-off-by: Pedro F. Leao <pedroforestileao@gmail.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Pedro Leão <forestileao@users.noreply.github.com> Signed-off-by: André Calil <andre@calil.com.br>
…#4922) ## Summary - add example payload fields to integration capability definitions - serialize example payloads for both legacy and setup-provider integration capabilities - map those fields back into `superplane index actions|triggers` and cover the regression with tests ## Testing - make pb.gen openapi.spec.gen openapi.client.gen openapi.web.client.gen - make test PKG_TEST_PACKAGES="./pkg/cli/commands/index ./pkg/grpc/actions/integrations" - make lint - make check.build.app Closes #4912 --------- Signed-off-by: Pedro F. Leao <pedroforestileao@gmail.com> Signed-off-by: André Calil <andre@calil.com.br>
The rich UI widget syntax reference was missing from agent sessions after the resource loading refactor. This embeds it as a static Go file and mounts it at `ref/rich-ui-widgets.md`. Covers: buttons, surveys, rubrics, charts, mermaid, node/run/integration chips, draft-actions. --------- Signed-off-by: Bender Rodriguez <bender@superplanehq.com> Co-authored-by: Bender Rodriguez <bender@superplanehq.com> Signed-off-by: André Calil <andre@calil.com.br>
Fixes #4920. ## Summary - add version_id to workflow_runs and backfill existing runs from the published version active at run creation - attach the live canvas version when creating new workflow runs and expose it through the CanvasRun API - load the run's recorded canvas version in runs view so historical/deleted nodes render correctly ## Validation - make test PKG_TEST_PACKAGES='./pkg/models ./pkg/grpc/actions/canvases' - make lint - make check.build.app - make format.js - make check.lint.ui - make check.build.ui - make check.db.migrations --------- Signed-off-by: Pedro F. Leao <pedroforestileao@gmail.com> Signed-off-by: André Calil <andre@calil.com.br>
<!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## Context Fix requested in PR comment: when using Versions → “Load older versions” then clicking to view a different version, the already-loaded history should stay available (no re-loading / re-clicking required). ## What’s in this PR (WIP) - Adds a frontend regression test for the Versions sidebar to ensure expanded history remains visible when selecting a different version. ## Next steps in this PR - Reproduce the issue end-to-end in `workflowv2` and implement the fix so the test represents the real regression (and add/adjust an integration-level test if needed). - Run `make format.js` and `make check.build.ui`. ## Testing - Unit test added (not yet validated in CI/local in this PR revision). <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-29121969-11c9-4d8a-90ca-1a45f53b71ab"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-29121969-11c9-4d8a-90ca-1a45f53b71ab"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> --------- Signed-off-by: Pedro F. Leao <pedroforestileao@gmail.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Pedro Leão <forestileao@users.noreply.github.com> Signed-off-by: André Calil <andre@calil.com.br>
## Summary - Preserve full markdown bodies for categorized rubric sections instead of flattening them to criteria only - Render rubric body markdown with GFM tables, fenced code blocks, links, blockquotes, and lists - Keep preserved rubric markdown when starting a build from a rubric widget ## Tests - make format.js - docker compose -f docker-compose.dev.yml exec app bash -c "cd web_src && npm test -- --run src/components/AgentSidebar/widgets/parser.test.ts src/components/AgentSidebar/widgets/RubricWidget.spec.tsx src/components/AgentSidebar/widgets/RichMessage.spec.tsx" - make check.build.ui - make check.lint.ui --------- Signed-off-by: Pedro F. Leao <pedroforestileao@gmail.com> Signed-off-by: André Calil <andre@calil.com.br>
fixes #4932 Signed-off-by: Igor Šarčević <igor@operately.com> Signed-off-by: André Calil <andre@calil.com.br>
## Summary - clear component sidebar URL state when switching canvas versions or entering/leaving edit mode - prevent node run-history loading from the component sidebar while the canvas is in edit mode - add a CanvasPage regression test for live-only sidebar event loading ## Validation - npm run test:run -- src/ui/CanvasPage/index.spec.tsx - make format.js - make check.build.ui Signed-off-by: André Calil <andre@calil.com.br>
Signed-off-by: Igor Šarčević <igor@operately.com> Signed-off-by: André Calil <andre@calil.com.br>
Co-authored-by: André Calil <andre@calil.com.br> Signed-off-by: André Calil <andre@calil.com.br>
Signed-off-by: Igor Šarčević <igor@operately.com> Signed-off-by: André Calil <andre@calil.com.br>
## Summary - scope e2e step helpers to subtests so page/session cleanup runs before the next DB reset - make manual-trigger setup deterministic through the backend event path while preserving run-title resolution - harden canvas node interactions, queued wait cleanup, and local/CI e2e timeouts ## Validation - make test.e2e - make lint && make check.build.app --------- Signed-off-by: Pedro F. Leao <pedroforestileao@gmail.com> Signed-off-by: André Calil <andre@calil.com.br>
Signed-off-by: Igor Šarčević <igor@operately.com> Signed-off-by: André Calil <andre@calil.com.br>
Signed-off-by: André Calil <andre@calil.com.br>
6709ec3 to
edcee23
Compare
Signed-off-by: André Calil <andre@calil.com.br>
|
@cursoragent update your review |
|
Done.
Pushed commit:
Verified:
Could not run full Docker-backed checks:
|
7b2392e to
818d0ad
Compare
Signed-off-by: André Calil <andre@calil.com.br>
Signed-off-by: André Calil <andre@calil.com.br>
| EventID: event.ID.String(), | ||
| SourceNodeID: event.NodeID, | ||
| Input: event.Data.Data(), | ||
| Input: map[string]any{event.NodeID: normalizeExpressionValue(event.Data.Data())}, |
There was a problem hiding this comment.
This change is suspicious. Why is this needed?
There was a problem hiding this comment.
To support expressions (hence the sourceNodeID) and to normalize different number types.
What do you find suspicious? Feel free to suggest a different approach.
There was a problem hiding this comment.
What do you find suspicious?
I could be misunderstanding this, but to me this looks suspicious to me because all the other changes seem to be about decoding, but for this one, you are actually changing what the ProcessQueueContext.Input value is. @forestileao can you take a look?
There was a problem hiding this comment.
What is the state here? @lucaspin @andrecalil @forestileao
There was a problem hiding this comment.
I was waiting for Pedro to chime in while I looked at other issues/tasks.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d73581f. Configure here.
| return out | ||
| default: | ||
| return value | ||
| } |
There was a problem hiding this comment.
Duplicate recursive JSON tree-walking logic across packages
Low Severity
toStructpbCompatible in structpb_compatible.go and normalizeExpressionValue/normalizeExpressionMap/normalizeExpressionSlice in node_configuration_builder.go both implement the same recursive tree-walking pattern over map[string]any, []any, and json.Number. The only difference is the leaf conversion strategy for json.Number. Extracting a shared generic walker parameterized by the number-conversion function would reduce the maintenance surface and the risk of one path diverging from the other.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit d73581f. Configure here.
| if err == nil { | ||
| return errors.New("invalid JSON: multiple top-level values") | ||
| } | ||
| return err |
There was a problem hiding this comment.
Multi-value detection uses wrong decode target type
Low Severity
UnmarshalJSONValue detects multiple top-level JSON values by attempting a second Decode into &struct{}{}. This works for extra objects or null, but if the trailing value is a number, string, boolean, or array, the decoder returns a type-mismatch error instead of nil. The function still rejects the input, but the returned error message is misleading (a Go unmarshal error instead of "multiple top-level values"). Using new(any) as the target would correctly detect all trailing JSON value types.
Reviewed by Cursor Bugbot for commit d73581f. Configure here.




Summary
Fixes canvas event JSON handling so numeric payload values are not silently converted to float64 and later rendered in scientific notation or with precision loss.
Changes:
CanvasEvent.DataJSON storage with a number-preservingmodels.JSONValue.json.Decoder.UseNumber().json.Number, stringifying only unsafe/exponent-prone values at the Struct boundary.