-
Notifications
You must be signed in to change notification settings - Fork 14k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(native-filters): Add legacy (filter-box) to native filter migration script #23269
feat(native-filters): Add legacy (filter-box) to native filter migration script #23269
Conversation
9b605a2
to
74bb8af
Compare
superset.add_command(attribute) | ||
|
||
if isinstance(attribute, click.core.Group): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to ensure that group commands aren't added as a top-level command. Regrettably there's no way of inspecting a (sub-)command to see if it's part of a group, but given how groups are defined, i.e., prior to the sub-commands it seems valid to simply short circuit.
I sense the only other option is to remove the magic auto-detection logic and explicitly register all the commands.
@@ -131,7 +131,7 @@ def alter_positions( | |||
for value in position_json: | |||
if ( | |||
isinstance(value, dict) | |||
and value.get("meta") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not required per like #135.
@@ -131,7 +131,7 @@ def alter_positions( | |||
for value in position_json: | |||
if ( | |||
isinstance(value, dict) | |||
and value.get("meta") | |||
and value.get("type") == "CHART" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is needed given how as part of the migration we're temporarily storing the old chartId
in the metadata block for the new markdown elements (which serve as a replacement for the filter-box charts) as a way to revert.
Granted this is bastardizing the metadata somewhat, but it does seem prudent to also ensure that the type is CHART
prior to fetching the chartId
.
superset/dashboards/dao.py
Outdated
@@ -200,7 +200,7 @@ def set_dash_metadata( # pylint: disable=too-many-locals | |||
slice_ids = [ | |||
value.get("meta", {}).get("chartId") | |||
for value in positions.values() | |||
if isinstance(value, dict) | |||
if isinstance(value, dict) and value.get("type") == "CHART" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above. Without this logic, when editing a dashboard all the old filter-box charts would be re-added given that the markdown elements still contain the chartId
field.
from superset.models.slice import Slice | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def convert_filter_scopes( | ||
json_metadata: Dict[Any, Any], filters: List[Slice] | ||
json_metadata: Dict[Any, Any], filter_boxes: List[Slice] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renaming adds clarity as to which type of charts/slices these are.
superset/views/core.py
Outdated
if isinstance(value, dict) and value.get("meta", {}).get("chartId"): | ||
if ( | ||
isinstance(value, dict) | ||
and value.get("type") == "CHART" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above.
74bb8af
to
d0fadf2
Compare
d0fadf2
to
74e9e88
Compare
74e9e88
to
8668e65
Compare
Codecov Report
@@ Coverage Diff @@
## master #23269 +/- ##
==========================================
- Coverage 68.08% 67.88% -0.21%
==========================================
Files 1923 1924 +1
Lines 74135 74364 +229
Branches 8103 8103
==========================================
+ Hits 50478 50481 +3
- Misses 21580 21806 +226
Partials 2077 2077
Flags with carried forward coverage won't be shown. Click here to find out more.
📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
e5b2827
to
199cf9b
Compare
7e12073
to
6d7d740
Compare
6d7d740
to
52da5f0
Compare
52da5f0
to
8c140da
Compare
d7365e4
to
7ae7089
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the PR @john-bodley. I left some first-pass comments.
|
||
Even though both legacy and native filters can coexist the overall user experience (UX) | ||
is substandard as the already convoluted filter space becomes overly complex. After | ||
enabling the `DASHBOARD_NATIVE_FILTERS` it strongly advised to run the migration ASAP to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
enabling the `DASHBOARD_NATIVE_FILTERS` it strongly advised to run the migration ASAP to | |
enabling the `DASHBOARD_NATIVE_FILTERS` it's strongly advised to run the migration ASAP to |
|
||
- Replaces every filter-box chart within the dashboard with a markdown element which | ||
provides a link to the deprecated chart. This preserves the layout whilst simultaneously | ||
providing context to aid with owners review/verify said change. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
providing context to aid with owners review/verify said change. | |
providing context to help owners review/verify said change. |
command—which provides the option to target either specific dashboard(s) or all | ||
dashboards. Note this operation is irreversible. | ||
|
||
Specifically the command performs the following: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specifically the command performs the following: | |
Specifically, the command performs the following: |
Specifically the command performs the following: | ||
|
||
- Removes the temporary dashboard metadata. | ||
- Deletes the filter-box charts†. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Deletes the filter-box charts†. | |
- Deletes the filter-box charts associated with the dashboard†. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously I had logic which actually deleted all filter-box charts if the --all
option was included (irrespective of whether they were part of a dashboard) but later changed said logic.
@@ -40,12 +40,15 @@ click==8.0.4 | |||
# apache-superset | |||
# celery | |||
# click-didyoumean | |||
# click-option-group |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@john-bodley Should we consider the CLI a development tool and move these dependencies to requirements/development.txt
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@michael-s-molina I think the challenge with that is the superset
CLI will be borked even if you ran superset run
etc. Also as you can see there are other CLI dependencies (click-didyoumean
) which have been included in the base requirements.
multiple=True, | ||
type=int, | ||
) | ||
def upgrade( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you move each command into its own file? (upgrade.py
, downgrade.py
, cleanup.py
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These commands aren't significantly large (in terms of lines of code) combined with the fact that they're somewhat related, thus I think they can reside in the same file. This is somewhat akin to Alembic migrations where the upgrade
and downgrade
functions coexist.
if "filterType" in fltr: | ||
filter_by_key_and_field[key][field] = fltr | ||
|
||
# Ancestors of filter-box charts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you could extract some sub-functions to improve readability? I was thinking one function for assembling the filters and other for establishing the hierarchy. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@michael-s-molina I generally agree that long functions aren't great and though I took a pass at extracting this into sub functions the refactor wasn't great, i.e., assembling the filters really contains the hierarchical wiring.
I also previous refactored fetching the defaults into a function, but there needed to be lots of special case handling due to where/when the defaults were used, i.e., a filter_select
filter may require the time range/granularity but these defaults are at the chart rather than dashboard level.
The TL;DR is granted the formulation isn't great I sense it's acceptable, especially in the context of a migration.
@villebro I could use a second pair of eyes here if you have some time 👀 🙏🏼 |
a080803
to
2fdfe98
Compare
Thanks @michael-s-molina for the review. I've hopefully addressed your comments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
2fdfe98
to
0535b28
Compare
0535b28
to
a88e67a
Compare
…ion script (apache#23269) (cherry picked from commit d0fda60)
…ion script (apache#23269) (cherry picked from commit d0fda60)
SUMMARY
This PR addresses recommendation #6 in #14383.
Specifically it adds a new CLI group command—which behaves in the same vein as an Alembic migration—for allowing admins to upgrade/degrade dashboards with legacy filters (filter-box charts and filter scopes) to native filters. i.e.,
This document (included in the PR) outlines the specific logic of the script and what is expected from dashboard owners.
This logic is based on #16992 (specifically the filterboxMigrationHelper.ts file).
Though I'm relatively confident on the logic—I can't really grasp JavaScript—there are some differences between @graceguo-supercat's script and my logic which maybe @ktmud, @nytai, @rusackas, @villebro, et al. could review:
‡ Per here there's logic to fallback to the chart level
time_grain_sqla
if there's no dashboard level default, i.e.,however the prior
if (!isEmpty(dashboardDefaultValues)) {
condition would mean that the||
would never be evaluated. I sense this was an error with the previous implementation, i.e., the logic should have been,The same is true for the granularity_sqla column however the time_range column and value columns seem correct. Note in my current implementation I always fallback to the chart level default if not defined at the dashboard level.
BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
BEFORE
AFTER
TESTING INSTRUCTIONS
Tested somewhat extensively using the example datasets.
ADDITIONAL INFORMATION