UI connection warning (#1111)
This commit is contained in:
parent
895719cf68
commit
4c84a349e1
@ -11,6 +11,7 @@
|
||||
export default function Component() {
|
||||
const [{{state_name}}, {{state_name|react_setter}}] = useState({{initial_state|json_dumps}})
|
||||
const [{{const.result}}, {{const.result|react_setter}}] = useState({{const.initial_result|json_dumps}})
|
||||
const [notConnected, setNotConnected] = useState(false)
|
||||
const {{const.router}} = useRouter()
|
||||
const {{const.socket}} = useRef(null)
|
||||
const { isReady } = {{const.router}}
|
||||
@ -35,7 +36,7 @@ export default function Component() {
|
||||
return;
|
||||
}
|
||||
if (!{{const.socket}}.current) {
|
||||
connect({{const.socket}}, {{state_name}}, {{state_name|react_setter}}, {{const.result}}, {{const.result|react_setter}}, {{const.router}}, {{transports}})
|
||||
connect({{const.socket}}, {{state_name}}, {{state_name|react_setter}}, {{const.result}}, {{const.result|react_setter}}, {{const.router}}, {{transports}}, setNotConnected)
|
||||
}
|
||||
const update = async () => {
|
||||
if ({{const.result}}.{{const.state}} != null){
|
||||
@ -70,7 +71,12 @@ export default function Component() {
|
||||
{% endfor %}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{%- if err_comp -%}
|
||||
{{ utils.render(err_comp, indent_width=1) }}
|
||||
{%- endif -%}
|
||||
{{utils.render(render, indent_width=0)}}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
{% endblock %}
|
||||
|
@ -193,7 +193,8 @@ export const connect = async (
|
||||
result,
|
||||
setResult,
|
||||
router,
|
||||
transports
|
||||
transports,
|
||||
setNotConnected
|
||||
) => {
|
||||
// Get backend URL object from the endpoint
|
||||
const endpoint_url = new URL(EVENTURL);
|
||||
@ -207,6 +208,11 @@ export const connect = async (
|
||||
// Once the socket is open, hydrate the page.
|
||||
socket.current.on("connect", () => {
|
||||
updateState(state, setState, result, setResult, router, socket.current);
|
||||
setNotConnected(false)
|
||||
});
|
||||
|
||||
socket.current.on('connect_error', (error) => {
|
||||
setNotConnected(true)
|
||||
});
|
||||
|
||||
// On each received message, apply the delta and set the result.
|
||||
|
@ -24,6 +24,7 @@ from pynecone.base import Base
|
||||
from pynecone.compiler import compiler
|
||||
from pynecone.compiler import utils as compiler_utils
|
||||
from pynecone.components.component import Component, ComponentStyle
|
||||
from pynecone.components.overlay.banner import ConnectionBanner
|
||||
from pynecone.config import get_config
|
||||
from pynecone.event import Event, EventHandler
|
||||
from pynecone.middleware import HydrateMiddleware, Middleware
|
||||
@ -76,6 +77,9 @@ class App(Base):
|
||||
# List of event handlers to trigger when a page loads.
|
||||
load_events: Dict[str, List[EventHandler]] = {}
|
||||
|
||||
# The component to render if there is a connection error to the server.
|
||||
connect_error_component: Optional[Component] = ConnectionBanner.create()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Initialize the app.
|
||||
|
||||
@ -411,7 +415,12 @@ class App(Base):
|
||||
custom_components = set()
|
||||
for route, component in self.pages.items():
|
||||
component.add_style(self.style)
|
||||
compiler.compile_page(route, component, self.state)
|
||||
compiler.compile_page(
|
||||
route,
|
||||
component,
|
||||
self.state,
|
||||
self.connect_error_component,
|
||||
)
|
||||
|
||||
# Add the custom components from the page to the set.
|
||||
custom_components |= component.get_custom_components()
|
||||
|
@ -15,6 +15,7 @@ from pynecone.vars import ImportVar
|
||||
# Imports to be included in every Pynecone app.
|
||||
DEFAULT_IMPORTS: imports.ImportDict = {
|
||||
"react": {
|
||||
ImportVar(tag="Fragment"),
|
||||
ImportVar(tag="useEffect"),
|
||||
ImportVar(tag="useRef"),
|
||||
ImportVar(tag="useState"),
|
||||
@ -31,7 +32,11 @@ DEFAULT_IMPORTS: imports.ImportDict = {
|
||||
ImportVar(tag="getRefValue"),
|
||||
},
|
||||
"": {ImportVar(tag="focus-visible/dist/focus-visible")},
|
||||
"@chakra-ui/react": {ImportVar(tag=constants.USE_COLOR_MODE)},
|
||||
"@chakra-ui/react": {
|
||||
ImportVar(tag=constants.USE_COLOR_MODE),
|
||||
ImportVar(tag="Box"),
|
||||
ImportVar(tag="Text"),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -62,12 +67,15 @@ def _compile_theme(theme: dict) -> str:
|
||||
return templates.THEME.render(theme=theme)
|
||||
|
||||
|
||||
def _compile_page(component: Component, state: Type[State]) -> str:
|
||||
def _compile_page(
|
||||
component: Component, state: Type[State], connect_error_component
|
||||
) -> str:
|
||||
"""Compile the component given the app state.
|
||||
|
||||
Args:
|
||||
component: The component to compile.
|
||||
state: The app state.
|
||||
connect_error_component: The component to render on sever connection error.
|
||||
|
||||
Returns:
|
||||
The compiled component.
|
||||
@ -85,6 +93,7 @@ def _compile_page(component: Component, state: Type[State]) -> str:
|
||||
hooks=component.get_hooks(),
|
||||
render=component.render(),
|
||||
transports=constants.Transports.POLLING_WEBSOCKET.get_transports(),
|
||||
err_comp=connect_error_component.render() if connect_error_component else None,
|
||||
)
|
||||
|
||||
|
||||
@ -188,7 +197,10 @@ def compile_theme(style: Style) -> Tuple[str, str]:
|
||||
|
||||
@write_output
|
||||
def compile_page(
|
||||
path: str, component: Component, state: Type[State]
|
||||
path: str,
|
||||
component: Component,
|
||||
state: Type[State],
|
||||
connect_error_component: Component,
|
||||
) -> Tuple[str, str]:
|
||||
"""Compile a single page.
|
||||
|
||||
@ -196,6 +208,7 @@ def compile_page(
|
||||
path: The path to compile the page to.
|
||||
component: The component to compile.
|
||||
state: The app state.
|
||||
connect_error_component: The component to render on sever connection error.
|
||||
|
||||
Returns:
|
||||
The path and code of the compiled page.
|
||||
@ -204,7 +217,7 @@ def compile_page(
|
||||
output_path = utils.get_page_path(path)
|
||||
|
||||
# Add the style to the component.
|
||||
code = _compile_page(component, state)
|
||||
code = _compile_page(component, state, connect_error_component)
|
||||
return output_path, code
|
||||
|
||||
|
||||
|
@ -29,6 +29,7 @@ component = Component.create
|
||||
badge = Badge.create
|
||||
code = Code.create
|
||||
code_block = CodeBlock.create
|
||||
connection_banner = ConnectionBanner.create
|
||||
data_table = DataTable.create
|
||||
divider = Divider.create
|
||||
list = List.create
|
||||
|
@ -8,6 +8,7 @@ from .alertdialog import (
|
||||
AlertDialogHeader,
|
||||
AlertDialogOverlay,
|
||||
)
|
||||
from .banner import ConnectionBanner
|
||||
from .drawer import (
|
||||
Drawer,
|
||||
DrawerBody,
|
||||
|
33
pynecone/components/overlay/banner.py
Normal file
33
pynecone/components/overlay/banner.py
Normal file
@ -0,0 +1,33 @@
|
||||
"""Banner components."""
|
||||
from typing import Optional
|
||||
|
||||
from pynecone.components.component import Component
|
||||
from pynecone.components.layout import Box, Cond, Fragment
|
||||
from pynecone.components.typography import Text
|
||||
from pynecone.vars import Var
|
||||
|
||||
|
||||
class ConnectionBanner(Cond):
|
||||
"""A connection banner component."""
|
||||
|
||||
@classmethod
|
||||
def create(cls, comp: Optional[Component] = None) -> Component:
|
||||
"""Create a connection banner component.
|
||||
|
||||
Args:
|
||||
comp: The component to render when there's a server connection error.
|
||||
|
||||
Returns:
|
||||
The connection banner component.
|
||||
"""
|
||||
if not comp:
|
||||
comp = Box.create(
|
||||
Text.create(
|
||||
"cannot connect to server. Check if server is reachable",
|
||||
bg="red",
|
||||
color="white",
|
||||
),
|
||||
textAlign="center",
|
||||
)
|
||||
|
||||
return super().create(Var.create("notConnected"), comp, Fragment.create()) # type: ignore
|
Loading…
Reference in New Issue
Block a user