UI connection warning (#1111)
This commit is contained in:
parent
895719cf68
commit
4c84a349e1
@ -11,6 +11,7 @@
|
|||||||
export default function Component() {
|
export default function Component() {
|
||||||
const [{{state_name}}, {{state_name|react_setter}}] = useState({{initial_state|json_dumps}})
|
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 [{{const.result}}, {{const.result|react_setter}}] = useState({{const.initial_result|json_dumps}})
|
||||||
|
const [notConnected, setNotConnected] = useState(false)
|
||||||
const {{const.router}} = useRouter()
|
const {{const.router}} = useRouter()
|
||||||
const {{const.socket}} = useRef(null)
|
const {{const.socket}} = useRef(null)
|
||||||
const { isReady } = {{const.router}}
|
const { isReady } = {{const.router}}
|
||||||
@ -35,7 +36,7 @@ export default function Component() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!{{const.socket}}.current) {
|
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 () => {
|
const update = async () => {
|
||||||
if ({{const.result}}.{{const.state}} != null){
|
if ({{const.result}}.{{const.state}} != null){
|
||||||
@ -70,7 +71,12 @@ export default function Component() {
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<Fragment>
|
||||||
|
{%- if err_comp -%}
|
||||||
|
{{ utils.render(err_comp, indent_width=1) }}
|
||||||
|
{%- endif -%}
|
||||||
{{utils.render(render, indent_width=0)}}
|
{{utils.render(render, indent_width=0)}}
|
||||||
|
</Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -193,7 +193,8 @@ export const connect = async (
|
|||||||
result,
|
result,
|
||||||
setResult,
|
setResult,
|
||||||
router,
|
router,
|
||||||
transports
|
transports,
|
||||||
|
setNotConnected
|
||||||
) => {
|
) => {
|
||||||
// Get backend URL object from the endpoint
|
// Get backend URL object from the endpoint
|
||||||
const endpoint_url = new URL(EVENTURL);
|
const endpoint_url = new URL(EVENTURL);
|
||||||
@ -207,6 +208,11 @@ export const connect = async (
|
|||||||
// Once the socket is open, hydrate the page.
|
// Once the socket is open, hydrate the page.
|
||||||
socket.current.on("connect", () => {
|
socket.current.on("connect", () => {
|
||||||
updateState(state, setState, result, setResult, router, socket.current);
|
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.
|
// 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 compiler
|
||||||
from pynecone.compiler import utils as compiler_utils
|
from pynecone.compiler import utils as compiler_utils
|
||||||
from pynecone.components.component import Component, ComponentStyle
|
from pynecone.components.component import Component, ComponentStyle
|
||||||
|
from pynecone.components.overlay.banner import ConnectionBanner
|
||||||
from pynecone.config import get_config
|
from pynecone.config import get_config
|
||||||
from pynecone.event import Event, EventHandler
|
from pynecone.event import Event, EventHandler
|
||||||
from pynecone.middleware import HydrateMiddleware, Middleware
|
from pynecone.middleware import HydrateMiddleware, Middleware
|
||||||
@ -76,6 +77,9 @@ class App(Base):
|
|||||||
# List of event handlers to trigger when a page loads.
|
# List of event handlers to trigger when a page loads.
|
||||||
load_events: Dict[str, List[EventHandler]] = {}
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
"""Initialize the app.
|
"""Initialize the app.
|
||||||
|
|
||||||
@ -411,7 +415,12 @@ class App(Base):
|
|||||||
custom_components = set()
|
custom_components = set()
|
||||||
for route, component in self.pages.items():
|
for route, component in self.pages.items():
|
||||||
component.add_style(self.style)
|
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.
|
# Add the custom components from the page to the set.
|
||||||
custom_components |= component.get_custom_components()
|
custom_components |= component.get_custom_components()
|
||||||
|
@ -15,6 +15,7 @@ from pynecone.vars import ImportVar
|
|||||||
# Imports to be included in every Pynecone app.
|
# Imports to be included in every Pynecone app.
|
||||||
DEFAULT_IMPORTS: imports.ImportDict = {
|
DEFAULT_IMPORTS: imports.ImportDict = {
|
||||||
"react": {
|
"react": {
|
||||||
|
ImportVar(tag="Fragment"),
|
||||||
ImportVar(tag="useEffect"),
|
ImportVar(tag="useEffect"),
|
||||||
ImportVar(tag="useRef"),
|
ImportVar(tag="useRef"),
|
||||||
ImportVar(tag="useState"),
|
ImportVar(tag="useState"),
|
||||||
@ -31,7 +32,11 @@ DEFAULT_IMPORTS: imports.ImportDict = {
|
|||||||
ImportVar(tag="getRefValue"),
|
ImportVar(tag="getRefValue"),
|
||||||
},
|
},
|
||||||
"": {ImportVar(tag="focus-visible/dist/focus-visible")},
|
"": {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)
|
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.
|
"""Compile the component given the app state.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
component: The component to compile.
|
component: The component to compile.
|
||||||
state: The app state.
|
state: The app state.
|
||||||
|
connect_error_component: The component to render on sever connection error.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The compiled component.
|
The compiled component.
|
||||||
@ -85,6 +93,7 @@ def _compile_page(component: Component, state: Type[State]) -> str:
|
|||||||
hooks=component.get_hooks(),
|
hooks=component.get_hooks(),
|
||||||
render=component.render(),
|
render=component.render(),
|
||||||
transports=constants.Transports.POLLING_WEBSOCKET.get_transports(),
|
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
|
@write_output
|
||||||
def compile_page(
|
def compile_page(
|
||||||
path: str, component: Component, state: Type[State]
|
path: str,
|
||||||
|
component: Component,
|
||||||
|
state: Type[State],
|
||||||
|
connect_error_component: Component,
|
||||||
) -> Tuple[str, str]:
|
) -> Tuple[str, str]:
|
||||||
"""Compile a single page.
|
"""Compile a single page.
|
||||||
|
|
||||||
@ -196,6 +208,7 @@ def compile_page(
|
|||||||
path: The path to compile the page to.
|
path: The path to compile the page to.
|
||||||
component: The component to compile.
|
component: The component to compile.
|
||||||
state: The app state.
|
state: The app state.
|
||||||
|
connect_error_component: The component to render on sever connection error.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The path and code of the compiled page.
|
The path and code of the compiled page.
|
||||||
@ -204,7 +217,7 @@ def compile_page(
|
|||||||
output_path = utils.get_page_path(path)
|
output_path = utils.get_page_path(path)
|
||||||
|
|
||||||
# Add the style to the component.
|
# Add the style to the component.
|
||||||
code = _compile_page(component, state)
|
code = _compile_page(component, state, connect_error_component)
|
||||||
return output_path, code
|
return output_path, code
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ component = Component.create
|
|||||||
badge = Badge.create
|
badge = Badge.create
|
||||||
code = Code.create
|
code = Code.create
|
||||||
code_block = CodeBlock.create
|
code_block = CodeBlock.create
|
||||||
|
connection_banner = ConnectionBanner.create
|
||||||
data_table = DataTable.create
|
data_table = DataTable.create
|
||||||
divider = Divider.create
|
divider = Divider.create
|
||||||
list = List.create
|
list = List.create
|
||||||
|
@ -8,6 +8,7 @@ from .alertdialog import (
|
|||||||
AlertDialogHeader,
|
AlertDialogHeader,
|
||||||
AlertDialogOverlay,
|
AlertDialogOverlay,
|
||||||
)
|
)
|
||||||
|
from .banner import ConnectionBanner
|
||||||
from .drawer import (
|
from .drawer import (
|
||||||
Drawer,
|
Drawer,
|
||||||
DrawerBody,
|
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