dashui

DashUI — shared ipywidgets component library for the Dashlibs suite. Import from here in any dash-* package instead of duplicating widget code.

 1"""
 2DashUI — shared ipywidgets component library for the Dashlibs suite.
 3Import from here in any dash-* package instead of duplicating widget code.
 4"""
 5from dashui.components import (
 6    SourceSelector,
 7    action_button,
 8    card,
 9    header,
10    html,
11    output_panel,
12    running_list,
13    section,
14    source_selector,
15    status_line,
16)
17from dashui.schema import list_columns, list_columns_safe
18from dashui.theme import (
19    BORDER,
20    CARD,
21    DANGER,
22    FONT_MONO,
23    FONT_SANS,
24    MUTED,
25    PRIMARY,
26    SUCCESS,
27    WARNING,
28    accent,
29)
30
31__version__ = "0.1.3"
32__all__ = [
33    "SourceSelector",
34    "action_button",
35    "card",
36    "header",
37    "html",
38    "output_panel",
39    "running_list",
40    "section",
41    "source_selector",
42    "status_line",
43    "list_columns",
44    "list_columns_safe",
45    "accent",
46    "PRIMARY",
47    "SUCCESS",
48    "DANGER",
49    "WARNING",
50    "BORDER",
51    "CARD",
52    "MUTED",
53    "FONT_SANS",
54    "FONT_MONO",
55]
@dataclass
class SourceSelector:
132@dataclass
133class SourceSelector:
134    """
135    The UC Table / DataFrame variable / SQL Query picker used by every
136    Dashlibs UI that reads from Databricks.
137
138    Usage::
139        src = source_selector()
140        ui = card([src.toggle, src.box, ...])
141        kind, value = src.value()
142    """
143    toggle: object
144    box: object
145    table_input: object
146    df_input: object
147    sql_input: object
148
149    def value(self) -> tuple[str, str]:
150        """Returns (kind, value) where kind is 'table' | 'dataframe' | 'sql'."""
151        if self.toggle.value == "UC Table":
152            return "table", self.table_input.value.strip()
153        if self.toggle.value == "DataFrame variable":
154            return "dataframe", self.df_input.value.strip()
155        return "sql", self.sql_input.value.strip()
156
157    def resolve_df(self):
158        """Resolve the selected source to a Spark DataFrame (for direct use in core classes)."""
159        kind, value = self.value()
160        if kind == "dataframe":
161            import IPython
162            shell = IPython.get_ipython()
163            df = shell.user_ns.get(value) if shell else None
164            if df is None:
165                raise ValueError(f"Variable '{value}' not found")
166            return df
167        from pyspark.sql import SparkSession
168        spark = SparkSession.getActiveSession()
169        if kind == "table":
170            return spark.table(value)
171        return spark.sql(value)

The UC Table / DataFrame variable / SQL Query picker used by every Dashlibs UI that reads from Databricks.

Usage:: src = source_selector() ui = card([src.toggle, src.box, ...]) kind, value = src.value()

SourceSelector( toggle: object, box: object, table_input: object, df_input: object, sql_input: object)
toggle: object
box: object
table_input: object
df_input: object
sql_input: object
def value(self) -> tuple[str, str]:
149    def value(self) -> tuple[str, str]:
150        """Returns (kind, value) where kind is 'table' | 'dataframe' | 'sql'."""
151        if self.toggle.value == "UC Table":
152            return "table", self.table_input.value.strip()
153        if self.toggle.value == "DataFrame variable":
154            return "dataframe", self.df_input.value.strip()
155        return "sql", self.sql_input.value.strip()

Returns (kind, value) where kind is 'table' | 'dataframe' | 'sql'.

def resolve_df(self):
157    def resolve_df(self):
158        """Resolve the selected source to a Spark DataFrame (for direct use in core classes)."""
159        kind, value = self.value()
160        if kind == "dataframe":
161            import IPython
162            shell = IPython.get_ipython()
163            df = shell.user_ns.get(value) if shell else None
164            if df is None:
165                raise ValueError(f"Variable '{value}' not found")
166            return df
167        from pyspark.sql import SparkSession
168        spark = SparkSession.getActiveSession()
169        if kind == "table":
170            return spark.table(value)
171        return spark.sql(value)

Resolve the selected source to a Spark DataFrame (for direct use in core classes).

def action_button(text: str, style: str = 'primary', emoji: str = ''):
194def action_button(text: str, style: str = "primary", emoji: str = ""):
195    """style in primary|success|warning|danger|info — matches the datapal-access button variants."""
196    w = _require_widgets()
197    label = f"{emoji} {text}".strip()
198    btn = w.Button(description=label, layout=w.Layout(height="40px", padding="0 16px"))
199    btn.add_class(f"dashui-btn-{style or 'default'}")
200    return btn

style in primary|success|warning|danger|info — matches the datapal-access button variants.

