input Validierung und UI handling fühlbar beschleunigt
This commit is contained in:
1 parent
31cdc7747f
commit
f4afd4b2e5
1 file changed
+77
-27
@@ -54,6 +54,15 @@ if "input_validated" not in st.session_state:
|
|||||||
st.session_state.input_validated = False
|
st.session_state.input_validated = False
|
||||||
if "template_validated" not in st.session_state:
|
if "template_validated" not in st.session_state:
|
||||||
st.session_state.template_validated = False
|
st.session_state.template_validated = False
|
||||||
|
# Caches für Validierung/Parsing – nur bei Dateiwechsel neu ausführen
|
||||||
|
if "last_input_file" not in st.session_state:
|
||||||
|
st.session_state.last_input_file = None
|
||||||
|
if "last_template_file" not in st.session_state:
|
||||||
|
st.session_state.last_template_file = None
|
||||||
|
if "cached_val_result" not in st.session_state:
|
||||||
|
st.session_state.cached_val_result = None
|
||||||
|
if "cached_tpl_result" not in st.session_state:
|
||||||
|
st.session_state.cached_tpl_result = None
|
||||||
|
|
||||||
# --- Layout: zwei Spalten ---
|
# --- Layout: zwei Spalten ---
|
||||||
col1, col2 = st.columns(2)
|
col1, col2 = st.columns(2)
|
||||||
@@ -73,9 +82,30 @@ with col1:
|
|||||||
|
|
||||||
if selected_input:
|
if selected_input:
|
||||||
input_path = Path(app_config.input_dir) / selected_input
|
input_path = Path(app_config.input_dir) / selected_input
|
||||||
# Validiere und parse sofort
|
|
||||||
with st.spinner("Validiere Input-Datei…"):
|
# Nur validieren/parsen wenn sich die Datei geändert hat
|
||||||
val_result = validate_input_file(input_path, app_config.input_schema, app_config.month_sheet_pattern)
|
if selected_input != st.session_state.last_input_file:
|
||||||
|
with st.spinner("Validiere Input-Datei…"):
|
||||||
|
val_result = validate_input_file(input_path, app_config.input_schema, app_config.month_sheet_pattern)
|
||||||
|
|
||||||
|
if val_result.is_valid:
|
||||||
|
records = parse_input_file(
|
||||||
|
input_path,
|
||||||
|
app_config.input_schema,
|
||||||
|
app_config.month_sheet_pattern,
|
||||||
|
app_config.skip_empty_name,
|
||||||
|
app_config.skip_empty_antragsnummer,
|
||||||
|
)
|
||||||
|
st.session_state.parsed_records = records
|
||||||
|
st.session_state.input_validated = True
|
||||||
|
else:
|
||||||
|
st.session_state.parsed_records = []
|
||||||
|
st.session_state.input_validated = False
|
||||||
|
|
||||||
|
st.session_state.cached_val_result = val_result
|
||||||
|
st.session_state.last_input_file = selected_input
|
||||||
|
else:
|
||||||
|
val_result = st.session_state.cached_val_result
|
||||||
|
|
||||||
if not val_result.is_valid:
|
if not val_result.is_valid:
|
||||||
st.markdown(
|
st.markdown(
|
||||||
@@ -100,27 +130,19 @@ with col1:
|
|||||||
for warn in val_result.warnings:
|
for warn in val_result.warnings:
|
||||||
st.warning(warn)
|
st.warning(warn)
|
||||||
|
|
||||||
# Parse die Datei
|
# Zeige Zusammenfassung aus gecachten Records
|
||||||
records = parse_input_file(
|
records = st.session_state.parsed_records
|
||||||
input_path,
|
|
||||||
app_config.input_schema,
|
|
||||||
app_config.month_sheet_pattern,
|
|
||||||
app_config.skip_empty_name,
|
|
||||||
app_config.skip_empty_antragsnummer,
|
|
||||||
)
|
|
||||||
st.session_state.parsed_records = records
|
|
||||||
st.session_state.input_validated = True
|
|
||||||
|
|
||||||
# Zeige Zusammenfassung
|
|
||||||
employees = get_unique_employees(records)
|
employees = get_unique_employees(records)
|
||||||
antragsnummern = get_unique_antragsnummern(records)
|
antragsnummern = get_unique_antragsnummern(records)
|
||||||
|
|
||||||
st.success(f"✅ {len(records)} Einträge in {val_result.info.get('sheets_with_data', 0)} Monats-Sheets")
|
st.success(f"✅ {len(records)} Einträge in {val_result.info.get('sheets_with_data', 0)} Monats-Sheets")
|
||||||
st.metric("Mitarbeiter", len(employees))
|
pills = " ".join(
|
||||||
st.metric("Antragsnummern", len(antragsnummern))
|
f'<span style="display:inline-block; background:#e8f0fe; color:#1a73e8; '
|
||||||
with st.expander("Antragsnummern anzeigen"):
|
f'border-radius:16px; padding:4px 12px; margin:3px; font-size:0.9em; '
|
||||||
for an in antragsnummern:
|
f'white-space:nowrap">{an}</span>'
|
||||||
st.text(f"• {an}")
|
for an in antragsnummern
|
||||||
|
)
|
||||||
|
st.markdown(f"**Antragsnummern:**<br>{pills}", unsafe_allow_html=True)
|
||||||
|
|
||||||
with col2:
|
with col2:
|
||||||
st.subheader("2. Template")
|
st.subheader("2. Template")
|
||||||
@@ -140,9 +162,16 @@ with col2:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if selected_template:
|
if selected_template:
|
||||||
template_path = Path(app_config.template_dir) / selected_template
|
# Nur validieren wenn sich das Template geändert hat
|
||||||
with st.spinner("Validiere Template…"):
|
if selected_template != st.session_state.last_template_file:
|
||||||
tpl_result = validate_template(template_path, app_config.output_mapping)
|
template_path = Path(app_config.template_dir) / selected_template
|
||||||
|
with st.spinner("Validiere Template…"):
|
||||||
|
tpl_result = validate_template(template_path, app_config.output_mapping)
|
||||||
|
st.session_state.cached_tpl_result = tpl_result
|
||||||
|
st.session_state.last_template_file = selected_template
|
||||||
|
st.session_state.template_validated = tpl_result.is_valid
|
||||||
|
else:
|
||||||
|
tpl_result = st.session_state.cached_tpl_result
|
||||||
|
|
||||||
if not tpl_result.is_valid:
|
if not tpl_result.is_valid:
|
||||||
st.markdown(
|
st.markdown(
|
||||||
@@ -176,11 +205,32 @@ st.subheader("3. Mitarbeiter auswählen")
|
|||||||
|
|
||||||
if st.session_state.input_validated and st.session_state.parsed_records:
|
if st.session_state.input_validated and st.session_state.parsed_records:
|
||||||
employees = get_unique_employees(st.session_state.parsed_records)
|
employees = get_unique_employees(st.session_state.parsed_records)
|
||||||
selected_employees = st.multiselect(
|
st.caption(f"{len(employees)} Mitarbeiter gefunden – wähle aus, für wen Tätigkeitsnachweise erstellt werden sollen:")
|
||||||
f"{len(employees)} Mitarbeiter gefunden – wähle aus, für wen Tätigkeitsnachweise erstellt werden sollen:",
|
|
||||||
options=employees,
|
# "Alle" / "Keine" Buttons
|
||||||
default=employees,
|
btn_col1, btn_col2 = st.columns(2)
|
||||||
|
if btn_col1.button("☑ Alle auswählen", use_container_width=True):
|
||||||
|
for emp in employees:
|
||||||
|
st.session_state[f"sel_{emp}"] = True
|
||||||
|
if btn_col2.button("☐ Keine auswählen", use_container_width=True):
|
||||||
|
for emp in employees:
|
||||||
|
st.session_state[f"sel_{emp}"] = False
|
||||||
|
|
||||||
|
# Mitarbeiter-Liste mit Rahmen
|
||||||
|
st.markdown(
|
||||||
|
'<div style="border:1px solid #d5d5d5; border-radius:6px; padding:8px 12px; '
|
||||||
|
'background:#fafafa; max-height:300px; overflow-y:auto">',
|
||||||
|
unsafe_allow_html=True,
|
||||||
)
|
)
|
||||||
|
selected_employees = []
|
||||||
|
for emp in employees:
|
||||||
|
key = f"sel_{emp}"
|
||||||
|
if key not in st.session_state:
|
||||||
|
st.session_state[key] = True
|
||||||
|
if st.checkbox(emp, value=st.session_state[key], key=key):
|
||||||
|
selected_employees.append(emp)
|
||||||
|
st.markdown("</div>", unsafe_allow_html=True)
|
||||||
|
|
||||||
st.caption(f"{len(selected_employees)} von {len(employees)} Mitarbeitern ausgewählt")
|
st.caption(f"{len(selected_employees)} von {len(employees)} Mitarbeitern ausgewählt")
|
||||||
else:
|
else:
|
||||||
selected_employees = []
|
selected_employees = []
|
||||||
|
|||||||
Reference in new issue
Block a user