Compare commits
1 Commits
20cd0b8547
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67170b8130 |
Binary file not shown.
0
app/data/parquet_store.py
Normal file
0
app/data/parquet_store.py
Normal file
@@ -1,11 +1,13 @@
|
|||||||
import streamlit as st
|
import streamlit as st
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from data.scriptloader import get_sql
|
#from data.scriptloader import get_sql
|
||||||
from data.db import load_data
|
from data.db import load_data
|
||||||
from auth_runtime import require_login
|
from auth_runtime import require_login
|
||||||
from ui.sidebar import build_sidebar, hide_sidebar_if_logged_out
|
#from ui.sidebar import build_sidebar, hide_sidebar_if_logged_out
|
||||||
from auth import get_fullname_for_user
|
#from auth import get_fullname_for_user
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from tools.excel_export import df_to_excel_bytes
|
||||||
|
from tools.help_text import get_help
|
||||||
|
|
||||||
|
|
||||||
st.set_page_config(page_title="Co-App Home", page_icon="🏠", layout="wide")
|
st.set_page_config(page_title="Co-App Home", page_icon="🏠", layout="wide")
|
||||||
@@ -13,7 +15,17 @@ st.set_page_config(page_title="Co-App Home", page_icon="🏠", layout="wide")
|
|||||||
authenticator = require_login()
|
authenticator = require_login()
|
||||||
st.session_state["authenticator"] = authenticator
|
st.session_state["authenticator"] = authenticator
|
||||||
|
|
||||||
|
st.markdown("""
|
||||||
|
<style>
|
||||||
|
.block-container {
|
||||||
|
padding-top: 0.2rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
""", unsafe_allow_html=True)
|
||||||
|
|
||||||
|
description = get_help("costobjects")
|
||||||
|
with st.expander(label="ℹ️ Hilfe / Hinweise", expanded=False): # ❓
|
||||||
|
st.markdown(description)
|
||||||
|
|
||||||
@st.cache_data
|
@st.cache_data
|
||||||
def cache_data() -> pd.DataFrame:
|
def cache_data() -> pd.DataFrame:
|
||||||
@@ -38,18 +50,31 @@ def sidebar_filters(df) -> dict:
|
|||||||
This function should contain UI concerns only (widgets, layout),
|
This function should contain UI concerns only (widgets, layout),
|
||||||
and not data filtering logic, to keep the code maintainable.
|
and not data filtering logic, to keep the code maintainable.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
st.markdown("""
|
||||||
|
<style>
|
||||||
|
section[data-testid="stSidebar"] .block-container {
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
section[data-testid="stSidebar"] div[data-testid="stVerticalBlock"] > div {
|
||||||
|
gap: 0.2rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
""", unsafe_allow_html=True)
|
||||||
|
|
||||||
st.sidebar.header("Filter")
|
st.sidebar.header("Filter")
|
||||||
|
|
||||||
if st.sidebar.button("Refresh (Global)"):
|
if st.sidebar.button("Refresh (Global)"):
|
||||||
cache_data.clear()
|
cache_data.clear()
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
year = st.sidebar.selectbox(label="Jahr", options=(2025, 2026), index=1)
|
|
||||||
filter_text = st.sidebar.text_input(label="Textsuche", placeholder="Suche Objekt, Text, Verantwortlicher")
|
filter_text = st.sidebar.text_input(label="Textsuche", placeholder="Suche Objekt, Text, Verantwortlicher")
|
||||||
col_s1, col_s2 = st.sidebar.columns(2)
|
col_s1, col_s2 = st.sidebar.columns(2)
|
||||||
with col_s1:
|
with col_s1:
|
||||||
typ = st.sidebar.selectbox(label="Typ", options=sorted(df["typ"].dropna().unique()), index=1)
|
year = st.selectbox(label="Jahr", options=(2025, 2026), index=1)
|
||||||
with col_s2:
|
with col_s2:
|
||||||
|
typ = st.selectbox(label="Typ", options=sorted(df["typ"].dropna().unique()), index=1)
|
||||||
obj = st.sidebar.multiselect("obj", sorted(df["obj"].dropna().unique()))
|
obj = st.sidebar.multiselect("obj", sorted(df["obj"].dropna().unique()))
|
||||||
zgrp1 = st.sidebar.multiselect("ZGrp1", sorted(df["zgrp1"].dropna().unique()))
|
zgrp1 = st.sidebar.multiselect("ZGrp1", sorted(df["zgrp1"].dropna().unique()))
|
||||||
zgrp2 = st.sidebar.multiselect("ZGrp2", sorted(df["zgrp2"].dropna().unique()))
|
zgrp2 = st.sidebar.multiselect("ZGrp2", sorted(df["zgrp2"].dropna().unique()))
|
||||||
@@ -100,9 +125,14 @@ def render_table(df):
|
|||||||
|
|
||||||
Keep this function presentation-only: it should not modify data.
|
Keep this function presentation-only: it should not modify data.
|
||||||
"""
|
"""
|
||||||
|
st.markdown("### Übersicht Kostenobjekte")
|
||||||
st.dataframe(df, hide_index=True, width="stretch", height="stretch")
|
st.dataframe(df, hide_index=True, width="stretch", height="stretch")
|
||||||
|
|
||||||
|
|
||||||
|
def download_data(df):
|
||||||
|
df.to_excel(path)
|
||||||
|
|
||||||
|
|
||||||
def page():
|
def page():
|
||||||
"""
|
"""
|
||||||
Page entry point: orchestrates data loading, UI, filtering, and rendering.
|
Page entry point: orchestrates data loading, UI, filtering, and rendering.
|
||||||
@@ -129,10 +159,9 @@ def page():
|
|||||||
# -----------------------------
|
# -----------------------------
|
||||||
# Presentation
|
# Presentation
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
|
|
||||||
df = df.sort_values(by="obj", key=lambda s: pd.to_numeric(s, errors="coerce"))
|
|
||||||
df_clean = df[df.columns[:-1]] # letzte Spalten entfernen (sysdate)
|
df_clean = df[df.columns[:-1]] # letzte Spalten entfernen (sysdate)
|
||||||
df_display = df_clean.loc[mask]
|
df_display = df_clean.loc[mask]
|
||||||
|
df_display = df_display.sort_values(by="obj", key=lambda s: pd.to_numeric(s, errors="coerce"))
|
||||||
render_table(df_display)
|
render_table(df_display)
|
||||||
|
|
||||||
col1, col2 = st.columns(2)
|
col1, col2 = st.columns(2)
|
||||||
@@ -141,11 +170,15 @@ def page():
|
|||||||
|
|
||||||
with col1:
|
with col1:
|
||||||
st.text(f"Datenstand: {data_as_of}")
|
st.text(f"Datenstand: {data_as_of}")
|
||||||
st.text("Datenquelle: Oracle (PENTA)")
|
|
||||||
with col2:
|
with col2:
|
||||||
st.markdown(f"<div style='text-align: right;'>Anzahl Zeilen: {row_count}</div>", unsafe_allow_html=True)
|
st.markdown(f"<div style='text-align: right;'>Anzahl Zeilen: {row_count}</div>", unsafe_allow_html=True)
|
||||||
|
|
||||||
|
st.download_button(
|
||||||
|
"📊 Excel-Datei herunterladen",
|
||||||
|
data=df_to_excel_bytes(df_display),
|
||||||
|
file_name="kostenobjekte",
|
||||||
|
mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
16
app/tools/excel_export.py
Normal file
16
app/tools/excel_export.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import pandas as pd
|
||||||
|
import io
|
||||||
|
|
||||||
|
def df_to_excel_bytes(df):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Convert a DataFrame to an in-memory XLSX file.
|
||||||
|
|
||||||
|
Returns a BytesIO object suitable for st.download_button(data=...).
|
||||||
|
"""
|
||||||
|
|
||||||
|
buffer = io.BytesIO()
|
||||||
|
with pd.ExcelWriter(buffer, engine="openpyxl") as writer:
|
||||||
|
df.to_excel(writer, index=False, sheet_name="Daten")
|
||||||
|
buffer.seek(0)
|
||||||
|
return buffer
|
||||||
5
app/tools/help_text.py
Normal file
5
app/tools/help_text.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from app_db.app_db import get_value
|
||||||
|
|
||||||
|
def get_help(dashboard :str):
|
||||||
|
helptext = get_value(f"select dash_description from dashboards where dash_name = '{dashboard}.py'")
|
||||||
|
return helptext
|
||||||
11
config/settings.py
Normal file
11
config/settings.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
BASE_DIR = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
STORAGE_DIR = BASE_DIR / "storage"
|
||||||
|
DB_DIR = STORAGE_DIR / "app_db"
|
||||||
|
DB_PATH = DB_DIR / "app.db"
|
||||||
|
DWH_DIR = STORAGE_DIR / "dwh"
|
||||||
|
|
||||||
|
|
||||||
|
print(BASE_DIR, DB_DIR)
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
begin;
|
||||||
|
|
||||||
|
alter table dashboards
|
||||||
|
add column dash_name text not null default "";
|
||||||
|
|
||||||
|
INSERT INTO schema_version (version) VALUES ('20260226_095800_add_col_dashname_dashboards');
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
Reference in New Issue
Block a user