Skip to content

Commit

Permalink
Introduce single page apps. (#3656)
Browse files Browse the repository at this point in the history
* Introduce single page apps.
  • Loading branch information
dfitchett authored Oct 28, 2024
1 parent 392fd9e commit 8f1ab5f
Show file tree
Hide file tree
Showing 32 changed files with 390 additions and 73 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test-code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -186,5 +186,5 @@ jobs:
- name: "Run VRO Streamlit tests"
if: inputs.run_all_tests || steps.vro-streamlit-changed-files-specific.outputs.any_changed == 'true'
run: |
# ./gradlew :vro-streamlit:test
echo "skipping tests for now..."
./gradlew :vro-streamlit:check
# echo "skipping tests for now..."
4 changes: 2 additions & 2 deletions vro-streamlit/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ tasks.getByPath('pytest').configure {
tasks.register('integrationPytest', PythonTask) {
dependsOn 'appinstall'
module = 'pytest'
command = './integration'
command = './integration --no-cov'
}

tasks.register('integrationTest', Test) {
Expand All @@ -49,7 +49,7 @@ tasks.register('integrationTest', Test) {
tasks.register('endToEndPytest', PythonTask) {
dependsOn 'appinstall'
module = 'pytest'
command = './end_to_end'
command = './end_to_end --no-cov'
}

tasks.register('endToEndTest', Test) {
Expand Down
2 changes: 1 addition & 1 deletion vro-streamlit/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
cd app || exit
cd vro_streamlit || exit

python -m streamlit run main.py
5 changes: 3 additions & 2 deletions vro-streamlit/end_to_end/test_end_to_end.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from streamlit.testing.v1 import AppTest


def test_main() -> None:
app = AppTest.from_file('src/app/main.py')
app = AppTest.from_file('src/vro_streamlit/main.py')
app.run()
assert not app.exception
assert not app.exception
5 changes: 3 additions & 2 deletions vro-streamlit/integration/test_integration.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from streamlit.testing.v1 import AppTest


def test_main() -> None:
app = AppTest.from_file('src/app/main.py')
app = AppTest.from_file('src/vro_streamlit/main.py')
app.run()
assert not app.exception
assert not app.exception
9 changes: 6 additions & 3 deletions vro-streamlit/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# pyproject.toml
[project]
name = 'app'
name = 'vro-streamlit'
version = '0.1'
requires-python = '>=3.10'

[tool.setuptools.package-data]
app = [".streamlit/*", "static/*"]
vro_streamlit = [".streamlit/*", "static/*"]

[tool.pytest.ini_options]
minversion = "6.0"
Expand All @@ -28,7 +28,10 @@ env = [

[tool.coverage.run]
# The following files are for development purposes and are not part of the coverage report
omit = []
omit = [
"**/bie_events/**",
"**/examples/**",
]

[tool.isort]
profile = "black"
Expand Down
22 changes: 0 additions & 22 deletions vro-streamlit/src/app/main.py

This file was deleted.

File renamed without changes.
Empty file.
9 changes: 9 additions & 0 deletions vro-streamlit/src/vro_streamlit/auth/auth_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from vro_streamlit.auth.user import User


def log_in() -> User:
return User('test')


def log_out() -> bool:
return True
3 changes: 3 additions & 0 deletions vro-streamlit/src/vro_streamlit/auth/user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class User:
def __init__(self, username: str):
self.username: str = username
File renamed without changes.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# mypy: ignore-errors
# Ignore until this class is implemented

import streamlit as st

from vro_streamlit.service.database import EVENTS_REPO


def show(): # pragma: no cover
st.header('BIE Claim Events')
st.markdown(
'The table below contains BIE Claim Events. For more information and descriptions of the individual fields. Please refer to the '
'[BIE Claim Events](https://confluence.devops.va.gov/display/VAExternal/Subdomain%3A+Claim+Events) domain page for BIE Events.'
)
st.markdown('*The data in this table is for demonstration purposes only and does not reflect real data.*')

st.dataframe(
EVENTS_REPO.get_claim_events(),
hide_index=True,
)


if __name__ == '__main__':
show()
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# mypy: ignore-errors
# Ignore until this class is implemented

import streamlit as st

from vro_streamlit.service.database import EVENTS_REPO


def show(): # pragma: no cover
st.header('BIE Contention Events')
st.markdown(
'The table below contains BIE Contention Events. For more information and descriptions of the individual fields. Please refer to the '
'[BIE Contention Events](https://github.com/department-of-veterans-affairs/abd-vro/wiki/BIE-Contention-Events-User-Guide) page in the VRO Wiki.'
)
st.markdown('*The data in this table is for demonstration purposes only and does not reflect real data.*')

st.dataframe(
EVENTS_REPO.get_contention_events(),
hide_index=True,
)


if __name__ == '__main__':
show()
Empty file.
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
# mypy: ignore-errors

import time

import numpy as np
import pandas as pd
import streamlit as st
from numpy._typing import NDArray

# sidebar config
st.sidebar.image('static/streamlit-logo.png')
st.sidebar.button('Rerun')

if 'color' not in st.session_state:
st.session_state.color = '#FF0000'

st.sidebar.write('Choose a datapoint color')
st.session_state.color = st.sidebar.color_picker('Color', st.session_state.color)

'Random line chart'
last_rows = np.random.randn(1, 1)
chart = st.line_chart(last_rows, color=st.session_state.color)
chart = st.line_chart(last_rows)
progress = st.progress(0)

for i in range(1, 101):
Expand Down Expand Up @@ -54,7 +46,7 @@ def rand_5_8() -> NDArray[np.float64]:
'Map'
map_data = pd.DataFrame(np.random.randn(100, 2) / [50, 50] + [38.66, -78.48], columns=['lat', 'lon'])

st.map(map_data, color=st.session_state.color)
st.map(map_data)

'Selection boxes'
option: int = st.selectbox('Which number do you like best?', df['first column'])
Expand All @@ -66,4 +58,4 @@ def rand_5_8() -> NDArray[np.float64]:
st.session_state.df = pd.DataFrame(np.random.randn(20, 2), columns=['x', 'y'])

st.divider()
st.scatter_chart(st.session_state.df, x='x', y='y', color=st.session_state.color)
st.scatter_chart(st.session_state.df, x='x', y='y')
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
# mypy: ignore-errors

import numpy as np
import pandas as pd
import streamlit as st

# sidebar config
st.sidebar.image('static/streamlit-logo.png')
st.sidebar.button('Rerun')

if 'color' not in st.session_state:
st.session_state.color = '#FF0000'

st.sidebar.write('Choose a datapoint color')
st.session_state.color = st.sidebar.color_picker('Color', st.session_state.color)

st.header('Streamlit text elements')
st.title('Title')
st.header('Header')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
# mypy: ignore-errors

import pandas as pd
import streamlit as st

# sidebar config
st.sidebar.image('static/streamlit-logo.png')
st.sidebar.button('Rerun')

if 'color' not in st.session_state:
st.session_state.color = '#FF0000'

st.sidebar.write('Choose a datapoint color')
st.session_state.color = st.sidebar.color_picker('Color', st.session_state.color)

st.title('Water Quality (pH)')
st.markdown('From [fws.gov](https://ecos.fws.gov/ServCat/DownloadFile/173741?Reference=117348)')
df = pd.DataFrame(pd.read_csv('https://ecos.fws.gov/ServCat/DownloadFile/173741?Reference=117348'), columns=['Read_Date', 'pH (standard units)'])

st.dataframe(df, use_container_width=True)

st.line_chart(df, x='Read_Date', color=st.session_state.color)
st.line_chart(df, x='Read_Date')
35 changes: 35 additions & 0 deletions vro-streamlit/src/vro_streamlit/directory/home.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from importlib.resources import files

import streamlit as st

import vro_streamlit.auth.auth_service as auth

LOGIN_BUTTON = 'home_login_button'
LOGO = files('vro_streamlit').joinpath('static/streamlit-logo.png').read_bytes()


def update_login_status() -> None:
if not st.session_state.user:
st.session_state.user = auth.log_in()
else:
if auth.log_out():
st.session_state.user = None


def show() -> None:
col1, col2 = st.columns([0.04, 0.96])
col1.image(LOGO, width=100)
col2.header('Home')
st.subheader('Welcome to the home page!')

user = st.session_state.get('user')
if user:
st.write(f'Hello, {user.username}!')
st.button('Log Out', key=LOGIN_BUTTON, on_click=update_login_status)
else:
st.write('Please Log In')
st.button('Log In', key=LOGIN_BUTTON, on_click=update_login_status)


if __name__ == '__main__':
show()
65 changes: 65 additions & 0 deletions vro-streamlit/src/vro_streamlit/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import streamlit as st

import vro_streamlit.auth.auth_service as auth
import vro_streamlit.config as config
import vro_streamlit.directory.home as home
from vro_streamlit.directory.bie_events import claim_events, contention_events

LOGIN_BUTTON = 'sidebar_login_button'
LOGOUT_BUTTON = 'sidebar_logout_button'

st.set_page_config(page_title='VRO Streamlit', layout='wide')


def init_session_state() -> None:
st.session_state.setdefault('database_connected', True)
st.session_state.setdefault('user', None)


def update_login_status() -> None:
if not st.session_state.user:
st.session_state.user = auth.log_in()
else:
if auth.log_out():
st.session_state.user = None


def create_navigation() -> None:
home_page = st.Page(home.show, title='Home', default=True)
# BIE events
bie_events = [
st.Page(claim_events.show, title='Claim Events', url_path='/claim_events'),
st.Page(contention_events.show, title='Contention Events', url_path='/contention_events'),
]
# examples
examples = [
st.Page('directory/examples/text.py', title='Text'),
st.Page('directory/examples/dataframes.py', title='Dataframes'),
st.Page('directory/examples/water_quality.py', title='Water Quality'),
]
nav = st.navigation({'Main': [home_page], 'BIE Events': bie_events, 'Examples': examples})
nav.run()


def create_sidebar() -> None:
with st.sidebar:
with st.container(border=True):
col1, col2 = st.columns(2)
with col1:
st.markdown('Environment', help='Current operating environment')
st.markdown('Database', help='Database connection status')
st.markdown('Authorized', help='User authorization status')
with col2:
st.markdown(f'`{config.ENV}`')
st.markdown(':large_green_circle:' if st.session_state.database_connected else ':red_circle:', unsafe_allow_html=True)
st.markdown(':large_green_circle:' if st.session_state.user else ':red_circle:', unsafe_allow_html=True)

button_text = 'Log Out' if st.session_state.user else 'Log In'
button_key = LOGOUT_BUTTON if st.session_state.user else LOGIN_BUTTON
st.button(button_text, use_container_width=True, on_click=update_login_status, key=button_key)


if __name__ == '__main__':
init_session_state()
create_sidebar()
create_navigation()
Empty file.
Loading

0 comments on commit 8f1ab5f

Please sign in to comment.