fix: prevent match group expanders from collapsing on button click
Replace st.rerun() with on_click callbacks so decisions write to session state before the natural rerun. Decided groups auto-collapse with status in the label; undecided groups stay expanded. Added undo button on decided groups. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -213,11 +213,7 @@ if uploaded is not None:
|
||||
# Individual group cards
|
||||
decisions = st.session_state["review_decisions"]
|
||||
for i, group in enumerate(result.match_groups):
|
||||
decision = match_group_card(group, df, group_num=i + 1)
|
||||
if decision is not None:
|
||||
decisions[group.group_id] = decision
|
||||
st.session_state["review_decisions"] = decisions
|
||||
st.rerun()
|
||||
match_group_card(group, df, group_num=i + 1)
|
||||
|
||||
# Show decision summary
|
||||
if decisions:
|
||||
|
||||
@@ -262,26 +262,37 @@ def match_group_card(
|
||||
group: MatchResult,
|
||||
df: pd.DataFrame,
|
||||
group_num: int,
|
||||
) -> Optional[bool]:
|
||||
) -> None:
|
||||
"""Render an expandable match group card with side-by-side diff.
|
||||
|
||||
Returns:
|
||||
True — user clicked Merge (accept match)
|
||||
False — user clicked Keep Both (reject match)
|
||||
None — no decision yet
|
||||
Decisions are stored directly in ``st.session_state["review_decisions"]``
|
||||
via ``on_click`` callbacks so that other expanders keep their state on
|
||||
rerun.
|
||||
"""
|
||||
confidence = group.confidence
|
||||
auto_expand = confidence < 95.0
|
||||
matched_on = ", ".join(group.matched_on)
|
||||
n_rows = len(group.row_indices)
|
||||
gid = group.group_id
|
||||
|
||||
decisions = st.session_state.get("review_decisions", {})
|
||||
has_decision = gid in decisions
|
||||
decision_val = decisions.get(gid)
|
||||
|
||||
# Build label — append decision status if already decided
|
||||
label = (
|
||||
f"Group {group_num}: {n_rows} rows "
|
||||
f"(confidence: {confidence:.0f}%) "
|
||||
f"[{matched_on}]"
|
||||
)
|
||||
if decision_val is True:
|
||||
label += " — Merged"
|
||||
elif decision_val is False:
|
||||
label += " — Kept Both"
|
||||
|
||||
with st.expander(label, expanded=auto_expand):
|
||||
# Decided groups collapse; undecided groups stay open
|
||||
expanded = not has_decision
|
||||
|
||||
with st.expander(label, expanded=expanded):
|
||||
# Build comparison DataFrame
|
||||
display_cols = [c for c in df.columns if not str(c).startswith("_norm_")]
|
||||
rows_data = []
|
||||
@@ -312,28 +323,32 @@ def match_group_card(
|
||||
styled = compare_df.style.apply(_highlight_diffs, axis=0)
|
||||
st.dataframe(styled, use_container_width=True)
|
||||
|
||||
# Action buttons
|
||||
btn_left, btn_mid, btn_right = st.columns(3)
|
||||
merge_key = f"merge_{group.group_id}"
|
||||
keep_key = f"keep_{group.group_id}"
|
||||
|
||||
with btn_left:
|
||||
if st.button("Merge", key=merge_key, type="primary"):
|
||||
return True
|
||||
with btn_mid:
|
||||
if st.button("Keep Both", key=keep_key):
|
||||
return False
|
||||
|
||||
# Check session state for previous decisions
|
||||
decisions = st.session_state.get("review_decisions", {})
|
||||
if group.group_id in decisions:
|
||||
decision = decisions[group.group_id]
|
||||
if decision is True:
|
||||
if has_decision:
|
||||
# Show current decision with option to undo
|
||||
if decision_val is True:
|
||||
st.success("Decision: Merge")
|
||||
elif decision is False:
|
||||
else:
|
||||
st.info("Decision: Keep Both")
|
||||
|
||||
return None
|
||||
def _undo(g=gid):
|
||||
st.session_state["review_decisions"].pop(g, None)
|
||||
|
||||
st.button("Undo", key=f"undo_{gid}", on_click=_undo)
|
||||
else:
|
||||
# Action buttons — on_click writes to session state before rerun
|
||||
def _on_merge(g=gid):
|
||||
st.session_state["review_decisions"][g] = True
|
||||
|
||||
def _on_keep(g=gid):
|
||||
st.session_state["review_decisions"][g] = False
|
||||
|
||||
btn_left, btn_mid, _btn_right = st.columns(3)
|
||||
with btn_left:
|
||||
st.button("Merge", key=f"merge_{gid}",
|
||||
type="primary", on_click=_on_merge)
|
||||
with btn_mid:
|
||||
st.button("Keep Both", key=f"keep_{gid}",
|
||||
on_click=_on_keep)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user