Skip to content

fix(dashboard): save an unreadable layout chart as a missing-chart tile - #45800

Draft
mikebridge wants to merge 14 commits into
apache:masterfrom
mikebridge:sc-129218-layout-unreadable-placeholder
Draft

mikebridge wants to merge 14 commits into
apache:masterfrom
mikebridge:sc-129218-layout-unreadable-placeholder

Conversation

@mikebridge

Copy link
Copy Markdown
Contributor

SUMMARY

Saving a dashboard layout that contains a tile for a chart you can't read no longer fails. The chart isn't attached to the dashboard, and its tile is saved as the same "This chart no longer exists." placeholder a deleted chart gets. This typically happens with a stale tile left after a chart was detached. Because the result is identical, a save doesn't reveal whether a chart you can't read exists.

This is stacked on #45538 and changes its behaviour for that one case. #45538 returns 422 for such a chart; this PR leaves it unlinked as a placeholder instead.

  • Unchanged: charts already on the dashboard (archived ones included) and a copy's source charts aren't checked, and readable charts are linked as in fix(dashboard): validate dashboard layout chart references on the server #45538.
  • Copy with charts: a readable chart outside the source still refuses the copy with 422.
  • Routes covered: dashboard PUT (both json_metadata.positions and raw position_json), POST, and the copy endpoint, which the MCP duplicate_dashboard tool also uses.

Stacked on #45538. Until that merges, this PR also shows #45538's commits; the change here is the last two commits. Master will be merged in once #45538 lands.

TESTING INSTRUCTIONS

  • pytest tests/unit_tests/dao/dashboard_test.py tests/unit_tests/mcp_service/dashboard/tool/test_duplicate_dashboard.py
  • pytest tests/integration_tests/dashboards/api_tests.py -k "layout_chart_access or matches_missing_chart or layout_detached_chart"

ADDITIONAL INFORMATION

mikebridge and others added 13 commits October 20, 2026 12:06
A dashboard save, create or copy rebuilds chart membership from the layout
it is sent. Only link a chart the layout adds if the caller can read it;
charts already on the dashboard (archived ones included) and, for a copy,
the source dashboard's charts stay accepted, so existing saves keep working.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The update command refuses a layout chart the caller cannot read in
validate(), before tab and native-filter removals deactivate reports
and email their owners. The editors and viewers of the charts being
checked are loaded in two queries instead of per chart. Tests cover a
chart the caller reads through a granted dataset but does not edit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… charts in the layout check

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…art-ids

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…art-ids

Keep both sides in set_dash_metadata: install the stored membership
baseline, refuse unreadable new layout charts against the stored
dashboard_slices rows, then keep archived members the layout omits.
Kept archived charts are limited to stored members.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Being archived does not exempt a chart from the layout access check: an
archived chart that is not already a member and that the caller cannot
read is refused, and the stored membership is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Saving a dashboard layout that adds a chart the user cannot read is refused on update, create and copy. Existing members, archived ones included, and a copy's source charts are not checked.
A dashboard save, create or copy whose layout adds a chart the caller cannot read no longer fails with 422. The chart is left unlinked and its tile is saved as the same placeholder a nonexistent chart gets, so the response does not reveal that the chart exists. Existing members, archived ones included, and a copy's source charts are not checked.

Copying with charts handles a tile for a chart outside the source the same way when the caller cannot read it; a readable one still refuses the copy.
A PUT that sends only position_json kept a tile for an existing chart the caller cannot read, while a nonexistent chart's tile became the missing-chart placeholder, so reading the layout back revealed which charts exist. The raw path and the copy-with-charts layout now repair a non-member chart the caller cannot read like a missing one.

The copy-with-charts handling moves into that shared repair, which also covers every save route with a parity test.
@netlify

netlify Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 1b7bb16
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6ae6b042e505a321d1b9bc09
😎 Deploy Preview https://deploy-preview-45800--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@codecov

codecov Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.76%. Comparing base (7519fa8) to head (1b7bb16).

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #45800   +/-   ##
=======================================
  Coverage   84.76%   84.76%           
=======================================
  Files        3072     3072           
  Lines      206119   206118    -1     
  Branches    48539    48539           
=======================================
+ Hits       174718   174719    +1     
+ Misses      28101    28100    -1     
+ Partials     3300     3299    -1     
Flag Coverage Δ
hive 34.49% <25.00%> (+<0.01%) ⬆️
mysql 52.60% <100.00%> (+<0.01%) ⬆️
postgres 52.62% <100.00%> (+<0.01%) ⬆️
presto 36.22% <25.00%> (+<0.01%) ⬆️
python 87.76% <100.00%> (+<0.01%) ⬆️
sqlite 52.37% <100.00%> (+<0.01%) ⬆️
unit 82.54% <93.75%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions Bot added the requires:rebase Requires rebasing on top of current master label Oct 30, 2026
@github-actions github-actions Bot removed the requires:rebase Requires rebasing on top of current master label Nov 1, 2026

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants