Skip to content

Commit 27795b7

Browse files
committed
Add disclaimer functionality to DataUIManager; enable collapsible disclaimer card in sidebar.
1 parent 99d2a03 commit 27795b7

1 file changed

Lines changed: 95 additions & 10 deletions

File tree

dvue/dataui.py

Lines changed: 95 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,24 @@
4242
from .utils import full_stack
4343
from .catalog import DataCatalog, DataReference, CatalogView # noqa: F401 – exposed for subclasses
4444

45+
# ---------------------------------------------------------------------------
46+
# Standard DWR disclaimer — import and assign to disclaimer_text on any
47+
# DataUIManager subclass to display it in the sidebar.
48+
# ---------------------------------------------------------------------------
49+
DWR_DISCLAIMER_TEXT = (
50+
"All information provided by the Department of Water Resources on its Web "
51+
"pages and Internet sites is made available to provide immediate access for "
52+
"the convenience of interested persons. While the Department believes the "
53+
"information to be reliable, human or mechanical error remains a "
54+
"possibility. Therefore, the Department does not guarantee the accuracy, "
55+
"completeness, timeliness, or correct sequencing of the information. "
56+
"Neither the Department of Water Resources nor any of the sources of the "
57+
"information shall be responsible for any errors or omissions, or for the "
58+
"use or results obtained from the use of this information. Other specific "
59+
"cautionary notices may be included on other Web pages maintained by the "
60+
"Department."
61+
)
62+
4563
# setup logger
4664
logger = logging.getLogger(__name__)
4765
logger.setLevel(logging.INFO)
@@ -309,8 +327,21 @@ class DataUIManager(DataProvider):
309327
* :meth:`get_widgets`
310328
* :meth:`get_data_actions`
311329
* :meth:`get_no_selection_message`
330+
* ``disclaimer_text`` param — set to any string to show a collapsible
331+
Disclaimer card at the bottom of the sidebar (use ``DWR_DISCLAIMER_TEXT``
332+
for the standard DWR disclaimer).
312333
"""
313334

335+
disclaimer_text = param.String(
336+
default=None,
337+
allow_None=True,
338+
doc=(
339+
"Text for a collapsible Disclaimer card shown at the bottom of the "
340+
"sidebar. Set to DWR_DISCLAIMER_TEXT for the standard DWR disclaimer, "
341+
"or any other string for a custom notice. Leave None to omit."
342+
),
343+
)
344+
314345
@classmethod
315346
def help(cls):
316347
"""
@@ -416,13 +447,18 @@ def get_map_option_widgets(self):
416447
return None
417448

