Skip to content

Type resource edit payloads for editResourceData#11

Open
gustavo-aguiar wants to merge 5 commits into
mainfrom
feat/edit-resource-types
Open

Type resource edit payloads for editResourceData#11
gustavo-aguiar wants to merge 5 commits into
mainfrom
feat/edit-resource-types

Conversation

@gustavo-aguiar

@gustavo-aguiar gustavo-aguiar commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

editResourceData existed end to end but was typed as TDataRecordInput, a data-point shape that requires variable and cannot express what the resource endpoint accepts. This types the edit payloads as TResourceEditInput{ device, ...fields }, { user, ...fields }, and { id, entity, ...fields } for entity data rows — across core, window.TagoIO, and useEditResourceData, adds an edit-resource.tsx example with inline editing driven by the resource's editable columns, and documents the shapes. Tag and parameter columns (tags.<key> / param.<key> in view/editable) are resolved from the row's tags/params arrays and edited with the dotted key, matching how native widgets address them. Entity_list rows have no platform edit support, so the example blocks editing them. Compile-time-only change; the wire format is unchanged.

Test plan

  • vp run build, vp run check:types, vp check all green
  • vp test: 167 pass, including new payload assertions per shape in packages/core/tests/store/widget-store.test.ts, a variables assertion in packages/react/tests/hooks/use-mutation-hooks.test.tsx, and a new editResourceData describe in packages/js/src/custom-widget.test.ts proving verbatim pass-through with autoFill enabled
  • Manual: companion example app with a mock parent mirroring the real payload shape (tags arrays + dotted view/editable) — edited a device name, a device tags.device_type, a user phone, and an entity status; promises settled via the echoed key, edits persisted across refreshResources(), and entity_list cells render read-only

Breaking changes

None at runtime. TypeScript consumers passing the old (incorrect) TDataRecordInput shape will get compile errors; that shape was never accepted by the resource endpoint.

Risk (CIA)

Likelihood: 🟢 Low | Impact: 🟢 Low | Exposure: 🟢 Low

Related

Companion host fix so the edit-resource response settles the SDK promise and entity edits route to the entity endpoint: tago-io/admin#5014

editResourceData (core, window.TagoIO, useEditResourceData) now takes
TResourceEditInput, the device/user/entity shapes the platform accepts,
instead of the data-record TDataRecordInput, which required `variable`
and never matched the resource endpoint. Wire format is unchanged. Adds
the edit-resource.tsx example with editable-column inline editing and
documents the three payload shapes.
@gustavo-aguiar

Copy link
Copy Markdown
Contributor Author

Companion host fix: tago-io/admin#5014 (edit-resource key echo + isEntity routing).

@gustavo-aguiar

Copy link
Copy Markdown
Contributor Author

Approve
Type-only correction that matches the host contract, with real payload assertions; the example is honest about the identity-key mapping. Three non-blocking notes.

In this PR

Improvements

  • packages/react/examples/edit-resource.tsx:45: for entity_list blocks resource.id can be undefined, so the payload goes out with entity: "" and the server rejects it. Consider skipping the editable affordance when the block has no id (device/user/entity are unaffected).
  • packages/react/examples/edit-resource.tsx:50: each EditableCell calls useResourceData() just for refresh, subscribing every cell to the realtime store. Hoisting refresh to the card (prop-drilling one function) keeps the store subscription count at one per widget.
  • packages/react/examples/edit-resource.tsx:55: await editResourceData(...) only settles when the host echoes the request key, which ships in the companion tago-io/admin#5014 — against a host without it the input stays disabled. Worth a one-line comment in the example so testers against an older host know why.

