Skip to content

Commit

Permalink
feat: add URL routing system and share button to every page
Browse files Browse the repository at this point in the history
  • Loading branch information
Elijas committed Nov 19, 2023
1 parent af35192 commit aaf766a
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 43 deletions.
60 changes: 50 additions & 10 deletions dev_utils/dashboard_app/app.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
from enum import Enum
import contextlib
from enum import Enum, auto
from urllib.parse import urlencode

import rich.traceback
import streamlit as st
import streamlit_antd_components as sac

import dev_utils.dashboard_app.streamlit_utils as st_utils
from dev_utils.core.config import get_config
from dev_utils.core.sec_edgar_reports_getter import SecEdgarReportsGetter
from dev_utils.dashboard_app.constants import example_queries_items
from dev_utils.dashboard_app.select_reports import render_select_reports
from dev_utils.dashboard_app.view_parsed.view_parsed import render_view_parsed

rich.traceback.install()
URL_PARAM_KEY = "p"

rich.traceback.install()
###################
### Page config ###
###################
Expand All @@ -24,14 +28,17 @@
layout="wide",
)
st_utils.st_multiselect_allow_long_titles()
st_utils.st_change_decoration_color()
st_utils.st_modify_decoration(hide=True)
st_utils.st_remove_top_page_margin()
st_utils.st_adjust_madewithstreamlit()
st_utils.st_replace_menu_with_share_link_to_this_page_placeholder_button()

###################
### Persistence ###
###################

url_params_queries = st.experimental_get_query_params().get("q", [])
url_query_params = st.experimental_get_query_params()
url_params_queries = url_query_params.get("q", [])

if "select_reports__queries" not in st.session_state:
default = ""
Expand All @@ -53,8 +60,8 @@


class NavbarItems(Enum):
SELECT_REPORTS = 0
VIEW_PARSED = 1
SELECT_REPORTS = auto()
VIEW_PARSED = auto()

@classmethod
def get_items(cls):
Expand All @@ -63,35 +70,68 @@ def get_items(cls):
sac.SegmentedItem(icon="search", label="view parsed"),
]

def serialize(self):
return self.name.lower()

@classmethod
def deserialize(cls, name: str):
return NavbarItems[name.upper()]


