Skip to content

Dash 3.0 feedback #3148

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

Closed
AnnMarieW opened this issue Feb 3, 2025 · 31 comments
Closed

Dash 3.0 feedback #3148

AnnMarieW opened this issue Feb 3, 2025 · 31 comments
Assignees
Labels
P1 needed for current cycle

Comments

@AnnMarieW
Copy link
Collaborator

AnnMarieW commented Feb 3, 2025

Thanks for making the dash 3.0 pre-release available. 🎉
Just a couple questions and comments:

  • Are you still planning on removing the _timestamp props? remove _timestamp properties #3055

  • The dcc.Dropdown is still using defaultProps which is causing a warning in the console. There are other console warning with dcc.Dropdown, but those aren't new, just wondering if there are plans to fix those too.

  • In dcc.Loading, the custom_component shows a typehints warning if you use components other than html components.

Feature request:

  • In DMC, we are relying on renderDashComponents from the dash-extensions.js library to render components as props defined in children. For more details see: Improve performance of context components re-rendering #3066 (comment). Philippe mentioned he could add a render(component, path) to dash_component_api quite easily, but wanted to wait for another release.
@T4rk1n
Copy link
Contributor

T4rk1n commented Feb 6, 2025

Are you still planning on removing the _timestamp props? #3055

No

The dcc.Dropdown is still using defaultProps which is causing a warning in the console. There are other console warning with dcc.Dropdown, but those aren't new, just wondering if there are plans to fix those too.

I noticed that one and fixed it in #3141 for RC2

In dcc.Loading, the custom_component shows a typehints warning if you use components other than html components.

There is no custom_component prop in the dcc.Loading, do you mean custom_spinner or target_components ?
custom_spinner worked for me in vscode and target_components is a dictionary type.

In DMC, we are relying on renderDashComponents from the dash-extensions.js library to render components as props defined in children. For more details see: #3066 (comment). Philippe mentioned he could add a render(component, path) to dash_component_api quite easily, but wanted to wait for another release.

Yes this can be added later in a 3.1 or later, probably best to think about the API properly as I think it could also be used to render components from clientside callbacks.

@AnnMarieW
Copy link
Collaborator Author

Sorry, I meant the custom_spinner in the dcc.Loading Here's what it looks like for me in Pycharm:

DMC or DBC componets:
Image

Image

html component is fine - no error:

Image

@BSd3v
Copy link
Contributor

BSd3v commented Feb 8, 2025

@T4rk1n,

I was testing things out for dmc, dash 3 and dag. I ran into an issue when trying to load custom components into the grid.

Image

This issue happened with both dmc and dash components trying to display in the grid.

I believe if you were to provide a response for the useLoading() to return false if the useDashContext doesnt find anything, this would alleviate this issue.

@AnnMarieW
Copy link
Collaborator Author

It would be helpful to have a better error message that included how to fix it (ie "use app.run() instead")

Traceback (most recent call last):
File "/home/amw/PycharmProjects/HelloDash/app.py", line 70, in
app.run_server(debug=True)
AttributeError: 'Dash' object has no attribute 'run_server'

@T4rk1n
Copy link
Contributor

T4rk1n commented Feb 12, 2025

I believe if you were to provide a response for the useLoading() to return false if the useDashContext doesnt find anything, this would alleviate this issue.

I think this is because the context is not found, by creating the component without the DashWrapper.

I'll add a warning and return {}, then you can use ctx.?useLoading() and also the renderDashComponents so this case can be fixed.

@BSd3v
Copy link
Contributor

BSd3v commented Feb 13, 2025

Another thing that I've noticed, when importing * from dash. The clientside_callback isnt available.

@T4rk1n
Copy link
Contributor

T4rk1n commented Feb 13, 2025

Another thing that I've noticed, when importing * from dash. The clientside_callback isnt available.

Thanks fixed in #3164

@BSd3v
Copy link
Contributor

BSd3v commented Feb 20, 2025

Would it be possible to add something like this, where we can run one function to populate components in dash?

import {dissoc, has, includes, isEmpty, isNil, mergeRight, type} from "ramda";

function stringifyId(id) {
    if (typeof id !== 'object') {
        return id;
    }
    const stringifyVal = v => (v && v.wild) || JSON.stringify(v);
    const parts = Object.keys(id)
        .sort()
        .map(k => JSON.stringify(k) + ':' + stringifyVal(id[k]));
    return '{' + parts.join(',') + '}';
}

const SIMPLE_COMPONENT_TYPES = ['String', 'Number', 'Null', 'Boolean'];
const isSimpleComponent = component => includes(type(component), SIMPLE_COMPONENT_TYPES);