Praise

  • packages/core/src/types/index.ts:232: the three edit shapes mirror the platform contract exactly (declared identity keys, template-literal tags./param. signatures matching the upstream SDK's string | boolean index).
  • packages/core/src/store/widget-store.ts:167: widening TMessage.variables removed the deleteData double cast instead of adding another one.
  • packages/js/src/custom-widget.test.ts:186: the pass-through test pins the autoFill bypass, which is the behavior most likely to regress if someone unifies the mutation paths later.

Risk (CIA)

Likelihood: 🟢 Low | Impact: 🟢 Low | Exposure: 🟢 Low.
Confirmed. Compile-time-only signature change; wire format and runtime behavior verified unchanged by the payload-assertion tests.

view/editable address tag and parameter columns as `tags.<key>` /
`param.<key>`, but rows carry `tags`/`params` as arrays of key-value
pairs, so those columns never matched row keys and no editable cell
rendered. Derive columns from view/editable too, resolve their values
from the arrays, and send edits with the dotted key. Adds
TResourceEntityListEdit ({ entity, ...fields }) since entity_list rows
are entities themselves, guards editing when the row identity is
missing, and hoists refresh out of the per-cell hook.
@gustavo-aguiar

Copy link
Copy Markdown
Contributor Author

Approve
Re-review of head 3b454ec, focused on whether the edit payloads match what the Admin's native widgets send. Device, user, and entity shapes are confirmed against the native builders; entity_list is the one inferred contract and is flagged below.

In this PR

Payload comparison against the Admin native widgets (source of truth on tago-io/admin main):

  • packages/core/src/types/index.ts:233 (TResourceDeviceEdit): matches Device List. packages/widgets/device-list/original/View/Logic/formatDataToSave/formatDataToSave.ts:142 returns { device: deviceId, ...fields }, with keys from getColumnPropertyname, tags.<tag>, param.<configuration_parameter>, last_input — exactly the shapes this type declares.
  • packages/core/src/types/index.ts:242 (TResourceUserEdit): matches User List. packages/widgets/user-list/original/View/Logic/formatDataToSave/formatDataToSave.ts:117 returns { user: userId, ...fields } over the same editable field set.
  • packages/core/src/types/index.ts:256 (TResourceEntityEdit): matches Entity Management. packages/widgets/entity-table/original/entity-management-logic.ts:494 returns { id: dataId, entity: entityId, ...fields }.
  • packages/react/examples/edit-resource.tsx:47 (getCellValue): the dotted tags.<key> addressing with values resolved from the row's tags array mirrors how Device List columns address tag properties, and edits go out with the dotted key like the native getColumnProperty output.

Questions

  • packages/core/src/types/index.ts:262 (TResourceEntityListEdit): no native widget edits entity_list rows, so { entity: rowId, ...fields } is inferred from the device/user identity-key pattern rather than verified against a native builder; the host passes it verbatim to PUT /data/{dash}/{widget}/resource. Verify against the real backend once tago-io/admin#5014 ships and adjust the shape (or its doc comment) if the endpoint expects something else.

Improvements

  • packages/react/examples/edit-resource.tsx:92: the example always sends the drafted value as a string. Device List coerces everything to String() too (formatDataToSave.ts:103), so device/user match native behavior, but Entity Management keeps numeric values for number columns — the in-code comment covers it; consider converting numeric entity fields in buildEditPayload if the example's entity card ever exposes a number column as editable.

Praise

  • packages/react/examples/edit-resource.tsx:66 (buildColumns): replacing the raw tags/params array columns with the dotted view/editable columns reproduces the native table behavior instead of dumping arrays, and fixed the "editable tag never renders" gap found in real-dashboard testing.

Risk (CIA)

Likelihood: 🟢 Low | Impact: 🟢 Low | Exposure: 🟢 Low.
Confirmed. Type-only surface plus example code; the three payload shapes that ship to production endpoints are verified against the native widget builders.

Entity_list rows have no edit support on the platform, so remove the
TResourceEntityListEdit shape and block editing those rows in the
example instead of sending a payload the backend rejects.
Entity Management keeps numbers for numeric columns, so the edit example
now coerces the draft back to a number when the current cell holds one,
instead of always sending strings. Device and user values stay strings,
matching the native widgets.
@gustavo-aguiar

Copy link
Copy Markdown
Contributor Author

Approve
Re-review of c02df3b + 08dd88a: the entity_list question from the prior pass is resolved by removing that surface entirely, the numeric-entity improvement is applied, and no new findings came out of the delta.

Praise

  • packages/core/src/types/index.ts:261: dropping TResourceEntityListEdit instead of shipping an unverified contract was the right call — the union now only contains shapes verified against the native widget builders, and canEditRow blocks the affordance in the example so users cannot reach the unsupported path.
  • packages/react/examples/edit-resource.tsx:80 (coerceEntityValue): coercing only when the current cell already holds a number (and the draft parses) reproduces Entity Management's typed-value behavior without guessing types; device/user edits stay strings like the native widgets send. Verified on the wire: the mock captured { id, entity, value: 42 } with a number payload.

Risk (CIA)

Likelihood: 🟢 Low | Impact: 🟢 Low | Exposure: 🟢 Low.
Confirmed. The delta removes an untested surface and refines example behavior; the shipped payload shapes remain the three verified against the Admin native widgets.

@gustavo-aguiar
gustavo-aguiar requested a review from vitorfdl July 17, 2026 14:58
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.

1 participant