Initial import
Some checks failed
Build & Release / build-docker-image (push) Failing after 3m15s
Build & Release / deploy-to-production (push) Has been skipped

This commit is contained in:
2026-03-31 19:09:37 +02:00
commit da7e881311
24 changed files with 2990 additions and 0 deletions

96
app/pages/counters.py Normal file
View File

@@ -0,0 +1,96 @@
import streamlit as st
import sql
from enums import CounterType
@st.dialog("Add New Counter", icon=":material/add_box:")
def _add_counter():
colors = sql.get_colors(1)
with st.form(key="add_counter", border=False, clear_on_submit=True):
title = st.text_input("Title:")
counter_type_name = st.selectbox("Type", options=[e.name for e in CounterType])
color = st.radio("Color",
key="color-selector",
width="stretch",
options=[colors[key][0] for key in colors],
format_func=lambda c: f"#{c}")
with st.container(horizontal=True, width="stretch", horizontal_alignment="center"):
if st.form_submit_button(label="Create", icon=":material/save:"):
sql.create_counter(title, CounterType[counter_type_name], color)
st.rerun()
@st.dialog("Remove Counter", icon=":material/delete:")
def _remove_counter(counter_id:int):
with st.form(key="remove_counter", border=False, clear_on_submit=True):
st.subheader("Are you sure?")
with st.container(horizontal=True, width="stretch", horizontal_alignment="center"):
if st.form_submit_button("Confirm", icon=":material/delete:"):
sql.remove_counter(counter_id)
st.rerun()
df = sql.get_counters()
with st.container(key="counter-table"):
for counter_id, name, counter_type_str, color in zip(df['id'], df['name'], df['type'], df['color']):
with st.container(width="stretch", key=f"counter_{counter_id}"):
with st.container(horizontal=True, width="stretch"):
st.header(f":material/calendar_clock: {name}", width="stretch")
if st.button("", icon=":material/exposure_plus_1:", key=f"increment_counter_{counter_id}"):
sql.increment_counter(counter_id)
st.rerun()
if st.button("", icon=":material/delete_forever:", key=f"remove_counter_{counter_id}"):
_remove_counter(counter_id)
with st.container(horizontal=True, width="stretch"):
counter_type = CounterType(counter_type_str)
stats_current_unit = counter_type.current_unit_text()
stats_prev_unit = counter_type.previous_unit_text()
match counter_type:
case CounterType.DAILY.value | CounterType.SIMPLE.value:
stats = sql.get_daily_analytics(counter_id)
stats_current = stats.iloc[0]["count"]
stats_prev = stats.iloc[1]["count"]
case CounterType.WEEKLY.value:
stats = sql.get_weekly_analytics(counter_id)
stats_current = stats.iloc[-1]["count"]
stats_prev = stats.iloc[-2]["count"]
case CounterType.MONTHLY.value:
stats = sql.get_monthly_analytics(counter_id)
stats_current = stats.iloc[-1]["count"]
stats_prev = stats.iloc[-2]["count"]
case CounterType.YEARLY.value:
stats = sql.get_yearly_analytics(counter_id)
stats_current = stats.iloc[-1]["count"]
stats_prev = stats.iloc[-2]["count"]
if counter_type is CounterType.SIMPLE.value:
st.markdown(f"**{stats_current} {stats_current_unit}**")
else:
st.markdown(f"""
**{stats_current} {stats_current_unit}**
*{stats_prev} {stats_prev_unit}*
""")
with st.container(horizontal=True, width="stretch", horizontal_alignment="right"):
st.page_link("pages/stats.py", icon=":material/bar_chart:", icon_position="right", label="", query_params={"counter_id": str(counter_id)})
st.html(f"""
<style>
div:has(> .st-key-counter_{counter_id}) {{
background-color: {color};
}}
</style>
""")
if st.button("Add Counter", width="stretch", icon=":material/add_box:"):
_add_counter()

44
app/pages/stats.py Normal file
View File

@@ -0,0 +1,44 @@
import logging
import streamlit as st
import json
import sql
import pandas as pd
from enums import CounterType
logger = logging.getLogger(__name__)
if "counter_id" in st.query_params.keys():
counter_id = int(st.query_params["counter_id"])
df = sql.get_counter(counter_id)
st.header('Counter: ' + df['name'])
color ='#' + df['color']
match df['type']:
case CounterType.DAILY.value | CounterType.SIMPLE.value:
st.bar_chart(sql.get_daily_analytics(int(df['id'])), x="date", y="count", color=color)
case CounterType.WEEKLY.value:
st.bar_chart(sql.get_weekly_analytics(int(df['id'])), x="week", y="count", color=color)
case CounterType.MONTHLY.value:
st.bar_chart(sql.get_monthly_analytics(int(df['id'])), x="month", y="count", color=color)
case CounterType.YEARLY.value:
st.bar_chart(sql.get_yearly_analytics(int(df['id'])), x="year", y="count", color=color)
else:
st.header("Statistics")
entries = sql.get_analytics()
entries_norm = pd.json_normalize(entries.counters.apply(json.loads)).fillna(0)
entries_full = pd.concat([entries, entries_norm], axis=1).drop(['counters'], axis=1)
selected_counters = [c for c in entries_full.columns if c != "date"]
all_counters = sql.get_counters()
colors = all_counters.loc[all_counters['name'].isin(selected_counters), ["name", "color"]]
colors.name = colors.name.astype("category")
colors.name = colors.name.cat.set_categories(selected_counters)
colors = colors.sort_values(["name"])
colors = colors.color.apply(lambda c: "#" + c).tolist()
st.bar_chart(entries_full, x="date", x_label="Date", y_label="Count", color=colors)