418449
def get_sidebar_disclaimer(self):
419-
"""Return a Panel pane (or plain string) to display at the bottom of the
420-
sidebar, or ``None`` (default) to add nothing.
450+
"""Return a Panel pane with disclaimer content for the modal dialog,
451+
or ``None`` (default) to add nothing.
421452
422-
Override in a subclass to inject a data-source disclaimer, terms of
423-
use notice, or any other footer content.
453+
Set the ``disclaimer_text`` param to have it rendered automatically,
454+
or override this method to return a custom Panel component.
424455
"""
425-
return None
456+
if not self.disclaimer_text:
457+
return None
458+
return pn.pane.Markdown(
459+
f"## Disclaimer\n\n{self.disclaimer_text}",
460+
sizing_mode="stretch_width",
461+
)
426462

427463
def get_data_actions(self) -> list:
428464
"""Return a list of default data actions. Override to customize available actions."""
@@ -902,6 +938,7 @@ def create_data_table(self, dfs):
902938

903939
self._display_panel = pn.Row(sizing_mode="stretch_both")
904940
self._action_panel = pn.Row()
941+
self._tab_count = 0
905942
actions = self._dataui_manager.get_data_actions()
906943

907944
if actions:
@@ -956,6 +993,39 @@ def about_callback(event):
956993
about_btn.on_click(about_callback)
957994
return about_btn
958995

996+
def create_disclaimer_button(self, template, disclaimer_modal_content):
997+
"""Return a button that swaps the modal to the disclaimer text and opens it."""
998+
disclaimer_btn = pn.widgets.Button(
999+
name="Disclaimer", button_type="light", icon="alert-circle"
1000+
)
1001+
1002+
def disclaimer_callback(event):
1003+
template.modal.clear()
1004+
template.modal.append(disclaimer_modal_content)
1005+
template.open_modal()
1006+
1007+
disclaimer_btn.on_click(disclaimer_callback)
1008+
return disclaimer_btn
1009+
1010+
def add_header_buttons(self, template):
1011+
"""Add About (and optionally Disclaimer) buttons to *template*'s header.
1012+
1013+
Use this when DataUI is embedded inside an outer template that supplies
1014+
its own header — the buttons will close over the correct *template* so
1015+
modals open on the servable outer template rather than the inner one
1016+
returned by :meth:`create_view`.
1017+
"""
1018+
about_button = self.create_about_button(template)
1019+
disclaimer_content = self._dataui_manager.get_sidebar_disclaimer()
1020+
if disclaimer_content is not None:
1021+
disclaimer_button = self.create_disclaimer_button(template, disclaimer_content)
1022+
template.header.append(
1023+
pn.Row(pn.layout.HSpacer(), disclaimer_button, about_button)
1024+
)
1025+
else:
1026+
template.header.append(pn.Row(pn.layout.HSpacer(), about_button))
1027+
template.modal.append(self.get_about_text())
1028+
9591029
def _create_main_view(self):
9601030
"""Create the main view content based on the current view_type"""
9611031
if self.view_type == "table":
@@ -992,6 +1062,19 @@ def hide_progress(self):
9921062
self.progress_bar.value = 0
9931063
self.progress_bar.indeterminate = False
9941064

1065+
def show_in_display_panel(self, title, content):
1066+
"""Add *content* as a closable tab in the display panel."""
1067+
if len(self._display_panel.objects) > 0 and isinstance(
1068+
self._display_panel.objects[0], pn.Tabs
1069+
):
1070+
tabs = self._display_panel.objects[0]
1071+
tabs.append((title, content))
1072+
tabs.active = len(tabs) - 1
1073+
else:
1074+
self._display_panel.objects = [
1075+
pn.Tabs((title, content), closable=True)
1076+
]
1077+
9951078
def show_map_in_display_panel(self, event):
9961079
"""Display the map in the display panel area as a closable tab"""
9971080
try:
@@ -1207,11 +1290,8 @@ def _map_callback(
12071290
sidebar_view = pn.Column(
12081291
pn.Tabs(("Options", control_widgets), ("Table Options", table_options)),
12091292
self.progress_bar,
1293+
sizing_mode="stretch_both",
12101294
)
1211-
# Append optional disclaimer to the bottom of the sidebar.
1212-
disclaimer = self._dataui_manager.get_sidebar_disclaimer()
1213-
if disclaimer is not None:
1214-
sidebar_view.append(disclaimer)
12151295
# Create view navigation buttons.
12161296
# Nav bar is placed inside _main_view (not in template.header) so it
12171297
# is part of template.main and remains visible when DataUI is embedded
@@ -1236,7 +1316,12 @@ def _map_callback(
12361316

12371317
# About button only in the header (visible in standalone use).
12381318
about_button = self.create_about_button(template)
1239-
template.header.append(pn.Row(pn.layout.HSpacer(), about_button))
1319+
disclaimer_text = self._dataui_manager.get_sidebar_disclaimer()
1320+
if disclaimer_text is not None:
1321+
disclaimer_button = self.create_disclaimer_button(template, disclaimer_text)
1322+
template.header.append(pn.Row(pn.layout.HSpacer(), disclaimer_button, about_button))
1323+
else:
1324+
template.header.append(pn.Row(pn.layout.HSpacer(), about_button))
12401325
template.main.append(self._main_view)
12411326

12421327
# Adding about button

0 commit comments

Comments
 (0)