# app.py
# Minimal Streamlit status board using ONLY built-in components (no Altair).
# - Connects directly to Postgres
# - Orders rows: ORDER BY ref_x DESC, ref_12 DESC, ref_16 DESC
# - Fixed column order: ref_x, ref_12, ref_16
# - Each "dot" is a clickable link button to your File Browser URL
# - Two generic action buttons per row (function placeholders provided)
import os
from urllib.parse import quote
import pandas as pd
import streamlit as st
from sqlalchemy import create_engine, text
# -----------------------------
# Configuration
# -----------------------------
st.set_page_config(page_title="File Processing Status", layout="wide")
# Hide chrome for a minimal look
st.markdown(
"""
""",
unsafe_allow_html=True,
)
# DB config (fill via st.secrets or env)
DB_HOST = "postgres"
DB_PORT = "5432"
DB_NAME = "mydatabase"
DB_USER = "myuser"
DB_PASSWORD = "mypassword"
TABLE_NAME = "decorrupt"
# Optional: restrict columns; leave empty to auto-detect
REF_PREFIX = "ref_"
# File Browser base (adjust to your host/IP)
FILEBROWSER_BASE = "http://192.168.1.229:8081/files"
# Expected ref columns (fixed order)
REF_COLS = ["ref_x", "ref_12", "ref_16"]
# Dot icons for statuses (built-in emoji; no custom CSS/JS)
DOTS = {
-1: "🔴", # unknown/error
0: "⚪", # not processing (gray/white)
1: "🟠", # processing (orange)
2: "🟢", # processed (green)
}
LABELS = {0: "not processing", 1: "processing", 2: "processed", -1: "unknown"}
def update_status(filename: str, column_name: str, new_value: int) -> bool:
"""
Update a single column for a given filename in the specified table.
Args:
filename (str): The filename to update.
table_name (str): The table where the row exists.
column_name (str): The column to update (e.g., 'ref_x').
new_value (int): The new status value (e.g., 0, 1, 2).
Returns:
bool: True if update succeeded, False otherwise.
"""
sql = text(f'UPDATE "decorrupt" SET "{column_name}" = :new_value WHERE filename = :filename')
try:
engine = get_engine() # reuse your existing get_engine()
with engine.begin() as conn: # auto-commits or rolls back
result = conn.execute(sql, {"new_value": new_value, "filename": filename})
return result.rowcount > 0
except Exception as e:
st.error(f"Failed to update {filename}.{column_name}: {e}")
return False
# -----------------------------
# DB helpers
# -----------------------------
def get_engine():
url = f"postgresql+psycopg2://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
return create_engine(url, pool_pre_ping=True)
def load_data(table_name: str) -> pd.DataFrame:
query = text(f'SELECT * FROM "{table_name}" WHERE isdeleted = 0 ORDER BY filename')
with get_engine().connect() as conn:
return pd.read_sql(query, conn)
# -----------------------------
# Actions (function placeholders)
# -----------------------------
def resolve_record(filename: str):
update_status(filename = filename, column_name = "isresolved", new_value = 1)
st.toast(f"{filename} resolved")
def delete_record(filename: str):
update_status(filename = filename, column_name = "isdeleted", new_value = 1)
st.toast(f"{filename} deleted")
# -----------------------------
# Load & validate
# -----------------------------
st.title("File Processing Status")
st.caption("0 = not processing · 1 = processing · 2 = processed")
if "