-
-
Notifications
You must be signed in to change notification settings - Fork 77
Updates the use of renderDashComponents to use ExternalWrapper when Dash 3 and falls back on dash-extensions for Dash 2
#531
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
Changes from 5 commits
aa99942
cb72f67
51df059
7161491
1ccae3d
e33570a
c51bd47
764df32
2208d9a
c72fc60
0b19eb1
1a444e0
899288c
e878be3
62d5b4b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,4 +4,5 @@ pytest<8.1.0 | |
| wheel | ||
| selenium<4.3.0 | ||
| black | ||
| build | ||
| build | ||
| dash-iconify | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,212 @@ | ||
| from dash import Dash, html, Output, Input, State, _dash_renderer, clientside_callback | ||
| import dash_mantine_components as dmc | ||
| from dash_iconify import DashIconify | ||
| from dash.testing.wait import until | ||
| import time | ||
|
|
||
| _dash_renderer._set_react_version("18.2.0") | ||
|
|
||
|
|
||
| def test_001oc_optional_components(dash_duo): | ||
| app = Dash(__name__) | ||
|
|
||
| min_step = 0 | ||
| max_step = 3 | ||
| active = 0 | ||
|
|
||
| layout = html.Div( | ||
| [ | ||
| dmc.Stepper( | ||
| id="stepper", | ||
| active=active, | ||
| children=[ | ||
| dmc.StepperStep( | ||
| label="Step 1", | ||
| description=html.Div(dmc.Button(id='test_button', children='test', disabled=True)), | ||
| children="Step 1", | ||
| ), | ||
| dmc.StepperStep( | ||
| label="Step 2", | ||
| description="Verify email", | ||
| children="Step 2", | ||
| ), | ||
| dmc.StepperStep( | ||
| label="Step 3", | ||
| description="Get full access", | ||
| children="Step 3", | ||
| ), | ||
| dmc.StepperCompleted( | ||
| children=dmc.Text( | ||
| "Completed, click back button to get to previous step", | ||
| ta="center", | ||
| ) | ||
| ), | ||
| ], | ||
| ), | ||
| dmc.Group( | ||
| justify="center", | ||
| mt="xl", | ||
| children=[ | ||
| dmc.Button("Back", id="previous-button", variant="default"), | ||
| dmc.Button("Next step", id="next-button"), | ||
| ], | ||
| ), | ||
| html.Div(id='output') | ||
| ] | ||
| ) | ||
|
|
||
| app.layout = dmc.MantineProvider(layout) | ||
|
|
||
| clientside_callback("""(n)=> { | ||
| if (n) { | ||
| return `clicked ${n} times` | ||
| } | ||
| }""", | ||
| Output('output', 'children'), | ||
| Input('test_button', 'n_clicks'), | ||
| prevent_initial_call=True, | ||
| suppress_callback_exceptions=True) | ||
|
|
||
| clientside_callback( | ||
| """(a) => { | ||
| return a !== 0 | ||
| }""", | ||
| Output('test_button', 'disabled'), | ||
| Input('stepper', 'active'), | ||
| suppress_callback_exceptions=True | ||
| ) | ||
|
|
||
| clientside_callback( | ||
| """(n, active) => n ? Math.max(active - 1, 0) : active""", | ||
| Output("stepper", "active", allow_duplicate=True), | ||
| Input("previous-button", "n_clicks"), | ||
| State("stepper", "active"), | ||
| prevent_initial_call=True, | ||
| ) | ||
|
|
||
| clientside_callback( | ||
| """(n, active) => n ? Math.min(active + 1, 2) : active""", | ||
| Output("stepper", "active", allow_duplicate=True), | ||
| Input("next-button", "n_clicks"), | ||
| State("stepper", "active"), | ||
| prevent_initial_call=True, | ||
| ) | ||
|
|
||
| dash_duo.start_server(app) | ||
|
|
||
| # Wait for the app to load | ||
| dash_duo.wait_for_text_to_equal("#test_button", "test") | ||
| assert dash_duo.find_element('#test_button').get_attribute('disabled') is None | ||
|
|
||
| step_buttons = dash_duo.find_elements("button.mantine-Stepper-step") | ||
| for i, btn in enumerate(step_buttons): | ||
| btn.click() | ||
| dash_duo.wait_for_text_to_equal("div.mantine-Stepper-content", f"Step {i + 1}") | ||
|
|
||
| dash_duo.find_element("#previous-button").click() | ||
| dash_duo.wait_for_text_to_equal("div.mantine-Stepper-content", "Step 2") | ||
|
|
||
| assert dash_duo.find_element('#test_button').get_attribute('disabled') == 'true' | ||
|
|
||
|
|
||
| dash_duo.find_element("#previous-button").click() | ||
| dash_duo.wait_for_text_to_equal("div.mantine-Stepper-content", "Step 1") | ||
|
|
||
| until(lambda: dash_duo.find_element('#test_button').get_attribute('disabled') is None, timeout=3) | ||
|
|
||
| for i in range(5): | ||
| dash_duo.find_element('#test_button').click() | ||
| dash_duo.wait_for_text_to_equal("#output", f"clicked {i+1} times") | ||
|
|
||
| assert dash_duo.get_logs() == [] | ||
|
|
||
| def test_002oc_optional_components(dash_duo): | ||
| ## tests async rendering and also compares after callbacks to the icon | ||
| styles_css = """ | ||
| .dmc-api-demo-root { | ||
| border: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4)); | ||
| padding: var(--mantine-spacing-xs) var(--mantine-spacing-sm); | ||
| border-radius: var(--mantine-radius-md); | ||
| font-weight: 500; | ||
| cursor: pointer; | ||
|
|
||
| &[data-checked] { | ||
| background-color: var(--mantine-color-blue-filled); | ||
| border-color: var(--mantine-color-blue-filled); | ||
| color: var(--mantine-color-white); | ||
| } | ||
| }""" | ||
|
|
||
| demo_py = """ | ||
| import dash_mantine_components as dmc | ||
|
|
||
| dmc.Checkbox( | ||
| classNames={"root": "dmc-api-demo-root"}, | ||
| label="Checkbox button", | ||
| w=180 | ||
| )""" | ||
|
|
||
|
|
||
| code = [ | ||
| { | ||
| "fileName": "demo.py", | ||
| "code": demo_py, | ||
| "language": "python", | ||
| "icon": DashIconify(icon="vscode-icons:file-type-reactts", width=20, id='test-0-icon'), | ||
| }, | ||
| { | ||
| "fileName": "styles.css", | ||
| "code":styles_css, | ||
| "language": "css", | ||
| "icon": DashIconify(icon="vscode-icons:file-type-css", width=20, id='test-1-icon'), | ||
| }, | ||
| ] | ||
|
|
||
|
|
||
| app = Dash(external_stylesheets=dmc.styles.ALL) | ||
|
|
||
|
|
||
| component = dmc.CodeHighlightTabs( | ||
| code=code, | ||
| withExpandButton=True, | ||
| expandCodeLabel="Show full code", | ||
| collapseCodeLabel="Show less", | ||
| defaultExpanded=False, | ||
| maxCollapsedHeight=100, | ||
| m="lg" | ||
| ) | ||
|
|
||
|
|
||
| app.layout = dmc.MantineProvider( | ||
| [component, | ||
| dmc.Button(id='test-0', children='Change Python Icon'), | ||
| dmc.Button(id='test-1', children='Change CSS Icon')], | ||
| id="mantine-provider", | ||
| forceColorScheme="light", | ||
| ) | ||
|
|
||
| for i in range(2): | ||
| clientside_callback( | ||
| """(n) => { | ||
| return 'dashicons:money-alt' | ||
| }""", | ||
| Output(f'test-{i}-icon', 'icon'), | ||
| Input(f'test-{i}', 'n_clicks'), | ||
| prevent_initial_call=True, | ||
| suppress_callback_exceptions=True | ||
| ) | ||
|
|
||
| dash_duo.start_server(app) | ||
|
|
||
| icons = dash_duo.find_elements('svg.iconify') | ||
|
|
||
| assert len(icons) == 2 | ||
|
|
||
| for i, x in enumerate(icons): | ||
| old_html = x.get_attribute('innerHTML') | ||
| dash_duo.find_element(f'#test-{i}').click() | ||
| if i: | ||
| until(lambda: dash_duo.find_element(f'svg.iconify:nth-child({i})').get_attribute('innerHTML') != old_html, timeout=3) | ||
| else: | ||
| until(lambda: dash_duo.find_element(f'svg.iconify:first-child').get_attribute('innerHTML') != old_html, | ||
| timeout=3) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
for i in range(len(icons)):
icon_selector = f'svg.iconify:nth-child({i + 1})'
old_html = dash_duo.find_element(icon_selector).get_attribute('innerHTML')
dash_duo.find_element(f'#test-{i}').click()
until(lambda: dash_duo.find_element(icon_selector).get_attribute('innerHTML') != old_html, timeout=3)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not valid. I tried it...
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. > document.querySelector('div:first-child')===document.querySelector('div:nth-child(1)')
<- true
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Of course, dash iconify doesnt pass the id to the component...
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alexcjohnson what about what I just used? I wrapped the icons in divs and used that to target the components.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regardless as written this test is looking at the first one in both
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I updated the test, that's what I was referring to. 🙂 Might be able to do without the time.sleep.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's nice and clear 😎 |
||
Uh oh!
There was an error while loading. Please reload this page.