Skip to content
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

Update to use dmc 0.15.1 #924

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions vizro-core/examples/dev/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -820,13 +820,13 @@ def multiple_cards(data_frame: pd.DataFrame, n_rows: Optional[int] = 1) -> html.

if __name__ == "__main__":
app = Vizro().build(dashboard)
app.dash.layout.children.append(
dbc.NavLink(
["Made with ", html.Img(src=get_asset_url("logo.svg"), id="banner", alt="Vizro logo"), "vizro"],
href="https://github.com/mckinsey/vizro",
target="_blank",
className="anchor-container",
)

banner = dbc.NavLink(
["Made with ", html.Img(src=get_asset_url("logo.svg"), id="banner", alt="Vizro logo"), "vizro"],
href="https://github.com/mckinsey/vizro",
target="_blank",
className="anchor-container",
)
app.dash.layout.children = [app.dash.layout.children, banner]
petar-qb marked this conversation as resolved.
Show resolved Hide resolved
server = app.dash.server
app.run()
2 changes: 1 addition & 1 deletion vizro-core/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ dependencies = [
"pandas>=2",
"plotly>=5.12.0",
"pydantic>=1.10.16", # must be synced with pre-commit mypy hook manually
"dash_mantine_components<0.13.0", # 0.13.0 is not compatible with 0.12,
"dash_mantine_components==0.15.1", # 0.13.0 is not compatible with 0.12,
petar-qb marked this conversation as resolved.
Show resolved Hide resolved
"flask_caching>=2",
"wrapt>=1",
"black",
Expand Down
10 changes: 10 additions & 0 deletions vizro-core/src/vizro/_vizro.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from typing import TYPE_CHECKING, TypedDict, cast

import dash
import dash_mantine_components as dmc
import plotly.io as pio
from dash.development.base_component import ComponentRegistry
from flask_caching import SimpleCache
Expand All @@ -17,6 +18,8 @@
from vizro.managers import data_manager, model_manager
from vizro.models import Dashboard, Filter

dash._dash_renderer._set_react_version("18.2.0")

petar-qb marked this conversation as resolved.
Show resolved Hide resolved
logger = logging.getLogger(__name__)

if TYPE_CHECKING:
Expand Down Expand Up @@ -49,6 +52,13 @@ def __init__(self, **kwargs):
use_pages=True,
)

# Ensure external_stylesheets is a list and append the additional stylesheet
external_stylesheets = self.dash.config.external_stylesheets
self.dash.config.external_stylesheets = (
external_stylesheets if isinstance(external_stylesheets, list) else [external_stylesheets]
)
petar-qb marked this conversation as resolved.
Show resolved Hide resolved
self.dash.config.external_stylesheets.append(dmc.styles.DATES)

# When Vizro is used as a framework, we want to include the library and framework resources.
# Dash serves resources in the order 1. external_stylesheets/scripts; 2. library resources from the
# ComponentRegistry; 3. resources added by append_css/scripts.
Expand Down
27 changes: 5 additions & 22 deletions vizro-core/src/vizro/models/_components/form/date_picker.py
petar-qb marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from pydantic import Field, PrivateAttr, validator


import datetime
from datetime import date

import dash_bootstrap_components as dbc
Expand Down Expand Up @@ -42,6 +41,8 @@ class DatePicker(VizroBaseModel):
max: Optional[date] = Field(None, description="End date for date picker.")
value: Optional[Union[list[date], date]] = Field(None, description="Default date for date picker")
title: str = Field("", description="Title to be displayed.")

# Could probably delete the `range` arg, but keeping it makes it backwards compatible
Copy link
Contributor

@huong-li-nguyen huong-li-nguyen Dec 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! The range argument is definitely a bit redundant if we ever want to introduce the type argument of the new dmc.DatePickerInput as well. Options would then include: "default", "range", "multiple" in which case this boolean argument doesn't make much sense as you could then also define it via the type directly, but probably better to keep it for backwards compatibility even though it might be double-defined then.

Let's leave it in for now and discuss when @antonymilne is back 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Antony previously mentioned the concept of a "multiple" option for the DatePicker in #318 (comment).

At this point, I believe we don't need to support the "multiple" mode yet, as it represents a niche use case. If we decide to implement this feature, we should also consider extending similar functionality to other components, such as vm.Slider. This would align with broader discussions about restructuring our components (See -> #318 (comment))).

For now, the range property seems to address the requirements effectively.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, perfect! I didn't know he commented on this already. Let's leave it as is then, and @AnnMarieW you could delete this line then: date_range_picker_kwargs = {"allowSingleDateInRange": True} if self.range else {}

I don't think it's needed anymore since that is controlled by the type argument now instead of allowSingleDateInRange

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should always include allowSingleDateInRange=True, in the dmc.DatePickerInput configuration. It will enable that a single date can be selected when range=True (so type="range"), and will have no effect when range=False (so type="default").

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see, but then let's specify it directly as allowSingleDateInRange=True instead of adding that line 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused by this - not sure what props to update 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All that is needed is to delete the following line:
date_range_picker_kwargs = {"allowSingleDateInRange": True} if self.range else {}

and insert allowSingleDateInRange: True directly to the dmc.DatePickerInput configuration like in this suggestion comment.

range: bool = Field(True, description="Boolean flag for displaying range picker.")
actions: list[Action] = []

Expand Down Expand Up @@ -71,33 +72,15 @@ def build(self):
output=output,
inputs=inputs,
)
# clientside callback is required as a workaround when the date-picker is overflowing its parent container
# if there is not enough space. Caused by another workaround for this issue:
# https://github.com/snehilvj/dash-mantine-components/issues/219
clientside_callback(
ClientsideFunction(namespace="date_picker", function_name="update_date_picker_position"),
output=Output(self.id, "dropdownPosition"),
inputs=Input(self.id, "n_clicks"),
)
petar-qb marked this conversation as resolved.
Show resolved Hide resolved

