-
Notifications
You must be signed in to change notification settings - Fork 1
V1.0.0 A smaller, smooter, cleaner, clearer framework #23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from all commits
Commits
Show all changes
63 commits
Select commit
Hold shift + click to select a range
412ef0e
First steps
ponsoc 40a7bf5
Version bump
ponsoc ce15cf5
Flow and layout are now abstract
ponsoc 58f077f
Component absract
ponsoc 8b158ea
Cleaning the store
ponsoc 489b63e
Sidebar is a component and should be in a layout, not in main app
ponsoc ae2d619
Second attempt
ponsoc e91d374
Review improvements
ponsoc b573115
Update README.md
ponsoc 2296175
Update refresh.py
ponsoc 39da56e
Update metric.py
ponsoc 5fef8ab
No value in current route when properly using the router the layout i…
ponsoc 595912d
Update layout.py
ponsoc fba86fb
Update refresh.py
ponsoc 2b606ff
Update login_succes.py
ponsoc fca3bfe
Update component.py
ponsoc 9833822
formatting
ponsoc fd7676e
formatting
ponsoc 4e71ea9
Resolving first comments
ponsoc 78e2b7f
Formatting and removing unused stuff
ponsoc 65af69f
Cleaning
ponsoc 883a2f0
Added create methods for flow and layout
ponsoc 535b8c3
Introducing toast
ponsoc 3ead59f
Better naming
ponsoc fb75cd1
Some cleaning considered the new framework rules and started with upd…
ponsoc c891361
Update login.py
ponsoc 6ed71ce
Cleaning and docs
ponsoc 1df2ab5
Update login.py
ponsoc 23ea5b2
improved visibility functionality
ponsoc c468adb
doc strings and type hints
ponsoc 5a21bed
final cleaning
ponsoc 7d2c14c
docs strings
ponsoc 790ea1b
Update store.py
ponsoc c17b510
Merge pull request #21 from ponsoc/improve-router2
ponsoc d2b4f1e
Merge branch 'improve-router2' into smaller-footprint
ponsoc 789541f
Update README.md
ponsoc 93b99ec
Added migration guide
ponsoc fdeeee7
Merge pull request #22 from ponsoc/smaller-footprint
ponsoc 180e935
Formatting
ponsoc 5d2fc98
Update README.md
ponsoc f5356ad
Update README.md
ponsoc 3f6261c
Update README.md
ponsoc 4f9782b
Comments Jamie and event handlers for app and routes
ponsoc 82d1ea2
Final changes, component events work now through events
ponsoc c330813
Comments Jamie
ponsoc b9c88d0
Better flow context
ponsoc c4c6ee2
New Fragment and Dialog component types
ponsoc ded77d1
Comments Jamie done
ponsoc 02efdc1
formatting
ponsoc 7cfc0eb
minor naming
ponsoc 1b7df3a
update store tests
ponsoc 086bf9d
update router tests
ponsoc a7a995c
add and update all tests
ponsoc 3534b76
formatting
ponsoc 2460e7f
more formatting
ponsoc b547c39
missed a file
ponsoc ce7a54b
fix minor bug and update test
ponsoc 922f688
fix order
ponsoc 872ca97
schedule and rerun
ponsoc 51034f2
Better way of working with the events
ponsoc 2699b22
Update test_component.py
ponsoc 6f7bd9d
Improved tests and example app
ponsoc c931551
Version and readme
ponsoc File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| [flake8] | ||
| extend-ignore = E203, E501 | ||
| extend-ignore = E203, E501, E731 | ||
| exclude = .github,__pycache__,docs/source/conf.py,old,build,dist,venv, | ||
| max-complexity = 10 |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,4 +2,4 @@ | |
|
|
||
| app = MainApp() | ||
|
|
||
| app.run() | ||
| app.app.run() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,47 @@ | ||
| html, body, * { | ||
| font-style: italic | ||
| } | ||
| } | ||
|
|
||
| .status-icon { | ||
| width: 20px; | ||
| height: 20px; | ||
| border-radius: 50%; | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| font-size: 12px; | ||
| font-weight: bold; | ||
| color: white; | ||
| } | ||
|
|
||
| /* RUNNING (spinner) */ | ||
| .running { | ||
| border: 3px solid rgba(0,0,0,0.1); | ||
| border-left-color: #4CAF50; | ||
| animation: spin 1s linear infinite; | ||
| } | ||
|
|
||
| /* STATIC STATES */ | ||
| .success { | ||
| background-color: #4CAF50; | ||
| } | ||
|
|
||
| .error { | ||
| background-color: #F44336; | ||
| } | ||
|
|
||
| .info { | ||
| background-color: #2196F3; | ||
| } | ||
|
|
||
| /* Spin animation */ | ||
| @keyframes spin { | ||
| 0% { transform: rotate(0deg);} | ||
| 100% { transform: rotate(360deg);} | ||
| } | ||
|
|
||
| .status-row { | ||
| display: flex; | ||
| align-items: center; | ||
| gap: 10px; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import streamlit as st | ||
| from ststeroids import Component, Flow | ||
|
|
||
|
|
||
| class ButtonComponent(Component): | ||
|
|
||
| EVENT_ClICK = "click" | ||
|
|
||
| def __init__(self, button_text: str): | ||
| self.button_text = button_text | ||
|
|
||
| def _handle_click(self): | ||
| self.trigger(self.EVENT_ClICK) | ||
|
|
||
| def display(self): | ||
| st.button(self.button_text, on_click=self._handle_click) | ||
|
|
||
| def on_click(self, flow: Flow) -> None: | ||
| """ | ||
| Register a flow to be executed when the user clicks the button. | ||
| """ | ||
| self.on(self.EVENT_ClICK, flow) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,29 +1,27 @@ | ||
| import uuid | ||
| import streamlit as st | ||
| from ststeroids import Component | ||
|
|
||
|
|
||
| class DataViewerComponent(Component): | ||
| def __init__( | ||
| self, | ||
| component_id: str, | ||
| header: str, | ||
| column_config: dict = {}, | ||
| column_order: list = [], | ||
| ): | ||
| super().__init__(component_id, {"data": None, "dek": uuid.uuid4()}) | ||
| self.header = header | ||
| self.column_config = column_config | ||
| self.column_order = column_order | ||
| self.data = None | ||
|
|
||
| def render(self): | ||
| def display(self): | ||
| st.subheader(self.header) | ||
| st.dataframe( | ||
| self.state.data, | ||
| self.data, | ||
| hide_index=True, | ||
| column_config=self.column_config, | ||
| column_order=self.column_order, | ||
| ) | ||
|
|
||
| def set_data(self, data): | ||
| self.state.data = data | ||
| self.data = data |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,37 +1,31 @@ | ||
| import streamlit as st | ||
| from ststeroids import Component, Flow | ||
| from ststeroids import Dialog, Flow | ||
|
|
||
|
|
||
| class LoginDialogComponent(Component): | ||
| class LoginDialogComponent(Dialog): | ||
|
|
||
| EVENT_LOGIN = "login" | ||
|
|
||
| def __init__( | ||
| self, | ||
| component_id: str, | ||
| login_flow: Flow, | ||
| login_success_flow: Flow, | ||
| header: str = "Enter username/password", | ||
| ): | ||
| super().__init__(component_id, {"visible": False}) | ||
| self.header = header | ||
| self.login_flow = login_flow | ||
| self.login_success_flow = login_success_flow | ||
| self.error_message = None | ||
| self.hide() | ||
|
|
||
| def render(self): | ||
| if self.state.visible: | ||
| username = st.text_input("Username") | ||
| password = st.text_input("Password", type="password") | ||
| if st.button("Login", use_container_width=True): | ||
| login_succes = self.login_flow.execute_run(username, password) | ||
| if login_succes: | ||
| self.login_success_flow.execute_run() | ||
| else: | ||
| st.error("Login failed, please check your username and password.") | ||
| def display(self): | ||
| self.username = st.text_input("Username") | ||
| self.password = st.text_input("Password", type="password") | ||
| if st.button("Login", use_container_width=True): | ||
| self.trigger(self.EVENT_LOGIN) | ||
| if self.error_message: | ||
| st.error(self.error_message) | ||
| self.error_message = None | ||
|
|
||
| def show(self): | ||
| if self.state.visible is False: | ||
| self.state.visible = True | ||
| st.rerun() | ||
| def on_login(self, flow: Flow) -> None: | ||
| """ | ||
| Register a flow to be executed when the user clicks the login button. | ||
| """ | ||
| self.on(self.EVENT_LOGIN, flow) | ||
|
|
||
| def hide(self): | ||
| if self.state.visible is True: | ||
| self.state.visible = False | ||
| st.rerun() | ||
| def set_error(self, message: str): | ||
| self.error_message = message |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,18 +1,17 @@ | ||
| import streamlit as st | ||
| from ststeroids import Component | ||
| from ststeroids import Fragment | ||
|
|
||
|
|
||
| class MetricComponent(Component): | ||
| class MetricComponent(Fragment): | ||
| def __init__( | ||
| self, | ||
| component_id: str, | ||
| header: str, | ||
| ): | ||
| super().__init__(component_id, {"value": None}) | ||
| self.header = header | ||
| self.value = 0 | ||
|
|
||
| def render(self): | ||
| st.metric(self.header, self.state.value) | ||
| def display(self): | ||
| st.metric(self.header, self.value) | ||
|
|
||
| def set_value(self, value: int): | ||
| self.state.value = value | ||
| self.value = value |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,14 @@ | ||
| import streamlit as st | ||
| from ststeroids import Component, Router | ||
| from ststeroids import Component | ||
|
|
||
|
|
||
| class SidebarComponent(Component): | ||
|
|
||
| def __init__(self, component_id: str, router: Router): | ||
| super().__init__(component_id) | ||
| self.router = router | ||
|
|
||
| def render(self): | ||
| def display(self): | ||
| with st.sidebar: | ||
| st.page_link("pages/dashboard.py", icon=":material/search:", label="Dashboard") | ||
| st.page_link("pages/manage.py", icon=":material/bar_chart:", label="Manage data") | ||
|
|
||
| st.page_link( | ||
| "pages/dashboard.py", icon=":material/search:", label="Dashboard" | ||
| ) | ||
| st.page_link( | ||
| "pages/manage.py", icon=":material/bar_chart:", label="Manage data" | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| from typing import Literal | ||
|
|
||
| import streamlit as st | ||
| from ststeroids import Component | ||
|
|
||
|
|
||
| class StatusComponent(Component): | ||
|
|
||
| def __init__( | ||
| self, | ||
| message: str = None, | ||
| type: Literal["running", "info", "error", "success"] = "info", | ||
| ): | ||
| self.message = message | ||
| self.type = type | ||
|
|
||
| def display(self): | ||
| if self.message: | ||
| st.markdown(f"<div class='status-row'>{self._status_icon(self.type)}<div>{self.message}</div></div>", unsafe_allow_html=True) | ||
|
|
||
| def set_status(self, message: str, type: Literal["running", "info", "error", "success"] = "info"): | ||
| self.message = message | ||
| self.type = type | ||
|
|
||
| def clear(self): | ||
| self.message = None | ||
| self.type = None | ||
|
|
||
| def _status_icon(self, state: str): | ||
| icons = {"success": "✓", "error": "✕", "info": "i", "running": ""} | ||
|
|
||
| return f"<div class='status-icon {state}'>{icons.get(state, '')}</div>" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import streamlit as st | ||
| from ststeroids import Component | ||
|
|
||
|
|
||
| class ToastComponent(Component): | ||
| def __init__( | ||
| self, | ||
| ): | ||
| self.message = None | ||
| self.hide() | ||
|
|
||
| def display(self): | ||
| st.toast(self.message) | ||
| self.hide() | ||
|
|
||
| def set_message(self, message: str): | ||
| self.message = message | ||
| self.show() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| from .login import LoginFlow | ||
| from .login_succes import LoginSuccessFlow | ||
| from .refresh import RefreshFlow | ||
| from .app_setup import SetupFlow | ||
| from .logout import LogoutFlow | ||
| from .long_running import LongRunningFlow | ||
|
|
||
| __all__ = [LoginFlow, LoginSuccessFlow, RefreshFlow] | ||
| __all__ = [LoginFlow, RefreshFlow, SetupFlow, LogoutFlow, LongRunningFlow] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| from ststeroids import Flow, FlowContext | ||
|
|
||
|
|
||
| class SetupFlow(Flow): | ||
| def run(self, _ctx: FlowContext): | ||
| print("I'm a flow setting up the app per user") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,17 +1,62 @@ | ||
| from service import MockBackendService | ||
| from ststeroids import Flow, Store | ||
| from ststeroids import Flow, Store, FlowContext | ||
| from components import ( | ||
| LoginDialogComponent, | ||
| DataViewerComponent, | ||
| MetricComponent, | ||
| ToastComponent, | ||
| ) | ||
| from shared import ComponentIDs | ||
| import streamlit as st | ||
|
|
||
|
|
||
| class LoginFlow(Flow): | ||
| def __init__(self, session_store: Store, backend_service: MockBackendService): | ||
| super().__init__() | ||
| self.session_store = session_store | ||
| self.backend_service = backend_service | ||
|
|
||
| def run(self, username: str, password: str): | ||
| response = self.backend_service.authenticate(username, password) | ||
| @property | ||
| def cp_login_dialog(self): | ||
| return LoginDialogComponent.get(ComponentIDs.dialog_login) | ||
|
|
||
| @property | ||
| def cp_data_viewer(self): | ||
| return DataViewerComponent.get(ComponentIDs.data_viewer) | ||
|
|
||
| @property | ||
| def cp_total_movies(self): | ||
| return MetricComponent.get(ComponentIDs.total_movies) | ||
|
|
||
| @property | ||
| def cp_toast(self): | ||
| return ToastComponent.get(ComponentIDs.toast) | ||
|
|
||
| def run(self, _ctx: FlowContext): | ||
| response = self.backend_service.authenticate( | ||
| self.cp_login_dialog.username, self.cp_login_dialog.password | ||
| ) | ||
| if response.ok: | ||
| token_data = response.json() | ||
| self.session_store.set_property("access_token", token_data["access_token"]) | ||
| return True | ||
| return False | ||
| self._login_success(response) | ||
| else: | ||
| self._login_failed() | ||
|
|
||
| def _login_success(self, response): | ||
| token_data = response.json() | ||
| self.session_store.set_property("access_token", token_data["access_token"]) | ||
| self.cp_login_dialog.hide() | ||
| response = self.backend_service.get_movies() | ||
| # enable the line below for example of an error scenario | ||
| # response.ok = False | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this comment still relevant?
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes |
||
| if response.ok: | ||
| data = response.json() | ||
| self.session_store.set_property( | ||
| "data", data | ||
| ) # Store the data in the session_store for later use in more complex applications | ||
| self.cp_total_movies.set_value(len(data)) | ||
| self.cp_data_viewer.set_data(data) | ||
| else: | ||
| self.cp_toast.set_message("error") | ||
| st.switch_page("pages/dashboard.py") | ||
|
|
||
| def _login_failed(self): | ||
| self.cp_login_dialog.set_error("Login failed, check your username and password") | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.visible is currently commented, either implement or remove comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doen