Skip to content

Commit 13beafa

Browse files
Hans Kallekleivanders-kiaer
Hans Kallekleiv
authored andcommitted
Use urls instead of tabs for main layout
1 parent f1af19a commit 13beafa

File tree

5 files changed

+103
-69
lines changed

5 files changed

+103
-69
lines changed

CHANGELOG.md

+13
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [UNRELEASED] - YYYY-MM-DD
8+
9+
### Changed
10+
11+
- [#230](https://github.com/equinor/webviz-config/pull/230) - Instead of using
12+
`dcc.Tabs` to give the impression of a "multi page app", webviz now uses `dcc.Link` and
13+
`dcc.Location`. This has two main advantages: Big applications can have significantly
14+
faster loading time, as only callbacks on selected "page" fire initially. In addition,
15+
the user can navigate with forward/backward buttons in browser, as well as getting
16+
an URL they can share with other in order to point them to the correct "page". Plugin
17+
authors should check that persistence is set to `session` on Dash components they use
18+
if they wan't user selections to remain across "page" changes.
19+
720
## [0.1.4] - 2020-09-24
821

922
### Added

tests/test_portable.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,11 @@ def test_portable(dash_duo, tmp_path):
2525
# Start and test app
2626
dash_duo.start_server(app)
2727
for page in [
28-
"markdown_example",
29-
"table_example",
30-
"pdf_example",
31-
"syntax_highlighting_example",
32-
"plot_a_table",
33-
"last_page",
28+
"markdown-example",
29+
"table-example",
30+
"pdf-example",
31+
"syntax-highlighting-example",
32+
"plot-a-table",
3433
]:
3534
dash_duo.wait_for_element(f"#{page}").click()
3635
assert dash_duo.get_logs() == [], "browser console should contain no error"

webviz_config/_config_parser.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -195,10 +195,10 @@ def check_for_tabs_in_file(path: pathlib.Path) -> None:
195195

196196
def _generate_page_id(self, title: str) -> str:
197197
"""From the user given title, this function provides a unique
198-
human readable page id, not already present in self._page_ids
198+
human readable page id, not already present in `self._page_ids`.
199199
"""
200200

201-
base_id = re.sub("[^-a-z0-9_]+", "", title.lower().replace(" ", "_"))
201+
base_id = re.sub("[^-a-z0-9_]+", "", title.lower().replace(" ", "-"))
202202

203203
page_id = base_id
204204

+35-27
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
div.styledLogo.tab {
1+
.styledLogo {
22
border: none;
33
background: transparent;
44
outline: none;
@@ -8,7 +8,7 @@ div.styledLogo.tab {
88
padding: 20px 30px;
99
}
1010

11-
div.styledButton.tab {
11+
.styledButton {
1212
border: none;
1313
background: transparent;
1414
outline: none;
@@ -26,31 +26,47 @@ div.styledButton.tab {
2626
border-bottom: 1px solid white;
2727
}
2828

29-
div.styledButton.tab:hover {
29+
.styledButton:hover {
3030
color: var(--menuLinkHoverColor);
3131
background-color: var(--menuLinkBackgroundHover);
3232
}
3333

34-
div.selectedButton.tab--selected {
34+
.selectedButton--selected {
3535
color: var(--menuLinkColorSelected);
3636
background-color: var(--menuLinkBackgroundSelected);
3737
}
3838

39-
div.pageWrapper.tab-content {
39+
.pageWrapper {
4040
display: flex;
4141
flex-direction: column;
4242
width: 100%;
4343
margin: 20px;
4444
}
4545

4646
.layoutWrapper {
47+
display: flex;
48+
flex-direction: row;
4749
width: 100%;
4850
}
51+
.sideWrapper {
52+
display: flex;
53+
flex: 1;
54+
flex-direction: column;
55+
overflow-x: hidden;
56+
overflow-y: scroll;
57+
height: 100vh;
58+
min-width: 30rem;
59+
scrollbar-width: thin;
60+
scrollbar-color: var(--menuBackground) var(--menuBackground); /* thumb and track color */
61+
}
4962

50-
.wrapper {
63+
.pageContent {
5164
display: flex;
65+
flex: 8;
66+
flex-direction: column;
5267
height: 100%;
5368
width: 100%;
69+
padding: 15px;
5470
}
5571

5672
.logoWrapper {
@@ -60,55 +76,47 @@ div.pageWrapper.tab-content {
6076
align-items: center;
6177
}
6278

63-
.sideBar {
64-
overflow-x: hidden;
65-
overflow-y: scroll;
66-
height: 100vh;
67-
min-width: 30rem;
68-
scrollbar-width: thin;
69-
scrollbar-color: var(--menuBackground) var(--menuBackground); /* thumb and track color */
70-
}
71-
7279
@media (min-width: 800px) {
73-
.sideBar {
80+
.sideWrapper {
7481
width: 30rem;
7582
}
7683
}
7784

78-
.sideBar:hover {
85+
.sideWrapper:hover {
7986
scrollbar-color: var(--menuLinkColor) var(--menuBackground); /* thumb and track color */
8087
}
8188

82-
.sideBar::-webkit-scrollbar
89+
.sideWrapper::-webkit-scrollbar
8390
{
8491
width: 3px;
8592
background-color:var(--menuBackground);
8693
}
8794

88-
.sideBar::-webkit-scrollbar-track
95+
.sideWrapper::-webkit-scrollbar-track
8996
{
9097
-webkit-box-shadow: inset 0 0 3px var(--menuBackground);
9198
background-color: var(--menuBackground);
9299
}
93100

94-
.sideBar:hover::-webkit-scrollbar-track
101+
.sideWrapper:hover::-webkit-scrollbar-track
95102
{
96103
-webkit-box-shadow: inset 0 0 3px var(--menuLinkBackgroundHover);
97-
98104
background-color: var(--menuBackground);
99105
}
100106

101-
.sideBar::-webkit-scrollbar-thumb
107+
.sideWrapper::-webkit-scrollbar-thumb
102108
{
103109
background-color: var(--menuBackground);
104110
}
105111

106-
.sideBar:hover::-webkit-scrollbar-thumb
112+
.sideWrapper:hover::-webkit-scrollbar-thumb
107113
{
108114
background-color: var(--menuLinkColor);
109115
}
110116

111-
112-
/* Needed to override border for the last tab */
113-
#last_page {border: none!important;} /* csslint allow: known-properties, important */
114-
#logo {padding:50px!important; border: none!important;max-width: 100%; height:auto;} /* csslint allow: known-properties, important */
117+
#logo {
118+
padding: 50px;
119+
border: none;
120+
max-width: 100%;
121+
height: auto;
122+
}

webviz_config/templates/webviz_template.py.jinja2

+48-34
Original file line numberDiff line numberDiff line change
@@ -76,40 +76,54 @@ if {{ not portable }} and not webviz_config.is_reload_process():
7676
# from the child/restart/reload process.
7777
app.layout = html.Div()
7878
else:
79-
app.layout = dcc.Tabs(
80-
parent_className="layoutWrapper",
81-
content_className="pageWrapper",
82-
className="sideBar",
83-
vertical=True,
84-
children=[
85-
{% for page in pages %}
86-
dcc.Tab(
87-
{%- if loop.first -%}
88-
id="logo",
89-
className="styledLogo",
90-
{%- else -%}
91-
{%- if loop.last -%}
92-
id="last_page",
93-
{%- else -%}
94-
id="{{page.id}}",
95-
{%- endif -%}
96-
label="{{page.title}}",
97-
selected_className="selectedButton",
98-
className="styledButton",
99-
{%- endif -%}
100-
children=[
101-
{% for content in page.content -%}
102-
{%- if content is string -%}
103-
dcc.Markdown(r"""{{ content }}""")
104-
{%- else -%}
105-
{{ content._call_signature[0] }}.{{ content._call_signature[1] }}
106-
{%- endif -%}
107-
{{- "" if loop.last else ","}}
108-
{% endfor -%}
109-
],
110-
) {{- "" if loop.last else "," -}}
111-
{% endfor %}],
112-
)
79+
page_content = {}
80+
{% for page in pages %}
81+
page_content["{{page.id}}"] = [
82+
{% for content in page.content -%}
83+
{%- if content is string -%}
84+
dcc.Markdown(r"""{{ content }}""")
85+
{%- else -%}
86+
{{ content._call_signature[0] }}.{{ content._call_signature[1] }}
87+
{%- endif -%}
88+
{{- "" if loop.last else ","}}
89+
{% endfor -%}
90+
]
91+
{% endfor %}
92+
app.layout = html.Div(
93+
className="layoutWrapper",
94+
children=[html.Div(
95+
children=[dcc.Location(
96+
id='url', refresh=True),
97+
html.Div(
98+
className="sideWrapper",
99+
children=[
100+
{% for page in pages %}
101+
dcc.Link(
102+
{%- if loop.first -%}
103+
"",
104+
id="logo",
105+
className="styledLogo",
106+
href="/",
107+
{%- else -%}
108+
"{{page.title}}",
109+
className="styledButton",
110+
id="{{page.id}}",
111+
href="/{{page.id}}",
112+
{%- endif -%}
113+
)
114+
{{- "" if loop.last else "," -}}
115+
{% endfor %}
116+
])]),
117+
html.Div(className="pageContent", id="page-content")])
118+
119+
120+
@app.callback(dash.dependencies.Output("page-content", "children"),
121+
dash.dependencies.Input("url", "pathname"))
122+
def update_page(pathname):
123+
pathname = pathname.replace("/", "")
124+
if not pathname:
125+
pathname = "front-page"
126+
return page_content.get(pathname, "Error 404 - Oooppss... Page not found.")
113127

114128
{{ "WEBVIZ_ASSETS.directly_host_assets(app)" if not portable else ""}}
115129

0 commit comments

Comments
 (0)