Files
shelly-ui/.agents/skills/developing-with-streamlit/templates/apps/README.md
T
jonas 71803418e5 Initial commit: Shelly Manager with Textual CLI, Streamlit UI, and comprehensive .gitignore
Shelly device management app with mDNS/subnet discovery, inventory,
configuration, and mass operations for Gen1/Gen2+ devices.

Includes .gitignore excluding runtime data (device DB, user config),
AI conversation history, build artifacts, and common Python/OS patterns.
2026-03-23 21:51:59 +01:00

5.7 KiB

Streamlit Dashboard App Templates

This directory contains ready-to-use dashboard templates for Streamlit. Each template demonstrates best practices for building data-driven dashboards with modern UI patterns.

Available Templates

Public Demo Templates

These templates are based on official Streamlit demo apps and work out of the box:

Template Description Key Features
dashboard-seattle-weather Weather data exploration dashboard st.metric, st.pills, st.altair_chart, year comparison
dashboard-stock-peers Stock peer analysis and comparison st.multiselect, normalized charts, peer average calculation
dashboard-stock-peers-snowflake Same as above but using Snowflake st.connection("snowflake"), synthetic stock data in SQL

Analytics Dashboard Templates

These templates demonstrate common dashboard patterns with synthetic data. Replace the data generation functions with your actual data sources:

Template Description Key Features
dashboard-metrics Core metrics dashboard with KPIs Chart/table toggle, st.popover filters, TIME_RANGES (1M/6M/1Y/QTD/YTD/All)
dashboard-metrics-snowflake Same as above but using Snowflake st.connection("snowflake"), SQL-based data generation
dashboard-feature-usage API endpoint usage analytics Segmented control, starter kits, normalization toggle, rolling averages
dashboard-companies Company leaderboard with drill-down Interactive dataframe, sparkline columns, growth scores
dashboard-compute Resource consumption monitoring @st.fragment, st.popover filters, TIME_RANGES, line/bar toggle
dashboard-compute-snowflake Same as above but using Snowflake st.connection("snowflake"), SQL-based data generation

Quick Start

Run a Template Locally

# Navigate to a template directory
cd templates/apps/dashboard-metrics

# Install dependencies with uv
uv pip install -e .

# Run the app
uv run streamlit run streamlit_app.py

Template Structure

Each template follows this structure:

dashboard-{name}/
├── streamlit_app.py    # Main application code
└── pyproject.toml      # Dependencies and metadata

Canonical Patterns

When creating new templates or adapting existing ones, follow these patterns for consistency.

Page Configuration

Always set page config as the first Streamlit call, with layout="wide" and a Material icon:

st.set_page_config(
    page_title="My Dashboard",
    page_icon=":material/monitoring:",
    layout="wide",
)

Constants

Use these standard constant names:

TIME_RANGES = ["1M", "6M", "1Y", "QTD", "YTD", "All"]
CHART_HEIGHT = 300  # Standard chart height in pixels

Time Range Filtering

All dashboard templates that support time filtering use the same filter_by_time_range function:

def filter_by_time_range(df: pd.DataFrame, x_col: str, time_range: str) -> pd.DataFrame:
    """Filter dataframe by time range."""
    if time_range == "All" or df.empty:
        return df

    df = df.copy()
    df[x_col] = pd.to_datetime(df[x_col])
    max_date = df[x_col].max()

    if time_range == "1M":
        min_date = max_date - timedelta(days=30)
    elif time_range == "6M":
        min_date = max_date - timedelta(days=180)
    elif time_range == "1Y":
        min_date = max_date - timedelta(days=365)
    elif time_range == "QTD":
        quarter_month = ((max_date.month - 1) // 3) * 3 + 1
        min_date = pd.Timestamp(date(max_date.year, quarter_month, 1))
    elif time_range == "YTD":
        min_date = pd.Timestamp(date(max_date.year, 1, 1))
    else:
        return df

    return df[df[x_col] >= min_date]

Popover Filters

Compact filter controls using st.popover:

with st.popover("Filters", type="tertiary"):
    line_options = st.pills("Lines", ["Daily", "7-day MA"], selection_mode="multi")
    time_range = st.segmented_control("Time range", TIME_RANGES, default="All")

Page Header with Reset Button

def render_page_header(title: str):
    """Render page header with title and reset button."""
    with st.container(
        horizontal=True, horizontal_alignment="distribute", vertical_alignment="center"
    ):
        st.markdown(title)
        if st.button(":material/restart_alt: Reset", type="tertiary"):
            st.session_state.clear()
            st.rerun()

Independent Widget Updates with @st.fragment

@st.fragment
def metric_card():
    with st.container(border=True):
        # This widget updates independently without full page rerun
        ...

Snowflake Column Normalization

Snowflake returns uppercase column names. Always normalize after queries:

df = conn.query(query)
df.columns = df.columns.str.lower()

Snowflake Connection Error Handling

try:
    get_snowflake_connection()
except Exception as e:
    st.error(f"Failed to connect to Snowflake: {e}")
    st.info(
        "Make sure you have configured your Snowflake connection in "
        "`.streamlit/secrets.toml` or via environment variables."
    )
    st.stop()

Data Loading with Caching

@st.cache_data(ttl=3600)
def load_metric_data() -> pd.DataFrame:
    """Load metric data. Replace with your actual data source."""
    # Replace this with:
    # - Snowflake query via st.connection("snowflake")
    # - API call
    # - Database query
    return generate_synthetic_data()

Dependencies

All templates require Python >=3.11 and use:

  • snowflake-connector-python>=3.3.0 (required — streamlit[snowflake] silently skips this on Python 3.12+)
  • streamlit[snowflake]>=1.54.0
  • altair>=5.5.0
  • pandas>=2.2.3
  • numpy>=1.26.0