Skip to content

Commit

Permalink
remove double viewport in prepartion for idom router
Browse files Browse the repository at this point in the history
  • Loading branch information
Archmonger committed Sep 23, 2022
1 parent af88f7d commit 4155439
Show file tree
Hide file tree
Showing 9 changed files with 37 additions and 162 deletions.
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[python]": {
"editor.defaultFormatter": "ms-python.python"
"editor.defaultFormatter": "ms-python.python",
"editor.codeActionsOnSave": {
"source.organizeImports": true
}
},
"files.insertFinalNewline": true
}
3 changes: 0 additions & 3 deletions conreq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,15 @@
SidebarTab,
TabbedViewportState,
Viewport,
ViewportSelector,
)


__all__ = [
"app",
"config",
"utils",
"HomepageState",
"TabbedViewportState",
"AuthLevel",
"ViewportSelector",
"Seconds",
"ModalState",
"Icon",
Expand Down
78 changes: 6 additions & 72 deletions conreq/_core/home/components/__init__.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
import asyncio
from copy import copy
from datetime import datetime, timedelta
from datetime import datetime

import idom
from django.urls import reverse_lazy
from django_idom.decorators import auth_required
from idom.html import _, script

from conreq import HomepageState, ViewportSelector
from conreq import HomepageState
from conreq._core.home.components.backdrop import backdrop
from conreq._core.home.components.modal import modal
from conreq._core.home.components.navbar import navbar
from conreq._core.home.components.sidebar import sidebar
from conreq._core.home.components.viewport import viewport, viewport_loading_animation
from conreq.types import Seconds

# pylint: disable=protected-access


# pylint: disable=protected-access
# TODO: Style viewports using Shadow DOM https://web.dev/shadowdom-v1/
# TODO: Add react components: SimpleBar, Pretty-Checkbox, IziToast, Bootstrap
@idom.component
Expand All @@ -37,81 +34,18 @@ def set_viewport():
if not state._viewport_intent:
return

# Set timestamp to the time of intent change
state._viewport_intent.timestamp = datetime.now()

# Switch to a cached viewport
if state._viewport_primary is state._viewport_intent:
state._viewport_selector = ViewportSelector.primary
elif state._viewport_secondary is state._viewport_intent:
state._viewport_selector = ViewportSelector.secondary

# Replace the selected viewport
elif state._viewport_intent.selector == ViewportSelector.primary:
state._viewport_selector = state._viewport_intent.selector
state._viewport_primary = state._viewport_intent
elif state._viewport_intent.selector == ViewportSelector.secondary:
state._viewport_selector = state._viewport_intent.selector
state._viewport_secondary = state._viewport_intent

# Automatically determine what viewport to use
elif state._viewport_intent.selector == ViewportSelector.auto:
# Use an unused viewport if it exists
if not state._viewport_primary:
state._viewport_selector = ViewportSelector.primary
state._viewport_primary = state._viewport_intent
elif not state._viewport_secondary:
state._viewport_selector = ViewportSelector.secondary
state._viewport_secondary = state._viewport_intent
# Replace the oldest viewport
elif (
state._viewport_primary.timestamp < state._viewport_secondary.timestamp
):
state._viewport_selector = ViewportSelector.primary
state._viewport_primary = state._viewport_intent
else:
state._viewport_selector = ViewportSelector.secondary
state._viewport_secondary = state._viewport_intent

# Reset the intent
state._viewport = state._viewport_intent
state._viewport.timestamp = datetime.now()
state._viewport_intent = None

set_state(copy(state))

@idom.hooks.use_effect
async def viewport_expiration():
"""If there are two viewports rendered, have the background viewport expire
after 3 minutes of inactivity."""
while True:
await asyncio.sleep(Seconds.minute)
if (
state._viewport_primary
and state._viewport_secondary
and datetime.now() - state._viewport_primary.timestamp
> timedelta(minutes=2.5)
and datetime.now() - state._viewport_secondary.timestamp
> timedelta(minutes=2.5)
):
if (
state._viewport_selector != ViewportSelector.primary
and state._viewport_primary.expires
):
state._viewport_primary = None
set_state(copy(state))

if (
state._viewport_selector != ViewportSelector.secondary
and state._viewport_secondary.expires
):
state._viewport_secondary = None
set_state(copy(state))

return _(
navbar(state, set_state),
modal(state, set_state),
sidebar(state, set_state),
viewport_loading_animation(state, set_state),
viewport(state, set_state, ViewportSelector.primary),
viewport(state, set_state, ViewportSelector.secondary),
viewport(state, set_state),
backdrop(state, set_state),
)
11 changes: 2 additions & 9 deletions conreq/_core/home/components/navbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from idom import component, hooks
from idom.html import button, div, script, span

from conreq import HomepageState, ViewportSelector
from conreq import HomepageState
from conreq._core.server_settings.models import GeneralSettings

# pylint: disable=protected-access
Expand Down Expand Up @@ -46,14 +46,7 @@ def _update_page_title():


def _get_page_title(state: HomepageState):
if state._viewport_primary and state._viewport_selector == ViewportSelector.primary:
return state._viewport_primary.page_title or _default_page_title()
if (
state._viewport_secondary
and state._viewport_selector == ViewportSelector.secondary
):
return state._viewport_secondary.page_title or _default_page_title()
return _default_page_title()
return getattr(state._viewport, "page_title", None) or _default_page_title()


def _default_page_title():
Expand Down
26 changes: 7 additions & 19 deletions conreq/_core/home/components/sidebar.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,7 @@
from django_idom.hooks import use_websocket
from idom.html import _, div, i, nav

from conreq import (
HomepageState,
NavGroup,
SidebarTab,
Viewport,
ViewportSelector,
config,
)
from conreq import HomepageState, NavGroup, SidebarTab, Viewport, config
from conreq._core.home.components.welcome import welcome
from conreq.types import SidebarTabEvent
from conreq.utils.environment import get_debug_mode, get_safe_mode
Expand Down Expand Up @@ -74,10 +67,10 @@ def sidebar(state: HomepageState, set_state):

sidebar_tabs = config.homepage.sidebar_tabs

@idom.hooks.use_effect
@idom.hooks.use_effect(dependencies=[])
async def set_initial_tab():
# The initial tab has already been set
if state._viewport_selector != ViewportSelector._initial:
if state._viewport or state._viewport_intent:
return None

# Use the configured default tab, if it exists
Expand Down Expand Up @@ -167,11 +160,8 @@ async def username_on_click(_):


def _sidebar_tab_class(state: HomepageState, tab: SidebarTab):
if (
state._viewport_selector is not ViewportSelector._initial
and tab.viewport
and tab.viewport.component
is state.__getattribute__(f"_viewport_{state._viewport_selector}").component
if state._viewport and getattr(tab.viewport, "component", None) is getattr(
state._viewport, "component", None
):
return NAV_TAB_ACTIVE
return NAV_TAB
Expand All @@ -197,10 +187,8 @@ async def on_click(event):
return

# Don't reload if clicking the current tab
if (
state._viewport_selector is not ViewportSelector._initial
and tab.viewport
is state.__getattribute__(f"_viewport_{state._viewport_selector}")
if getattr(tab.viewport, "component", None) is getattr(
state._viewport, "component", None
):
return

Expand Down
41 changes: 14 additions & 27 deletions conreq/_core/home/components/viewport.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import idom
from idom.html import div

from conreq import HomepageState, ViewportSelector, config
from conreq._core.home.components.protocol import ConditionalRender
from conreq import HomepageState, config
from conreq.types import Viewport

# pylint: disable=protected-access
Expand All @@ -15,23 +14,23 @@
def viewport_loading_animation(state: HomepageState, set_state):
# pylint: disable=unused-argument
return div(
VIEWPORT_CONTAINER_LOADING
| (
{"className": VIEWPORT_CONTAINER_LOADING["className"] + " hidden"}
if state._viewport_selector
in {ViewportSelector.primary, ViewportSelector.secondary}
and not state._viewport_intent
else {}
(
VIEWPORT_CONTAINER_LOADING
| (
{}
if state._viewport_intent
else {"className": VIEWPORT_CONTAINER_LOADING["className"] + " hidden"}
)
),
config.components.loading_animation_large,
)


@idom.component
def viewport(state: HomepageState, set_state, viewport_name: str):
def viewport(state: HomepageState, set_state):
# sourcery skip: assign-if-exp
this_viewport: Viewport = getattr(state, f"_viewport_{viewport_name}")
base_attrs = {"className": f"viewport-container {viewport_name}"}
this_viewport = state._viewport
base_attrs = {"className": "viewport-container"}

if not this_viewport:
return div(base_attrs | HIDDEN)
Expand All @@ -40,29 +39,17 @@ def viewport(state: HomepageState, set_state, viewport_name: str):
viewport_attrs(
base_attrs,
state,
viewport_name,
this_viewport,
),
ConditionalRender(
this_viewport.component(state, set_state),
state._viewport_selector == viewport_name,
)
if getattr(state, f"_viewport_{viewport_name}")
else "",
this_viewport.component(state, set_state) if state._viewport else "",
key=f"{this_viewport.component.__module__}.{this_viewport.component.__name__}",
)


def viewport_attrs(
base_attrs, state: HomepageState, viewport_name, _viewport: Viewport
):
def viewport_attrs(base_attrs, state: HomepageState, _viewport: Viewport):
# Ensure we are constructing a new class with the pipe operator
new_attrs = base_attrs
if state._viewport_selector != viewport_name:
new_attrs = new_attrs | HIDDEN
else:
new_attrs = new_attrs | {}

new_attrs = new_attrs | HIDDEN if state._viewport_intent else new_attrs | {}
if not _viewport.padding:
new_attrs["className"] += " no-padding"
if _viewport.html_class:
Expand Down
11 changes: 1 addition & 10 deletions conreq/app/register/homepage.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
from typing import Callable

from conreq import config
from conreq.types import (
AuthLevel,
Icon,
NavGroup,
SidebarTab,
Viewport,
ViewportSelector,
)
from conreq.types import AuthLevel, Icon, NavGroup, SidebarTab, Viewport


# TODO: Implement url_pattern for IDOM components. Needs react-router to be integrated into IDOM core.
Expand All @@ -19,7 +12,6 @@ def sidebar_tab(
on_click: Callable | None = None,
html_class: str = "",
padding: bool = True,
selector: str = ViewportSelector.primary,
auth: str = AuthLevel.user,
) -> Callable:
"""Decorates an IDOM component. Tab is added to the sidebar and is rendered when clicked.
Expand All @@ -41,7 +33,6 @@ def decorator(component):
name=name,
viewport=Viewport(
component=component,
selector=selector,
html_class=html_class,
padding=padding,
),
Expand Down
4 changes: 1 addition & 3 deletions conreq/config/utils.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
from typing import Callable

from conreq.types import AuthLevel, SidebarTab, Viewport, ViewportSelector
from conreq.types import AuthLevel, SidebarTab, Viewport


def tab_constructor(
name: str,
component: Callable,
on_click: Callable | None = None,
padding: bool = True,
selector: str = ViewportSelector.auto,
auth: str = AuthLevel.user,
html_class: str = "",
) -> SidebarTab:
return SidebarTab(
name=name,
viewport=Viewport(
component=component,
selector=selector,
html_class=html_class,
padding=padding,
),
Expand Down
Loading

0 comments on commit 4155439

Please sign in to comment.