Skip to content

Commit fcf0c08

Browse files
Merge pull request #28 from The-Schultz-Lab/hist7-searchable-history
Searchable + faceted History browser (HIST.7)
2 parents 6c7e61c + 69d1506 commit fcf0c08

6 files changed

Lines changed: 767 additions & 11 deletions

File tree

quantui/app.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,13 @@ class QuantUIApp:
904904
past_dd: Any
905905
past_output: Any
906906
past_refresh_btn: Any
907+
history_search: Any
908+
history_filter_clear_btn: Any
909+
history_count_lbl: Any
910+
history_method_dd: Any
911+
history_basis_dd: Any
912+
history_date_from: Any
913+
history_date_to: Any
907914
lib_category_dd: Any
908915
lib_search_txt: Any
909916
lib_results_dd: Any
@@ -1788,6 +1795,21 @@ def _wire_callbacks(self) -> None:
17881795
self.past_refresh_btn.on_click(self._on_past_refresh)
17891796
self.copy_path_btn.on_click(self._on_copy_results_path)
17901797
self.view_log_btn.on_click(self._on_view_log)
1798+
# History search / faceted filters (HIST.7)
1799+
for _w in (
1800+
self.history_search,
1801+
self.history_method_dd,
1802+
self.history_basis_dd,
1803+
self.history_date_from,
1804+
self.history_date_to,
1805+
):
1806+
_w.observe(self._safe_cb(self._on_history_filter_changed), names="value")
1807+
for _chip in (
1808+
*self._history_calc_chips.values(),
1809+
*self._history_status_chips.values(),
1810+
):
1811+
_chip.observe(self._safe_cb(self._on_history_filter_changed), names="value")
1812+
self.history_filter_clear_btn.on_click(self._on_history_filter_clear)
17911813
# Perf stats reset
17921814
self._reset_btn.on_click(self._on_reset_click)
17931815
self._reset_confirm_yes.on_click(self._on_confirm_yes)
@@ -3512,6 +3534,32 @@ def _on_compare_clear(self, btn) -> None:
35123534
def _on_past_dd_changed(self, change) -> None:
35133535
_hist_on_past_dd_changed(self, change, layout_fn=_layout)
35143536

3537+
def _on_history_filter_changed(self, change=None) -> None:
3538+
from quantui.app_history import apply_history_filter
3539+
3540+
apply_history_filter(self)
3541+
3542+
def _on_history_filter_clear(self, btn=None) -> None:
3543+
from quantui.app_history import apply_history_filter
3544+
3545+
# Reset every facet widget, suspending the observer so we run a single
3546+
# filter pass at the end instead of one per widget reset.
3547+
self._history_filter_suspend = True
3548+
try:
3549+
self.history_search.value = ""
3550+
self.history_method_dd.value = ""
3551+
self.history_basis_dd.value = ""
3552+
self.history_date_from.value = None
3553+
self.history_date_to.value = None
3554+
for chip in (
3555+
*self._history_calc_chips.values(),
3556+
*self._history_status_chips.values(),
3557+
):
3558+
chip.value = False
3559+
finally:
3560+
self._history_filter_suspend = False
3561+
apply_history_filter(self)
3562+
35153563
def _on_past_refresh(self, btn) -> None:
35163564
self._activity_begin("Refreshing history list...")
35173565
try:

