|
7 | 7 | from hotdata_runtime import HotdataClient, QueryResult, workspace_health_lines |
8 | 8 |
|
9 | 9 |
|
10 | | -def _option_map_with_unique_labels( |
11 | | - pairs: list[tuple[str, str]], |
12 | | -) -> dict[str, str]: |
13 | | - counts: dict[str, int] = {} |
14 | | - options: dict[str, str] = {} |
15 | | - for label, value in pairs: |
16 | | - count = counts.get(label, 0) |
17 | | - counts[label] = count + 1 |
18 | | - key = label if count == 0 else f"{label} ({count + 1})" |
19 | | - options[key] = value |
20 | | - return options |
21 | | - |
22 | | - |
23 | 10 | def query_result( |
24 | 11 | result: QueryResult, |
25 | 12 | *, |
@@ -72,32 +59,71 @@ class RecentResults: |
72 | 59 | def __init__(self, client: HotdataClient, *, limit: int = 50) -> None: |
73 | 60 | self._client = client |
74 | 61 | self._results = client.list_recent_results(limit=limit, offset=0) |
75 | | - option_pairs = [ |
76 | | - (f"{r.created_at} · {r.status} · {r.result_id}", r.result_id) |
| 62 | + self._rows: list[dict[str, object]] = [ |
| 63 | + { |
| 64 | + "created_at": r.created_at, |
| 65 | + "status": r.status, |
| 66 | + "result_id": r.result_id, |
| 67 | + } |
77 | 68 | for r in self._results |
78 | 69 | ] |
79 | | - options = _option_map_with_unique_labels(option_pairs) |
80 | | - self.pick = mo.ui.dropdown( |
81 | | - options=options or {"(no results)": ""}, |
82 | | - label="Recent results", |
83 | | - full_width=True, |
| 70 | + self.table = ( |
| 71 | + mo.ui.table( |
| 72 | + self._rows, |
| 73 | + label="Recent results", |
| 74 | + pagination=True, |
| 75 | + page_size=min(10, limit), |
| 76 | + selection="single", |
| 77 | + max_height=320, |
| 78 | + ) |
| 79 | + if self._rows |
| 80 | + else None |
84 | 81 | ) |
85 | 82 |
|
86 | 83 | @property |
87 | 84 | def selected_result_id(self) -> str | None: |
88 | | - v = self.pick.value |
89 | | - return v if v else None |
| 85 | + if self.table is None: |
| 86 | + return None |
| 87 | + selected = self.table.value |
| 88 | + if not selected: |
| 89 | + return None |
| 90 | + row = selected[0] |
| 91 | + if not isinstance(row, dict): |
| 92 | + return None |
| 93 | + rid = row.get("result_id") |
| 94 | + return rid if rid else None |
90 | 95 |
|
91 | 96 | @property |
92 | 97 | def result(self) -> QueryResult: |
93 | 98 | rid = self.selected_result_id |
94 | | - mo.stop(rid is None, mo.md("Pick a result id to load.")) |
| 99 | + mo.stop(rid is None, mo.md("Select a result row to load.")) |
95 | 100 | return self._client.get_result(rid or "") |
96 | 101 |
|
| 102 | + @property |
| 103 | + def result_panel(self): |
| 104 | + rid = self.selected_result_id |
| 105 | + if rid is None: |
| 106 | + return mo.md("_Select a result row to load._") |
| 107 | + return query_result(self._client.get_result(rid), label="Recent result") |
| 108 | + |
| 109 | + @property |
| 110 | + def tab_ui(self): |
| 111 | + if self.table is not None: |
| 112 | + _ = self.table.value |
| 113 | + return mo.vstack([self.ui, self.result_panel], gap=2) |
| 114 | + |
97 | 115 | @property |
98 | 116 | def ui(self): |
99 | | - _ = self.pick.value |
100 | | - return mo.vstack([self.pick], gap=1) |
| 117 | + if self.table is None: |
| 118 | + return mo.md("_No recent results._") |
| 119 | + _ = self.table.value |
| 120 | + return mo.vstack( |
| 121 | + [ |
| 122 | + mo.md("### Recent results"), |
| 123 | + self.table, |
| 124 | + ], |
| 125 | + gap=1, |
| 126 | + ) |
101 | 127 |
|
102 | 128 |
|
103 | 129 | def recent_results(client: HotdataClient, *, limit: int = 50) -> RecentResults: |
@@ -150,3 +176,34 @@ def connection_status(client: HotdataClient): |
150 | 176 | mo.md(f"**API** error — {parts[0]}"), |
151 | 177 | kind="danger", |
152 | 178 | ) |
| 179 | + |
| 180 | + |
| 181 | +def connections_panel(client: HotdataClient): |
| 182 | + """Workspace health callout plus a table of configured connections.""" |
| 183 | + status = connection_status(client) |
| 184 | + conns = client.connections().list_connections().connections |
| 185 | + if not conns: |
| 186 | + return mo.vstack([status, mo.md("_No connections in this workspace._")], gap=1) |
| 187 | + rows: list[dict[str, object]] = [] |
| 188 | + for c in conns: |
| 189 | + rows.append( |
| 190 | + { |
| 191 | + "name": c.name, |
| 192 | + "id": c.id, |
| 193 | + "source_type": getattr(c, "source_type", None), |
| 194 | + } |
| 195 | + ) |
| 196 | + return mo.vstack( |
| 197 | + [ |
| 198 | + status, |
| 199 | + mo.ui.table( |
| 200 | + rows, |
| 201 | + label="Connections", |
| 202 | + pagination=True, |
| 203 | + page_size=min(10, len(rows)), |
| 204 | + selection=None, |
| 205 | + max_height=320, |
| 206 | + ), |
| 207 | + ], |
| 208 | + gap=1, |
| 209 | + ) |
0 commit comments