date_picker_class = dmc.DateRangePicker if self.range else dmc.DatePicker

# dropdownPosition must be set to bottom-start as a workaround for issue:
# https://github.com/snehilvj/dash-mantine-components/issues/219
# clearable must be set to False as a workaround for issue:
# https://github.com/snehilvj/dash-mantine-components/issues/212
# maxDate must be increased by one day, and later on disabledDates must be set as maxDate + 1 day
# as a workaround for issue: https://github.com/snehilvj/dash-mantine-components/issues/230
date_picker = date_picker_class(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Saw that all of these issues have been fixed in the mantine repository @AnnMarieW - this is amazing! 🥳

@nadijagraca @petar-qb - could you double-check manually if all of the issues we've faced initially are solved now? I remember for one of the bugs, we had to add the datepicker to the right side and then change screen sizes etc. I don't know if there were other scenarios like that which need manual checking. You will know best 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After some testing with various configuration inputs, I can say that all our previous workaround solutions are unnecessary as dmc.DatePickerInput handles them all internally 🎉 Here's the example of our workaround solutions.

  • maxDate=self.max + datetime.timedelta(days=1) if self.max else None,
  • dropdownPosition="bottom-start",
  • clearable=False,
  • disabledDates=self.max + datetime.timedelta(days=1) if self.max else None,

date_picker = dmc.DatePickerInput(
Copy link
Contributor

@petar-qb petar-qb Dec 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This suggestion is only used as a reference from another comment.

Suggested change
date_picker = dmc.DatePickerInput(
date_picker = dmc.DatePickerInput(
id=self.id,
minDate=self.min,
value=init_value,
maxDate=self.max,
persistence=True,
persistence_type="session",
type="range" if self.range else "default",
className="datepicker",
# removes the default red color for weekend days
styles={"day": {"color": "var(--mantine-color-text"}},
allowSingleDateInRange: True,
)

id=self.id,
minDate=self.min,
value=init_value,
maxDate=self.max + datetime.timedelta(days=1) if self.max else None,
maxDate=self.max,
persistence=True,
persistence_type="session",
dropdownPosition="bottom-start",
clearable=False,
disabledDates=self.max + datetime.timedelta(days=1) if self.max else None,
type="range" if self.range else "default",
className="datepicker",
**date_range_picker_kwargs,
petar-qb marked this conversation as resolved.
Show resolved Hide resolved
)
Expand Down
8 changes: 7 additions & 1 deletion vizro-core/src/vizro/models/_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import dash
import dash_bootstrap_components as dbc
import dash_mantine_components as dmc
import plotly.io as pio
from dash import (
ClientsideFunction,
Expand Down Expand Up @@ -156,7 +157,7 @@ def build(self):
State("collapsable-left-side", "is_open"),
)

return html.Div(
layout = html.Div(
id="dashboard-container",
children=[
html.Div(id="vizro_version", children=vizro.__version__, hidden=True),
Expand All @@ -171,6 +172,11 @@ def build(self):
dash.page_container,
],
)
return dmc.MantineProvider(
layout,
# Use the `theme` to style all Mantine components with a Vizro theme. For more info see https://www.dash-mantine-components.com/components/mantineprovider
# theme = {...}
)
petar-qb marked this conversation as resolved.
Show resolved Hide resolved

def _validate_logos(self):
logo_img = self._infer_image(filename="logo")
Expand Down
10 changes: 6 additions & 4 deletions vizro-core/src/vizro/static/js/models/dashboard.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
function update_dashboard_theme(theme_selector_checked) {
document.documentElement.setAttribute(
"data-bs-theme",
theme_selector_checked ? "light" : "dark",
);
const theme = theme_selector_checked ? "light" : "dark";

// Update theme attributes for Bootstrap and Mantine
document.documentElement.setAttribute("data-bs-theme", theme);
document.documentElement.setAttribute("data-mantine-color-scheme", theme);

return window.dash_clientside.no_update;
}

Expand Down
Loading