Skip to content

Commit 856df04

Browse files
guidooswaldDBclaude
andcommitted
Move Load All button to response header, auto-dismiss progress after 5s
Load All button now renders inline in the response-meta bar (right of item count) via a clientside callback that reparents it into an anchor element. Progress message auto-clears 5 seconds after loading completes or errors. Removed fetch-bar-row wrapper; status bar is now a direct child of response-panel. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a23adea commit 856df04

3 files changed

Lines changed: 53 additions & 24 deletions

File tree

app.py

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -544,8 +544,10 @@ def build_response_panel(result: Dict[str, Any], chips: Optional[List] = None) -
544544
html.Div([
545545
dbc.Badge([html.I(className=f"bi {icon} me-1"), str(code) if code else "Error"],
546546
color=status_color, className="status-badge"),
547-
html.Span(f"{ms}ms", className="timing-label font-mono ms-2"),
547+
html.Span(f"{ms:,}ms", className="timing-label font-mono ms-2"),
548548
html.Span(item_count, className="timing-label") if item_count else None,
549+
# Anchor point for the absolutely-positioned Load All button
550+
html.Span(id="load-all-anchor", className="load-all-anchor"),
549551
html.Span(result.get("url", ""), className="response-url ms-auto"),
550552
], className="response-meta"),
551553
html.Div(body_children, className="response-body"),
@@ -963,18 +965,16 @@ def _custom_section():
963965
html.Div([
964966
html.Div(WELCOME, id="endpoint-detail", className="form-panel"),
965967
html.Div([
966-
html.Div([
967-
html.Div(id="fetch-status-bar", className="fetch-status-bar"),
968-
html.Button(
969-
[html.I(className="bi bi-cloud-download me-1"), "Load All"],
970-
id="sp-load-all-btn",
971-
n_clicks=0,
972-
className="sp-load-all-btn",
973-
title="Fetch all remaining pages",
974-
style={"display": "none"},
975-
),
976-
], className="fetch-bar-row"),
968+
html.Div(id="fetch-status-bar", className="fetch-status-bar"),
977969
html.Div(_RESPONSE_EMPTY, id="response-container", className="response-container"),
970+
html.Button(
971+
[html.I(className="bi bi-cloud-download me-1"), "Load All"],
972+
id="sp-load-all-btn",
973+
n_clicks=0,
974+
className="sp-load-all-btn",
975+
title="Fetch all remaining pages",
976+
style={"display": "none"},
977+
),
978978
], className="response-panel"),
979979
], className="main-content"),
980980
], className="app-body"),
@@ -1887,13 +1887,23 @@ def poll_load_all(n_intervals, cache):
18871887
], className="fetch-status-inner loading")
18881888
return no_update, no_update, no_update, status, False
18891889

1890-
# Done or error — render final result
1890+
# Auto-dismiss: if finished_at was set, wait 5s then clear status bar
1891+
finished_at = state.get("finished_at")
1892+
if finished_at and not state.get("done"):
1893+
if time.time() - finished_at >= 5:
1894+
state.pop("finished_at", None)
1895+
return no_update, no_update, no_update, "", True # clear status, stop ticker
1896+
return NO # keep ticking, waiting to dismiss
1897+
1898+
if not state.get("done"):
1899+
return NO
1900+
1901+
# Done or error — render final result and set dismiss timer
18911902
if state.get("error"):
18921903
status = html.Div([
18931904
html.I(className="bi bi-exclamation-triangle-fill me-2"),
18941905
f"Error after {pages} pages ({total:,} items): {state['error']}",
18951906
], className="fetch-status-inner error")
1896-
# Still render whatever we got
18971907
else:
18981908
status = html.Div([
18991909
html.I(className="bi bi-check-circle-fill me-2"),
@@ -1921,10 +1931,10 @@ def poll_load_all(n_intervals, cache):
19211931
if ep_id:
19221932
new_cache[ep_id] = {"result": merged_result, "chips": chips or None}
19231933

1924-
# Reset state for next use
1925-
_load_all_state.update({"running": False, "done": False, "items": []})
1934+
# Mark done, set dismiss timer — keep ticker running for auto-dismiss
1935+
_load_all_state.update({"done": False, "items": [], "finished_at": time.time()})
19261936

1927-
return build_response_panel(merged_result, chips), new_cache, chips or None, status, True
1937+
return build_response_panel(merged_result, chips), new_cache, chips or None, status, False
19281938

19291939

19301940
# 13. Search filter
@@ -2180,6 +2190,25 @@ def update_curl_display(last_req, conn_config):
21802190
)
21812191

21822192

2193+
# Reparent the Load All button into the response-meta bar after each render
2194+
app.clientside_callback(
2195+
"""
2196+
function(children, style) {
2197+
var anchor = document.getElementById('load-all-anchor');
2198+
var btn = document.getElementById('sp-load-all-btn');
2199+
if (anchor && btn) {
2200+
anchor.appendChild(btn);
2201+
}
2202+
return window.dash_clientside.no_update;
2203+
}
2204+
""",
2205+
Output("sp-load-all-btn", "className"),
2206+
Input("response-container", "children"),
2207+
Input("sp-load-all-btn", "style"),
2208+
prevent_initial_call=True,
2209+
)
2210+
2211+
21832212
# ── Entry point ───────────────────────────────────────────────────────────────
21842213
if __name__ == "__main__":
21852214
port = int(os.getenv("DATABRICKS_APP_PORT", "8050"))

assets/style.css

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ body {
257257
flex-direction: column;
258258
overflow: hidden;
259259
min-width: 0;
260+
position: relative;
260261
}
261262

262263
/* ── Welcome Panel ────────────────────────────────────────────────── */
@@ -613,24 +614,24 @@ body {
613614
border-radius: 3px;
614615
}
615616
.sp-toggle:hover { color: var(--cyan); background: rgba(0,212,255,0.08); }
617+
.load-all-anchor { display: inline; }
616618
.sp-load-all-btn {
617619
background: rgba(0,212,255,0.1);
618620
border: 1px solid rgba(0,212,255,0.25);
619621
color: var(--cyan);
620622
cursor: pointer;
621-
padding: 1px 8px;
622-
font-size: 10px;
623+
padding: 2px 10px;
624+
font-size: 11px;
623625
font-family: var(--font-mono);
624626
border-radius: 3px;
625627
white-space: nowrap;
626-
flex-shrink: 0;
627628
transition: all 0.15s;
629+
align-items: center;
628630
}
629631
.sp-load-all-btn:hover {
630632
background: rgba(0,212,255,0.2);
631633
border-color: rgba(0,212,255,0.45);
632634
}
633-
.side-panel.sp-collapsed .sp-load-all-btn { display: none; }
634635
.sp-load-progress { flex-shrink: 0; }
635636
.sp-load-progress-active {
636637
padding: 6px 10px;
@@ -715,8 +716,7 @@ body {
715716

716717

717718
/* ── Pagination status bar ────────────────────────────────────────── */
718-
.fetch-bar-row { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
719-
.fetch-status-bar { flex: 1; overflow: hidden; }
719+
.fetch-status-bar { flex-shrink: 0; overflow: hidden; }
720720
.fetch-status-bar:empty { display: none; }
721721

722722
.fetch-status-inner {

version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
367
1+
372

0 commit comments

Comments
 (0)