mikebridge opened a new pull request, #44028:
URL: https://github.com/apache/superset/pull/44028

   ### SUMMARY
   
   `position_json` (the dashboard layout JSON) is a plain column with no
   coordination against the `dashboard_slices` association. A chart hard-deleted
   while it was a live dashboard member leaves a layout node referencing a 
chart id
   that no longer resolves to any `Slice` row, and a restore-with-skips 
reproduces
   the same divergence — a layout tile pointing at a chart absent from `slices`.
   The divergence is invisible to the API consumer and accumulates: every save
   writes `meta.uuid = None` into the dangling slot.
   
   This reconciles `position_json` against membership **on write**. A `CHART` 
layout
   node whose `chartId` does not resolve to any `Slice` row is swapped in place 
for
   a markdown placeholder — keeping the node id, children, and geometry and
   replacing only `type`+`meta`. This mirrors the frontend 
`swapUnreachableChartSlots`
   (#41551) and the runtime `MissingChart` placeholder, **persisting** what the
   client already renders rather than re-deriving it on every load.
   
   Key design decisions:
   
   - **Soft-deleted members are preserved.** The dangling check keys on 
"chartId not
     resolvable to any `Slice` row **with the soft-delete visibility filter
     bypassed**", so a soft-deleted (recoverable) member — whose 
`dashboard_slices`
     junction row still exists — is never treated as dangling. Only 
genuinely-absent
     (hard-deleted / never-existed) references are repaired. The existing
     `test_set_dash_metadata_preserves_soft_deleted_members` stays green.
   - **Both write paths are covered.** `DashboardDAO.set_dash_metadata` 
(positions in
     `json_metadata`, reusing its already-resolved `uuid_map`) and the raw
     `position_json`-field PUT in `UpdateDashboardCommand.run` (which resolves
     membership itself via `reconcile_position_json`).
   - **The placeholder text is a plain literal, not `gettext`.** 
`position_json` is
     persisted, shared data rendered verbatim to every viewer, so translating 
it to
     the saving user's request locale would bake one language into content 
shown to
     everyone. Per-viewer localization stays the frontend's render-time job.
   
   Refs: sc-115325. Found during the #42469 (version-restore) review but
   pre-existing product-wide behavior, not a restore regression.
   
   ### BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
   
   No UI screenshot — this is a backend reconcile. Behaviorally: a dashboard 
whose
   layout references a hard-deleted chart previously kept a broken `CHART` tile
   (`meta.uuid = null`) accumulating on every save; after this change, saving 
swaps
   that slot to a markdown "This chart no longer exists." tile (the same 
content the
   frontend already renders at read time for such a slot).
   
   ### TESTING INSTRUCTIONS
   
   1. Create a dashboard with a chart, then hard-delete the chart.
   2. Save the dashboard (PUT). Observe the layout node for the deleted chart 
is now
      a markdown placeholder rather than a dangling `CHART` node, and
      `position_json` no longer references the absent chart id.
   3. Repeat with a **soft-deleted** chart — its tile must be preserved (still a
      `CHART` node with its uuid), confirming recoverable members are not 
repaired.
   
   Automated: `pytest tests/unit_tests/dao/dashboard_test.py` (both write paths,
   live + soft-deleted + genuinely-absent chartIds, non-dict-`position_json` 
guard,
   and a reverted-fix control) and
   `pytest tests/integration_tests/dashboards/api_tests.py -k 
reconciles_dangling`
   (a PUT end-to-end pinning that `run()` invokes the reconcile).
   
   ### ADDITIONAL INFORMATION
   
   - [ ] Has associated issue:
   - [ ] Required feature flags:
   - [x] Changes UI
   - [ ] Includes DB Migration (follow approval process in 
[SIP-59](https://github.com/apache/superset/issues/13351))
     - [ ] Migration is atomic, supports rollback & is backwards-compatible
     - [ ] Confirm DB migration upgrade and downgrade tested
     - [ ] Runtime estimates and downtime expectations provided
   - [ ] Introduces new feature or API
   - [ ] Removes existing feature or API
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to