feat: use list actions for uncategorized groups
This commit is contained in:
@@ -6,6 +6,7 @@ from __future__ import annotations
|
||||
import streamlit as st
|
||||
|
||||
from jarca_ledger_mcp.adapters.streamlit import categorization_gateway
|
||||
from dashboard.components import JarcaList
|
||||
from dashboard.common import * # noqa: F403, F405
|
||||
|
||||
def render_uncategorized_action_table(rows: list[dict[str, Any]], db_path: str) -> None:
|
||||
@@ -56,22 +57,28 @@ def save_merchant_rule_from_recommendation(merchant: str, tx_type: str, rec: dic
|
||||
)
|
||||
|
||||
|
||||
def render_uncategorized_groups(groups: list[dict[str, Any]], db_path: str, repeated_only: bool = False) -> None:
|
||||
visible = [g for g in groups if not repeated_only or int(g.get("count") or 0) >= 2]
|
||||
visible = visible[:10]
|
||||
if not visible:
|
||||
st.info("반복 후보가 없습니다.")
|
||||
return
|
||||
for idx, group in enumerate(visible):
|
||||
def render_uncategorized_groups_header(groups: list[dict[str, Any]]) -> None:
|
||||
st.markdown(f"{len(groups)}개 사용처 그룹")
|
||||
|
||||
|
||||
def render_uncategorized_group(group: dict[str, Any], db_path: str) -> None:
|
||||
rec = group.get("recommendation") or {}
|
||||
cols = st.columns([2.0, 0.7, 1.0, 1.55, 1.0, 1.0], vertical_alignment="center")
|
||||
cols = st.columns([2.0, 0.7, 1.0, 1.55, 1.0], vertical_alignment="center")
|
||||
merchant = group.get("merchant") or group.get("raw_summary") or "-"
|
||||
group_key = group.get("sample_transaction_id") or merchant
|
||||
cols[0].markdown(f"**{merchant}** \n<span style='color:#64748b;font-size:0.82rem'>{group.get('raw_summary') or '-'} · {group.get('type') or '-'}</span>", unsafe_allow_html=True)
|
||||
cols[1].write(f"{int(group.get('count') or 0):,}건")
|
||||
cols[2].write(format_krw(group.get("total_amount")))
|
||||
cols[3].write(recommendation_text(rec))
|
||||
apply_disabled = not bool(rec.get("category"))
|
||||
if cols[4].button("그룹 적용", key=f"uncat_group_apply_{idx}_{merchant}", disabled=apply_disabled, use_container_width=True):
|
||||
action = cols[4].menu_button(
|
||||
"작업",
|
||||
options=["그룹 적용", "규칙 만들기"],
|
||||
key=f"uncat_group_action_{group_key}",
|
||||
disabled=apply_disabled,
|
||||
width="stretch",
|
||||
)
|
||||
if action == "그룹 적용":
|
||||
res = categorization_gateway.apply_uncategorized_group_recommendation(
|
||||
group.get("merchant", ""), group.get("raw_summary", ""), group.get("type", ""), db_path=db_path
|
||||
)
|
||||
@@ -81,7 +88,7 @@ def render_uncategorized_groups(groups: list[dict[str, Any]], db_path: str, repe
|
||||
st.rerun()
|
||||
else:
|
||||
st.error(res.get("error", res))
|
||||
if cols[5].button("규칙 만들기", key=f"uncat_group_rule_{idx}_{merchant}", disabled=apply_disabled, use_container_width=True):
|
||||
elif action == "규칙 만들기":
|
||||
res = save_merchant_rule_from_recommendation(group.get("merchant", ""), group.get("type", ""), rec, db_path)
|
||||
clear_cache()
|
||||
if res.get("success"):
|
||||
@@ -89,9 +96,18 @@ def render_uncategorized_groups(groups: list[dict[str, Any]], db_path: str, repe
|
||||
st.rerun()
|
||||
else:
|
||||
st.warning(res.get("error", res))
|
||||
|
||||
st.caption(f"최근: {group.get('latest_date') or '-'} · 최대금액: {format_krw(group.get('max_amount'))} · 근거: {rec.get('reason') or '추천 없음'}")
|
||||
if idx < len(visible) - 1:
|
||||
st.divider()
|
||||
|
||||
|
||||
def render_uncategorized_groups(groups: list[dict[str, Any]], db_path: str, repeated_only: bool = False) -> None:
|
||||
visible = [g for g in groups if not repeated_only or int(g.get("count") or 0) >= 2][:10]
|
||||
JarcaList(
|
||||
render_header=render_uncategorized_groups_header,
|
||||
render_item=lambda group: render_uncategorized_group(group, db_path),
|
||||
items=visible,
|
||||
empty_message="반복 후보가 없습니다.",
|
||||
).render()
|
||||
|
||||
|
||||
def render_uncategorized_work_items(rows: list[dict[str, Any]], db_path: str, recommended_only: bool = False) -> None:
|
||||
|
||||
Reference in New Issue
Block a user