default_nav_bar_selection = NavbarItems.SELECT_REPORTS.value
with contextlib.suppress(Exception):
default_nav_bar_selection = NavbarItems.deserialize(
url_query_params[URL_PARAM_KEY][0]
).value
selected_navbar = NavbarItems(
sac.segmented(
1
+ sac.segmented(
items=NavbarItems.get_items(), # type: ignore
format_func="title",
align="center",
return_index=True,
index=default_nav_bar_selection - 1,
),
)

##############
### Runner ###
##############

query_elements = None
if selected_navbar == NavbarItems.SELECT_REPORTS:
render_select_reports()
query_elements = render_select_reports()
elif selected_navbar == NavbarItems.VIEW_PARSED:
render_view_parsed()
query_elements = render_view_parsed()

##############
### Footer ###
##############

# this is for metadata queries
metadata_queries = st.session_state.select_reports__queries
metadata_query_list = SecEdgarReportsGetter.raw_query_to_list(metadata_queries)

# this is for URL queries
query_elements = [
(URL_PARAM_KEY, selected_navbar.serialize()),
*(query_elements or []),
*([("q", query) for query in metadata_query_list]),
]
queries = urlencode(query_elements, doseq=True)
st_utils.st_set_url_to_share_link_to_this_page_placeholder_button(f"/?{queries}")

footer = f"v{get_config().sec_parser_version}"
if not get_config().environment.is_prod:
footer = f"[{get_config().environment.value}] {footer}"
st.markdown(
f"""
<div style="position: fixed; right: 20px; bottom: 10px; width: 100%; text-align: right; color: #aaa;">
<div style="position: fixed;
right: 18px;
bottom: 8px;
width: 100%;
text-align: right;
color: #eee;">
{footer}
</div>
""",
Expand Down
17 changes: 17 additions & 0 deletions dev_utils/dashboard_app/core/download_metadatas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import streamlit as st

from dev_utils.core.sec_edgar_reports_getter import (
SecEdgarReportsGetter,
get_filing_metadatas,
)


def global_get_report_metadatas():
queries = st.session_state.select_reports__queries
query_list = SecEdgarReportsGetter.raw_query_to_list(queries)
report_metadatas = []
for query in query_list:
new_reports = get_filing_metadatas(query)
report_metadatas.extend(new_reports)
st.session_state.select_reports__report_metadatas = report_metadatas
return query_list, report_metadatas
20 changes: 10 additions & 10 deletions dev_utils/dashboard_app/select_reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
get_filing_metadatas,
)
from dev_utils.dashboard_app.constants import example_queries_items
from dev_utils.dashboard_app.core.download_metadatas import global_get_report_metadatas
from dev_utils.dashboard_app.python_utils import smart_join


Expand Down Expand Up @@ -45,28 +46,27 @@ def render_select_reports():

to_add = [k for k in addlist if k not in current]
current.extend(to_add)
st.session_state.select_reports__queries = smart_join(current)
queries = smart_join(current)

st.session_state.select_reports__queries = queries
st_utils.st_unkeep("select_reports__queries")
queries = st.text_area(
"Enter your queries separated by commas and/or newlines:",
key="_select_reports__queries",
on_change=lambda: st_utils.st_keep("select_reports__queries"),
)

query_list = SecEdgarReportsGetter.raw_query_to_list(queries)
query_list, report_metadatas = global_get_report_metadatas()

reports = []
table_container = st.empty()
for query in query_list:
new_reports = get_filing_metadatas(query)
reports.extend(new_reports)
if reports:
reports_dict_list = SecEdgarReportsGetter.to_dict_list(reports)
if report_metadatas:
reports_dict_list = SecEdgarReportsGetter.to_dict_list(report_metadatas)
table_container.dataframe(reports_dict_list, use_container_width=False)

st.session_state.select_reports__report_metadatas = reports
st.session_state.select_reports__report_metadatas = report_metadatas

queries = urlencode([("q", query) for query in query_list], doseq=True)
query_elements = [("q", query) for query in query_list]
queries = urlencode(query_elements, doseq=True)

if query_list:
sac.buttons(
Expand Down
143 changes: 130 additions & 13 deletions dev_utils/dashboard_app/streamlit_utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,110 @@
import contextlib

import streamlit as st
import streamlit_antd_components as sac


def st_adjust_madewithstreamlit():
st.markdown(
"""
<style>
footer {
padding-left: 15px !important;
color: rgb(238, 238, 238) !important;
z-index: 1;
}
footer a {
color: rgb(210, 210, 210) !important;
}
</style>
""",
unsafe_allow_html=True,
)


def st_replace_menu_with_share_link_to_this_page_placeholder_button():
# Shared styles for the buttons
style = """
<style>
#MainMenu {
margin-right: 50px;
visibility: hidden;
}
.shareLinkToThisPageButton {
position: fixed;
top: 7px;
right: 7px;
background-color: #f0f2f6;
color: #31333e !important;
border: none;
padding: 5px 10px;
border-radius: 0.5rem;
cursor: pointer;
z-index: 9999999999;
text-decoration: none;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
font-weight: 500;
font-size: 1rem;
transition: background-color 0.3s ease, color 0.3s ease;
}
.shareLinkToThisPageButton:hover {
background-color: #777ea4;
color: #fff !important;
text-decoration: none; // Added this line to remove underline on hover
transition: color 0.3s ease; // Added this line to add transition to color change on hover
}
.shareLinkToThisPageButton:active {
background-color: #31333e;
color: #f0f2f6;
}
@media (max-width: 768px) {
#MainMenu {
margin-right: 5px;
}
.shareLinkToThisPageButtonText {
font-size: 0;
}
.shareLinkToThisPageButtonIcon {
display: inline;
}
}
@media (min-width: 769px) {
.shareLinkToThisPageButtonIcon {
display: none;
}
}
.shareLinkToThisPageButtonPlaceholder {
cursor: not-allowed;
}
</style>
"""
# Placeholder button
st.markdown(
style
+ '<a class="shareLinkToThisPageButtonPlaceholder shareLinkToThisPageButton" href="'
+ "#"
+ """"><span class="shareLinkToThisPageButtonIcon">🔗</span><span class="shareLinkToThisPageButtonText">🔗 Share</span></a>""",
unsafe_allow_html=True,
)


def st_set_url_to_share_link_to_this_page_placeholder_button(url: str):
style = """
<style>
.shareLinkToThisPageButtonPlaceholder {
display: none;
}
</style>
"""
st.markdown(
style
+ '<a class="shareLinkToThisPageButton" href="'
+ url
+ """"><span class="shareLinkToThisPageButtonIcon">🔗</span><span class="shareLinkToThisPageButtonText">🔗 Share</span></a>""",
unsafe_allow_html=True,
)


def st_divider(label, icon, *, align="center", bold=False):
sac.divider(
label=label,
Expand Down Expand Up @@ -34,19 +137,31 @@ def st_expander_allow_nested(): # noqa: ANN201
__ = _


def st_change_decoration_color():
st.markdown(
"""
<style>
div[data-testid="stDecoration"] {
background: none; /* This removes any background images or gradients */
background-color: #767FA6; /* This sets the background color to your primary color */
background-image: linear-gradient(90deg, #767FA6, #0000FF); /* This sets the new gradient */
}
</style>
""",
unsafe_allow_html=True,
)
def st_modify_decoration(hide=False):
if hide:
st.markdown(
"""
<style>
div[data-testid="stDecoration"] {
display: none;
}
</style>
""",
unsafe_allow_html=True,
)
else:
st.markdown(
"""
<style>
div[data-testid="stDecoration"] {
background: none; /* This removes any background images or gradients */
background-color: #f0f2f6; /* This sets the background color to your primary color */
background-image: linear-gradient(90deg, #f0f2f6, #777ea4); /* This sets the new gradient */
}
</style>
""",
unsafe_allow_html=True,
)


def st_remove_top_page_margin():
Expand All @@ -66,3 +181,5 @@ def st_unkeep(key):
"https://stackoverflow.com/questions/74968179/session-state-is-reset-in-streamlit-multipage-app"
# Copy from permanent key to temporary widget key
st.session_state["_" + key] = st.session_state[key]
st.session_state["_" + key] = st.session_state[key]
st.session_state["_" + key] = st.session_state[key]
2 changes: 1 addition & 1 deletion dev_utils/dashboard_app/view_parsed/performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def render_view_parsed_performance(previous_parsing_output: ParsingOutput, name)
with st.sidebar:
options = [
f"{x:.{max(1, 1-int(np.floor(np.log10(x))))}f}".rstrip("0")
for x in np.logspace(-4.5, -1, 100)
for x in np.logspace(-4.1, -1, 100)
]
interval = st.select_slider(
"Set sampling interval (seconds)",
Expand Down
Loading

0 comments on commit aaf766a

Please sign in to comment.