function renderDashComponent(component, index=null, basePath=[]) {
    const ExternalWrapper = (window as any).dash_component_api.ExternalWrapper
    // Nothing to render.
    if (isNil(component) || isEmpty(component)) {
        return null;
    }

    // Simple stuff such as strings.
    if (isSimpleComponent(component)) {
        return component
    }
    // Array of stuff.
    if(Array.isArray(component)){
        return component.map((item, i) => renderDashComponent(item, i, [...basePath, i]))
    }
    // If we get here, we need to render an actual Dash component.
    const {type, namespace} = component
    const props = dissoc('children', component.props);
    const children = component.props.children
    // Make sure that id is a string.
    if (props.id) {
        props.id = stringifyId(props?.id);
    }

    React.useEffect(() => {
        (window as any).dash_clientside.set_props(basePath, {children})
    }, [])

    // Merge props.
    const allProps = {...props, componentType: type, componentNamespace: namespace,
        componentPath: [...basePath], key: (index || Math.random().toString(36).substr(2, 9))}
    // Render the component.
    return (<ExternalWrapper {...allProps} />)
}

function renderDashComponents(props, propsToRender, basePath){
    for (let i = 0; i < propsToRender.length; i++) {
        let key = propsToRender[i];
        if (props.hasOwnProperty(key)){
            // Create a new path for this specific component rendering
            const newBasePath = [...basePath, "props", key];
            props[key] = renderDashComponent(props[key], null, newBasePath);
        }
    }
    return props
}

^ the above code was adjusted from @emilhe dash-extensions-js. One thing to note, the ExternalWrapper doesnt innately work with the children, thus I had to pass back as set_props for dash to render the children like normal.

Additionally, could you expose stringifyId on the dash_component_api or dash_clientside so that we wouldnt need to declare it and it would be maintained automatically?

@AnnMarieW
Copy link
Collaborator Author

👍 👍 Two thumbs up for adding the renderDashComponents function #3148 (comment)

Exposing the stringifyId is also a great idea!

@T4rk1n
Copy link
Contributor

T4rk1n commented Feb 20, 2025

I added in #3175 for RC3

  • stringifyId
  • fix children
  • Better message for run_server removal

Thanks for the feedback.

@BSd3v
Copy link
Contributor

BSd3v commented Feb 21, 2025

@T4rk1n

Any thoughts on the renderDashComponent(s)?

Or just keep it as something people have to add-on?

@AnnMarieW
Copy link
Collaborator Author

The new devtools in 3.0.0rc3 is pretty cool!
However it takes up a lot of space, and is quite distracting in dark mode. Is there a way to toggle it to make it smaller?
Also in dark mode, you can't read the "Callback" label unless you hover over it.

Image

@BSd3v
Copy link
Contributor

BSd3v commented Feb 22, 2025

Hey @T4rk1n,

For the ExternalWrapper or more technically the stringifyId, the id can not exist. If you dont pass an id to the ExternalWrapper it blows up the console.


Please also make it so that we can simply do this:

const RenderDashComponent = (component, basePath) => {
    const ExternalWrapper = window.dash_component_api?.ExternalWrapper
    var wrapperprops = {
          componentPath: [...basePath, 'external'],
          component // {type, namespace, props}
      }
    
    return createElement(ExternalWrapper, wrapperprops)
}

@gvwilson
Copy link
Contributor

@marthacryan please have a look at the dark mode issue that @AnnMarieW reported - thanks.

@ndrezn
Copy link
Member

ndrezn commented Feb 24, 2025

@AnnMarieW w.r.t. minimizing space, we found that it was difficult to clearly convey information with the closed dev tools UI (new update notification) while minimized so went with the default open.

However we also explored a pattern where it would be full-width on the footer but not overlay on top of the app, ensuring no app real estate would be covered.

We've had feedback from a couple people that it takes up too much space as-is, though.

Here is a comparison of a few different patterns:

With ability to minimize

Image

Full width

This appears to be floating in the mock but it would not be a floating footer when implemented
Image

I'm hesitant to make significant UI changes at this point in the dev process to avoid delaying 3.0 further but would love your feedback regardless: We could switch to e.g. the full footer mode in 3.1.

@BSd3v
Copy link
Contributor

BSd3v commented Feb 24, 2025

@ndrezn,

I think if full, you should make it a real footer instead of overlaying the app, this way you can at least scroll to things that would be hidden if needed...

As far as minimized view, I vote num 3

@ndrezn
Copy link
Member

ndrezn commented Feb 24, 2025

@BSd3v yes, it'd be a real footer, no overlay.

To be clear from a design perspective internally we lean footer over any of the minimized options. We also prefer the always-expanded option to any of the minimized options.

@AnnMarieW
Copy link
Collaborator Author

@ndrezn
I think I'd prefer a footer as well, but hard to say without trying it. I'd want to make sure it would be at the bottom of the viewport for minimal example apps that don't have a lot of content.

I also really like that the version number is included—it will be very helpful for debugging and especially useful when assisting people who are new to Dash.

@AnnMarieW
Copy link
Collaborator Author

