-
Notifications
You must be signed in to change notification settings - Fork 220
[Feat] Add page-level reset controls button #1437
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
base: main
Are you sure you want to change the base?
Conversation
View the example dashboards of the current commit live on PyCafe ☕ 🚀Updated on: 2025-10-06 13:15:21 UTC Compare the examples using the commit's wheel file vs the latest released version: vizro-core/examples/scratch_devView with commit's wheel vs View with latest release vizro-core/examples/dev/View with commit's wheel vs View with latest release vizro-core/examples/visual-vocabulary/View with commit's wheel vs View with latest release vizro-core/examples/tutorial/ |
vizro_controls_store_data = { | ||
page.id: { | ||
control.id: { | ||
"selectorId": control.selector.id, | ||
"originalValue": control.selector.value, | ||
} | ||
for control in cast( | ||
Iterable[ControlType], | ||
[*model_manager._get_models(Parameter, page), *model_manager._get_models(Filter, page)], | ||
) | ||
} | ||
for page in self.pages | ||
} | ||
|
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.
I was able skip the page.id
level of hierarchy and to move this to page.py
(similarly how the page_id_store
is added/handled), but I left it here on the dashboard level as this will be reused when someone starts working on the cross-page actions.
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.
The vizro_controls_store
structure will likely be adjusted later as we add more reset buttons (container-level, dashboard-level, figure-level) or cross-page actions. A flat structure is a strong candidate to avoid deep hierarchies.
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.
Is the current structure where page.id
is a top-level key done like this just so that reset_page_controls
can easily look up all the controls on that page?
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.
Yes exactly. However I think that the structure we be adjusted later to something like:
{
"control_1_id": {
"selector_id": "selector_control_1_id",
"page_id": "my_homepage",
"parent_container_id": "container_id"
"original_value": ["1", "2"],
"current_value": ["1," "2", "3"],
...
},
"control_2_id": ...
}
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.
I just refactored the code and switched to the format suggested in the previous comment. 😃
has_page_controls = bool( | ||
[*model_manager._get_models(Parameter, page), *model_manager._get_models(Filter, page)] | ||
) | ||
|
||
# Page header controls that appear on the right side of the header. | ||
header_controls = html.Div( | ||
id="header-controls", | ||
children=[ | ||
dcc.Loading( | ||
id="action-progress-indicator", | ||
delay_show=300, | ||
delay_hide=300, | ||
custom_spinner=html.Span( | ||
className="material-symbols-outlined progress-indicator", | ||
# Keep "progress_activity" children so the CSS spinner can render/display correctly. | ||
children="progress_activity", | ||
), | ||
# Placeholder div is added as used as target from actions to show loading indicator. | ||
children=html.Div(id="action-progress-indicator-placeholder"), | ||
), | ||
# Show reset button in header when page controls exist but control panel does not exist | ||
reset_page_controls_btn if has_page_controls and _all_hidden(control_panel) else None, | ||
dbc.Switch( | ||
id="theme-selector", | ||
value=self.theme == "vizro_light", | ||
persistence=True, | ||
persistence_type="session", | ||
), | ||
], | ||
) | ||
|
||
# Apply different container position logic based on condition | ||
if _all_hidden(header_left_content + header_right_content): | ||
page_header_content.append(header_controls) | ||
else: | ||
header_right_content.append(header_controls) | ||
|
||
# Show reset button in the control panel when page controls and control panel exist | ||
if has_page_controls and not _all_hidden(control_panel): | ||
control_panel.children.append(reset_page_controls_btn) | ||
|
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 code covers all the cases when:
- controls exist in the controls panel => reset button is in the control panel
- controls exist but hidden => reset button is in the header (page/dashboard depending on whether the dashboard header exist)
- there's no controls on the page => reset button is not added
) | ||
|
||
if page_controls: | ||
# TODO-AV2 D: Think about merging this with the URL callback when start working on cross-page actions. |
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.
The comment added so i can be cross linked.
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.
linked here -> https://github.com/McK-Internal/vizro-internal/issues/2054
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.
Wow, this looks great! Definitely it gets the preliminary "carry on as planned" from me 👍 The code looks really nice and simple overall and not too horribly hacky like we had worried. Great scratch_dev
app for testing everything too 💯
Please could you quickly update https://github.com/McK-Internal/vizro-internal/issues/1719 to briefly explain what the approach is here and what alternatives we dismissed and why (can be very rough notes).
On the styles: I like the rectangular text button but maybe also with the icon in it - what does that look like?
I'm not a big fan of the button moving next to the theme switcher but if others prefer it then it's ok. The alternative would be to keep the button in the same place and just have a big empty left sidebar for it which is also not great I know. If we do move the button next to the theme switcher then maybe in that case I would make it just a circular button with icon so it's more in scale with the theme switcher. wdyt now we have a real live example to look at @huong-li-nguyen? Happy to go with whatever you prefer here.
Should we explain this feature in docs?
Yes, just a couple of sentences in controls.md should be good, no need for anything else.
Should I adjust all docs screenshots so they contain reset button?
No, that is just too painful.
vizro_controls_store_data = { | ||
page.id: { | ||
control.id: { | ||
"selectorId": control.selector.id, | ||
"originalValue": control.selector.value, | ||
} | ||
for control in cast( | ||
Iterable[ControlType], | ||
[*model_manager._get_models(Parameter, page), *model_manager._get_models(Filter, page)], | ||
) | ||
} | ||
for page in self.pages | ||
} | ||
|
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.
Is the current structure where page.id
is a top-level key done like this just so that reset_page_controls
can easily look up all the controls on that page?
I just pushed some changes and you can see how it looks like now in the third screen-recording in the PR description. So, the current implementation adds:
I like the current solution. What do you think @huong-li-nguyen? |
The only thing I’m currently uncertain about is whether we should commit to adding the reset button by default without an easy way of removing it. We plan (not immediately but it should be an ultimate goal) to expand the reset-controls functionality beyond the page level by adding it to the dashboard, container, control, and source figure levels. However, making it a default behaviour (“set in stone”) might feel too intrusive for Vizro users, even now when it’s only applied at the page level. I’d recommend an opt-in / opt-out approach instead, so users can easily enable or disable the button at different levels. Here’s my suggested API design: vm.Dashboard(show_reset_controls_button: bool = False)
vm.Page(show_reset_controls_button: bool = True) # Maybe even set it to False by default.. or not
vm.Container(show_reset_controls_button: bool = False)
vm.Graph(show_reset_controls_button: bool = False)
vm.Filter(show_reset_control_button: bool = False) In that case I would expose additional I'd love to get you opinions on this: @antonymilne @huong-li-nguyen @Joseph-Perkins 🙏 |
) | ||
|
||
|
||
def set_selector_default_value(control_selector: SelectorType) -> None: |
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.
Another approach to calculating selectors' default values:
- During the creation of
vizro_controls_store
(dashboard.build
), calculate the default value for all selectors usingget_dict_options_and_default
and other relevant methods for min/max. - Implement a getter property (e.g
get_default_value
) for all selectors to access their current value.
NB: Default selector values cannot be calculated during the initialisation phase because options/min/max could be determined in the Filter.pre_build
phase.
I found the current implementation good enough but we should rethink the solution when we deal with the https://github.com/McK-Internal/vizro-internal/issues/1554
Closes https://github.com/McK-Internal/vizro-internal/issues/2191
Description
Draft PR opened without fixing/writing any tests or docs.
TODO
Screenshot
Screen.Recording.2025-10-06.at.15.47.32.mov
Screen.Recording.2025-10-06.at.15.49.51.mov
Screen.Recording.2025-10-08.at.11.25.13.mov
Notice
I acknowledge and agree that, by checking this box and clicking "Submit Pull Request":