def card(children, padding: str = '20px'):
120def card(children, padding: str = "20px"):
121    """Bordered, shadowed VBox container — the outer shell for every launch() UI."""
122    w = _require_widgets()
123    global _STYLE_INJECTED
124    body = [_global_style(), *children] if not _STYLE_INJECTED else list(children)
125    _STYLE_INJECTED = True
126    box = w.VBox(body, layout=w.Layout(padding=padding))
127    box.add_class("dashui-card")
128    box.add_class("dashui-root")
129    return box

Bordered, shadowed VBox container — the outer shell for every launch() UI.

def html(text: str):
49def html(text: str):
50    w = _require_widgets()
51    return w.HTML(text)
def output_panel():
203def output_panel():
204    """Standard scrollable output area for run/profile results and errors."""
205    w = _require_widgets()
206    out = w.Output(layout=w.Layout(padding="12px"))
207    out.add_class("dashui-output")
208    return out

Standard scrollable output area for run/profile results and errors.

def running_list(formatter):
211def running_list(formatter):
212    """
213    A live-updating numbered list display, the pattern used for 'added entities'
214    / 'added relationships' style accumulators.
215
216    Usage::
217        items = []
218        out, render = running_list(lambda i, item: f"{i}. {item['name']}")
219        items.append({"name": "Customer"})
220        render(items)
221    """
222    w = _require_widgets()
223    out = w.Output(layout=w.Layout(padding="8px 12px"))
224    out.add_class("dashui-output")
225
226    def render(items: list):
227        with out:
228            out.clear_output()
229            for i, item in enumerate(items, 1):
230                print(formatter(i, item))
231
232    return out, render

A live-updating numbered list display, the pattern used for 'added entities' / 'added relationships' style accumulators.

Usage:: items = [] out, render = running_list(lambda i, item: f"{i}. {item['name']}") items.append({"name": "Customer"}) render(items)

def section(title: str):
108def section(title: str):
109    """Step/section divider, styled like the datapal-access card label convention."""
110    return html(f"<div class='dashui-section'>{title}</div>")

Step/section divider, styled like the datapal-access card label convention.

def source_selector(label: str = 'Source:') -> SourceSelector:
174def source_selector(label: str = "Source:") -> SourceSelector:
175    w = _require_widgets()
176    toggle = w.ToggleButtons(options=["UC Table", "DataFrame variable", "SQL Query"], description=label)
177    table_input = w.Text(placeholder="catalog.schema.table", description="Table:")
178    df_input = w.Text(placeholder="df", description="Variable:")
179    sql_input = w.Textarea(placeholder="SELECT * FROM ...", description="SQL:", rows=3)
180    box = w.VBox([table_input])
181
182    def on_change(change):
183        if change["new"] == "UC Table":
184            box.children = [table_input]
185        elif change["new"] == "DataFrame variable":
186            box.children = [df_input]
187        else:
188            box.children = [sql_input]
189
190    toggle.observe(on_change, names="value")
191    return SourceSelector(toggle, box, table_input, df_input, sql_input)
def status_line(text: str, kind: str = 'info'):
113def status_line(text: str, kind: str = "info"):
114    """One-line colored status message: kind in success|error|warning|info."""
115    color = {"success": SUCCESS, "error": DANGER, "warning": WARNING, "info": MUTED_FOREGROUND}.get(kind, MUTED_FOREGROUND)
116    prefix = {"success": "✅", "error": "❌", "warning": "⚠️", "info": "ℹ️"}.get(kind, "")
117    return html(f"<span style='color:{color};font-family:{FONT_SANS}'>{prefix} {text}</span>")

One-line colored status message: kind in success|error|warning|info.

def list_columns(table: str) -> list[str]:
 6def list_columns(table: str) -> list[str]:
 7    """Return column names for a UC table, without loading any data."""
 8    from pyspark.sql import SparkSession
 9    spark = SparkSession.getActiveSession()
10    return [f.name for f in spark.table(table).schema.fields]

Return column names for a UC table, without loading any data.

def list_columns_safe(table: str) -> list[str]:
13def list_columns_safe(table: str) -> list[str]:
14    """Like list_columns, but returns [] instead of raising — for UI dropdowns."""
15    try:
16        return list_columns(table)
17    except Exception:
18        return []

Like list_columns, but returns [] instead of raising — for UI dropdowns.

def accent(library: str) -> str:
57def accent(library: str) -> str:
58    """Look up the accent color for a Dashlibs package name (e.g. 'dashsynthetic')."""
59    return ACCENTS.get(library, ACCENTS["default"])

Look up the accent color for a Dashlibs package name (e.g. 'dashsynthetic').

PRIMARY = '#2A9D90'
SUCCESS = '#29A36A'
DANGER = '#DC2828'
WARNING = '#F59F0A'
BORDER = '#DAE0E7'
CARD = '#FFFFFF'
MUTED = '#F0F2F4'
FONT_SANS = "'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif"
FONT_MONO = "'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace"