Skip to content

Commit

Permalink
[Bug] Fix text alignment and enable href in Button (#881)
Browse files Browse the repository at this point in the history
  • Loading branch information
huong-li-nguyen authored Nov 19, 2024
1 parent 2b656bf commit 597e2c0
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 70 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!--
A new scriv changelog fragment.
Uncomment the section that is right (remove the HTML comment wrapper).
-->

<!--
### Highlights ✨
- A bullet item for the Highlights ✨ category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Removed
- A bullet item for the Removed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))
-->

### Added

- Enable `href` inside `vm.Button`. ([#881](https://github.com/mckinsey/vizro/pull/881))

<!--
### Changed
- A bullet item for the Changed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Deprecated
- A bullet item for the Deprecated category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Fixed
- A bullet item for the Fixed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Security
- A bullet item for the Security category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX. ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 changes: 63 additions & 10 deletions vizro-core/docs/pages/user-guides/card-button.md
Original file line number Diff line number Diff line change
Expand Up @@ -482,9 +482,12 @@ img[src*="#my-image"] {

### Create a navigation card

This section describes how to use the [`Card`][vizro.models.Card] component to create a navigation card. To configure the navigation panel on the left hand side of the screen, refer to the [guide on navigation](navigation.md).
This section describes how to use the [`Card`][vizro.models.Card] component to create a navigation card,
enabling users to navigate to another page by clicking on the card area.

A navigation card enables you to navigate to a different page via a click on the card area.
For a button-style link navigation component, see the [separate guide on creating a link button](#create-a-link-button).
To configure the navigation panel on the left hand side of the screen, refer to the
[separate guide on navigation](navigation.md).

To create a navigation card:

Expand Down Expand Up @@ -587,21 +590,70 @@ For detailed examples on how to create a KPI card, refer to the [figure user gui

## Buttons

To enhance dashboard interactions, you can use the [`Button`][vizro.models.Button] component to trigger any pre-defined
action functions such as exporting chart data. To use the currently available options for the [`Actions`][vizro.models.Action]
component, check out the [API reference][vizro.actions].
The Button component is commonly used for interactive dashboard interactions
such as form submissions, navigation links, and other action triggers.

To add a [`Button`][vizro.models.Button], insert it into the `components` argument of the
[`Page`][vizro.models.Page].

You can configure the `text` argument to alter the display text of the [`Button`][vizro.models.Button] and the
`actions` argument to define which action function should be executed on button click.

In the below example we show how to configure a button to export the filtered data of a target chart using
[export_data][vizro.actions.export_data], a pre-defined action function.
### Customize button text

You can configure the `text` argument to alter the display text of the [`Button`][vizro.models.Button].

!!! example "Button"
!!! example "Customize text"

=== "app.py"
```{.python pycafe-link}
import vizro.models as vm
from vizro import Vizro

page = vm.Page(
title="Button with text",
components=[vm.Button(text="I'm a button!")],
)

dashboard = vm.Dashboard(pages=[page])
Vizro().build(dashboard).run()
```
=== "app.yaml"
```yaml
# Still requires a .py to add data to the data manager and parse YAML configuration
# See from_yaml example
pages:
- components:
- type: button
text: I'm a button!
title: Button with text
```
=== "Result"
[![ButtonText]][ButtonText]

[ButtonText]: ../../assets/user_guides/components/button_text.png


### Create a link button

To navigate to a different page using a button with an anchor tag, assign an absolute or relative URL to the
`Button.href`.

```python
import vizro.models as vm

vm.Button(text="Leave us a star! ⭐", href="https://github.com/mckinsey/vizro")
```

### Attach an action

You can use the [`Button`][vizro.models.Button] to trigger predefined action functions, such as exporting data.
To explore the available options for [`Actions`][vizro.models.Action], refer to our [API reference][vizro.actions].
Use the `Button.actions` argument to specify which action function executes when the button is clicked.

The example below demonstrates how to configure a button to export the filtered data of a target chart using the
[export_data][vizro.actions.export_data] action function.


!!! example "Button with action"

=== "app.py"
```{.python pycafe-link}
Expand Down Expand Up @@ -681,6 +733,7 @@ In the below example we show how to configure a button to export the filtered da

[Button]: ../../assets/user_guides/components/button.png

### Use as a control
The [`Button`][vizro.models.Button] component is currently reserved to be used inside the main panel (right-side) of the dashboard.
However, there might be use cases where one would like to place the `Button` inside the control panel (left-side) with the other controls.

Expand Down
52 changes: 4 additions & 48 deletions vizro-core/examples/scratch_dev/app.py
Original file line number Diff line number Diff line change
@@ -1,59 +1,15 @@
"""Dev app to try things out."""

import pandas as pd
import plotly.graph_objects as go
import vizro.models as vm
import vizro.plotly.express as px
from vizro import Vizro
from vizro.models.types import capture


@capture("graph")
def lollipop(data_frame: pd.DataFrame, x: str, y: str):
"""Creates a lollipop chart using Plotly.
This function generates a scatter chart and then draws lines extending from each point to the x-axis.
Args:
data_frame (pd.DataFrame): The data source for the chart.
x (str): The column name to be used for the x-axis.
y (str): The column name to be used for the y-axis.
Returns:
go.Figure: : A Plotly Figure object representing the lollipop chart.
"""
fig = go.Figure()

# Draw points
fig.add_trace(
go.Scatter(
x=data_frame[x],
y=data_frame[y],
mode="markers",
marker=dict(color="#00b4ff", size=12),
)
)

for i in range(len(data_frame)):
fig.add_trace(
go.Scatter(
x=[0, data_frame[x].iloc[i]],
y=[data_frame[y].iloc[i], data_frame[y].iloc[i]],
mode="lines",
line=dict(color="#00b4ff", width=3),
)
)
fig.update_layout(showlegend=False)
return fig


gapminder = px.data.gapminder()


page = vm.Page(
title="Lollipop",
title="Button Styling",
layout=vm.Layout(grid=[[0, 1]]),
components=[
vm.Graph(figure=lollipop(gapminder.query("year == 2007 and gdpPercap > 36000"), y="country", x="gdpPercap"))
vm.Button(),
vm.Button(text="Take me home", href="/"),
],
)

Expand Down
4 changes: 1 addition & 3 deletions vizro-core/examples/visual-vocabulary/assets/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ img[src*="#chart-icon"] {
position: relative;
}

.code-clipboard-container .pycafe-link,
.code-clipboard-container .pycafe-link:focus {
line-height: unset;
.code-clipboard-container .pycafe-link {
margin-bottom: 12px;
}

Expand Down
6 changes: 6 additions & 0 deletions vizro-core/schemas/0.1.28.dev0.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,12 @@
"default": "Click me!",
"type": "string"
},
"href": {
"title": "Href",
"description": "URL (relative or absolute) to navigate to.",
"default": "",
"type": "string"
},
"actions": {
"title": "Actions",
"default": [],
Expand Down
9 changes: 8 additions & 1 deletion vizro-core/src/vizro/models/_components/button.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Literal

import dash_bootstrap_components as dbc
from dash import get_relative_path

try:
from pydantic.v1 import Field
Expand All @@ -24,11 +25,17 @@ class Button(VizroBaseModel):

type: Literal["button"] = "button"
text: str = Field("Click me!", description="Text to be displayed on button.")
href: str = Field("", description="URL (relative or absolute) to navigate to.")
actions: list[Action] = []

# Re-used validators
_set_actions = _action_validator_factory("n_clicks")

@_log_call
def build(self):
return dbc.Button(id=self.id, children=self.text)
return dbc.Button(
id=self.id,
children=self.text,
href=get_relative_path(self.href) if self.href.startswith("/") else self.href,
target="_top",
)
2 changes: 1 addition & 1 deletion vizro-core/src/vizro/static/css/vizro-bootstrap.min.css

Large diffs are not rendered by default.

31 changes: 25 additions & 6 deletions vizro-core/tests/unit/vizro/models/_components/test_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,28 @@ def test_create_default_button(self):
assert hasattr(button, "id")
assert button.type == "button"
assert button.text == "Click me!"
assert button.href == ""
assert button.actions == []

@pytest.mark.parametrize("text", ["Test", 123, 1.23, True, """# Header""", """<p>Hello </p>"""])
def test_create_button_with_optional(self, text):
button = vm.Button(text=text)
assert hasattr(button, "id")
@pytest.mark.parametrize(
"text, href",
[
("Test", "/page_1_reference"),
("Test", "https://www.google.de/"),
(123, "/"),
("""# Header""", "/"),
(1.23, "/"),
("""<p>Hello </p>""", "/"),
(True, "/"),
],
)
def test_create_button_with_optional(self, text, href):
button = vm.Button(id="button-id", text=text, href=href)

assert button.id == "button-id"
assert button.type == "button"
assert button.text == str(text)
assert button.href == href
assert button.actions == []

def test_set_action_via_validator(self):
Expand All @@ -33,7 +47,12 @@ def test_set_action_via_validator(self):


class TestBuildMethod:
def test_button_build(self):
def test_button_build_wo_href(self):
button = vm.Button(id="button_id", text="My text").build()
expected = dbc.Button(id="button_id", children="My text")
expected = dbc.Button(id="button_id", children="My text", href="", target="_top")
assert_component_equal(button, expected)

def test_button_build_with_href(self):
button = vm.Button(id="button_id", text="My text", href="https://www.google.com").build()
expected = dbc.Button(id="button_id", children="My text", href="https://www.google.com", target="_top")
assert_component_equal(button, expected)
2 changes: 1 addition & 1 deletion vizro-core/tests/unit/vizro/models/test_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def test_field_invalid_pages_empty_list(self):
vm.Dashboard(pages=[])

def test_field_invalid_pages_input_type(self):
with pytest.raises(ValidationError, match="4 validation errors for Dashboard"):
with pytest.raises(ValidationError, match="5 validation errors for Dashboard"):
vm.Dashboard(pages=[vm.Button()])

def test_field_invalid_theme_input_type(self, page_1):
Expand Down

0 comments on commit 597e2c0

Please sign in to comment.