@T4rk1n
I just noticed that dcc.Mardown generates a warning in the console - which is weird because it's not a function component.

Warning: v: Support for defaultProps will be removed from function components in a future major release. Use JavaScript default parameters instead. Error Component Stack


from dash import Dash, dcc

app=Dash()
app.layout = dcc.Markdown("I have a console warning")

if __name__ == "__main__":
    app.run(debug=True)



@T4rk1n
Copy link
Contributor

T4rk1n commented Feb 27, 2025

I just noticed that dcc.Mardown generates a warning in the console - which is weird because it's not a function component.

It's the ReactMarkdown component from the library, we use a really old version of react-markdown and the newer versions has changed the API as such it doesn't work. We will need to update the package before react 18.

@gvwilson
Copy link
Contributor

Can we do that update as part of the 3.0 release or should we leave it for 3.1?

@T4rk1n
Copy link
Contributor

T4rk1n commented Feb 27, 2025

Can we do that update as part of the 3.0 release or should we leave it for 3.1

It should be included but we need to make sure it works with highlighting and mathjax. Also maybe test on the docs since that is used in example.

@gvwilson gvwilson added the P1 needed for current cycle label Feb 28, 2025
@BSd3v
Copy link
Contributor

BSd3v commented Mar 3, 2025

Running into an issue when trying to perform them in dash 3rc3:

import dash_mantine_components as dmc
from dash import Dash, _dash_renderer, callback, Output, Input, clientside_callback
from dash_iconify import DashIconify

_dash_renderer._set_react_version("18.2.0")
app = Dash(external_stylesheets=dmc.styles.ALL)

app.layout = dmc.MantineProvider(
    children=[
        dmc.NotificationProvider(),
        dmc.Affix(id='notify-container', position={"bottom": 20, "right": 20}),
        dmc.Button("Load Data", id="show-notification")
    ],
)


@callback(
    Output("notify-container", "children"),
    Input("show-notification", "n_clicks"),
    prevent_initial_call=True,
)
def notify(n):
    nf = dmc.Notification(
        id="my-notification",
        title="Appointment booked",
        message="Your appointment has been schedueled successfully",
        color="green",
        loading=False,
        action="show",
        autoClose=2000,
        icon=DashIconify(icon="akar-icons:circle-check"),
    )
    return nf


clientside_callback("""
    (c) => {
        setTimeout(() => dash_clientside.set_props('notify-container', {children: ''}), 300)
    }""",
    Input('show-notification', 'n_clicks'))

if __name__ == "__main__":
    app.run(debug=True)

Image

https://github.com/plotly/dash/blob/dash-3.0/dash/dash-renderer/src/wrapper/selectors.ts#L7C1-L26C1


dash=3.0.0rc3
dash-mantine-components=1.0.0rc1

@tcbegley
Copy link
Contributor

tcbegley commented Mar 3, 2025

In dash==3.0.0rc3 I can't seem to select the top option in a dcc.Dropdown

from dash import Dash, Input, Output, dcc, html

app = Dash(__name__)

app.layout = html.Div(
    [
        dcc.Dropdown(
            id="dropdown",
            options=[
                {"label": city, "value": city}
                for city in ["New York City", "Montréal", "San Francisco"]
            ],
            value="New York City",
        ),
        html.Div(id="output"),
    ]
)


@app.callback(Output("output", "children"), [Input("dropdown", "value")])
def callback(value):
    return f"You have selected {value}"


if __name__ == "__main__":
    app.run(debug=True)

Image

@AnnMarieW
Copy link
Collaborator Author

In dash==3.0.0rc3 I can't seem to select the top option in a dcc.Dropdown

To narrow it down - you can't select whatever is set initially in the value prop

@T4rk1n
Copy link
Contributor

T4rk1n commented Mar 4, 2025

To narrow it down - you can't select whatever is set initially in the value prop

Fixed in rc4

@gvwilson
Copy link
Contributor

gvwilson commented Mar 6, 2025

@T4rk1n please file separate issues for the pieces of this that are still unsolved and then close this one - thank you.

@T4rk1n
Copy link
Contributor

T4rk1n commented Mar 6, 2025

I opened #3198 and #3199 with the feedback left from this thread, as this issue is quite long we can open new issues for new feedback on dash 3.0

@T4rk1n T4rk1n closed this as completed Mar 6, 2025
@gvwilson
Copy link
Contributor

gvwilson commented Mar 6, 2025

thank you @T4rk1n

@BSd3v
Copy link
Contributor

BSd3v commented Mar 6, 2025

Can we get the changes to the dev UI as an issue too? Right now... its just so much room at the bottom and interferes with notifications. Or is someone already working on this adjustment?

@gvwilson
Copy link
Contributor

gvwilson commented Mar 6, 2025

@BSd3v please go ahead and file that one and tag me - thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P1 needed for current cycle
Projects
None yet
Development

No branches or pull requests

6 participants