quantui/app_builders.py

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,15 +430,116 @@ def build_history_section(
430430
app._cal_accordion = widgets.Accordion(children=[cal_panel], selected_index=None)
431431
app._cal_accordion.set_title(0, "Calibrate time estimates")
432432

433+
# ── Search / faceted filters (HIST.7) ──────────────────────────────
434+
# All filtering is client-side over the cached ``app._history_entries``
435+
# list; widgets here only hold facet state. See app_history.apply_history_filter.
436+
from quantui.app_history import HISTORY_CALC_TYPE_FACETS, HISTORY_STATUS_FACETS
437+
438+
app._history_entries = []
439+
app._history_filter_suspend = False
440+
app.history_search = widgets.Text(
441+
placeholder="search name or formula (e.g. benzene, C6H6)",
442+
continuous_update=True, # type-to-narrow
443+
layout=layout_fn(width="300px"),
444+
)
445+
app.history_filter_clear_btn = widgets.Button(
446+
icon="times",
447+
tooltip="Clear all history filters",
448+
layout=layout_fn(width="40px"),
449+
)
450+
app.history_count_lbl = widgets.HTML(
451+
'<span style="color:#888;font-size:12px"></span>'
452+
)
453+
app._history_calc_chips = {
454+
key: widgets.ToggleButton(
455+
value=False,
456+
description=label,
457+
tooltip=f"Show only {label} calculations",
458+
layout=layout_fn(width="auto"),
459+
)
460+
for label, key in HISTORY_CALC_TYPE_FACETS
461+
}
462+
app.history_method_dd = widgets.Dropdown(
463+
options=[("Any method", "")],
464+
value="",
465+
description="Method:",
466+
style={"description_width": "55px"},
467+
layout=layout_fn(width="200px"),
468+
)
469+
app.history_basis_dd = widgets.Dropdown(
470+
options=[("Any basis", "")],
471+
value="",
472+
description="Basis:",
473+
style={"description_width": "55px"},
474+
layout=layout_fn(width="200px"),
475+
)
476+
app.history_date_from = widgets.DatePicker(
477+
description="From:",
478+
style={"description_width": "45px"},
479+
layout=layout_fn(width="200px"),
480+
)
481+
app.history_date_to = widgets.DatePicker(
482+
description="To:",
483+
style={"description_width": "35px"},
484+
layout=layout_fn(width="190px"),
485+
)
486+
app._history_status_chips = {
487+
key: widgets.ToggleButton(
488+
value=False,
489+
description=label,
490+
layout=layout_fn(width="auto"),
491+
)
492+
for label, key in HISTORY_STATUS_FACETS
493+
}
494+
495+
def _facet_label(text: str, width: str = "60px") -> widgets.HTML:
496+
return widgets.HTML(
497+
f'<span style="color:#555;font-size:12px;width:{width};'
498+
f'display:inline-block">{text}</span>'
499+
)
500+
501+
app._history_filter_box = widgets.VBox(
502+
[
503+
widgets.HBox(
504+
[
505+
app.history_search,
506+
app.history_filter_clear_btn,
507+
app.history_count_lbl,
508+
],
509+
layout=layout_fn(align_items="center", gap="6px"),
510+
),
511+
widgets.HBox(
512+
[_facet_label("Type:"), *app._history_calc_chips.values()],
513+
layout=layout_fn(align_items="center", gap="4px", flex_wrap="wrap"),
514+
),
515+
widgets.HBox(
516+
[app.history_method_dd, app.history_basis_dd],
517+
layout=layout_fn(align_items="center", gap="8px"),
518+
),
519+
widgets.HBox(
520+
[
521+
app.history_date_from,
522+
app.history_date_to,
523+
_facet_label("Status:", "55px"),
524+
*app._history_status_chips.values(),
525+
],
526+
layout=layout_fn(align_items="center", gap="6px", flex_wrap="wrap"),
527+
),
528+
],
529+
layout=layout_fn(margin="0 0 8px", gap="4px"),
530+
)
531+
433532
# The History tab is now purely the result-browser. Performance stats
434533
# + Calibrate accordions moved to the System Settings tab — see below —
435534
# so the user finds benchmarking + system state in one logical place.
436535
app.history_panel = widgets.VBox(
437536
[
438537
widgets.HTML(
439538
'<p style="color:#555;font-size:13px;margin:0 0 8px">'
440-
"Calculations are saved automatically. Select one below to view its results.</p>"
539+
"Calculations are saved automatically. Filter below, then select "
540+
"one to view its results.</p>"
441541
),
542+
app._history_filter_box,
442543
widgets.HBox(
443544
[
444545
app.past_dd,

0 commit comments

Comments
 (0)