Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions consts.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
class Status:
GOOD = 'good'
DOWN = 'down'
UNKNOWN = 'unknown-device'
BROKEN = 'broken'
MISCONFIGURED = 'misconfigured'

STATUSES = \
['good'] * 20 + \
['down'] * 2 + \
['unknown-device'] * 5 + \
['broken', 'misconfigured']
[Status.GOOD] * 20 + \
[Status.DOWN] * 2 + \
[Status.UNKNOWN] * 5 + \
[Status.BROKEN, Status.MISCONFIGURED]

COLORS = {
'good': '#72fa93',
'down': '#e45f2b',
'unknown-device': '#f6c445',
'broken': '#e39af0',
'misconfigured': '#9ac1f0',
Status.GOOD: '#72fa93',
Status.DOWN: '#e45f2b',
Status.UNKNOWN: '#f6c445',
Status.BROKEN: '#e39af0',
Status.MISCONFIGURED: '#9ac1f0',
}
10 changes: 10 additions & 0 deletions css_utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from reactpy import html


def grid_position(x, y, width=1, height=1):
width_str = height_str = ''
if width != 1:
Expand All @@ -8,3 +11,10 @@ def grid_position(x, y, width=1, height=1):
'grid-row': f'{y} {height_str}',
'grid-column': f'{x} {width_str}',
}


def colorize(text: str, color: str):
return html.span(
{'style': {'color': color}},
text,
)
28 changes: 28 additions & 0 deletions static/dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,40 @@ div#app {
border-radius: 5px;
background-color: #101014;
box-shadow: 0px 0px 3px #0f0f11;
position: absolute;
left: -100%;
padding: 10px;
z-index: 2;
}

.vl-popup {
border-radius: 5px;
background-color: #101014;
box-shadow: 0px 0px 5px #c5ced1;

position: absolute;
left: -100%;
padding: 10px;
z-index: 1;
}

.vl-popup-button {
border-radius: 5px;
background-color: #1f242e;
outline-style: solid;
outline-width: 1px;
outline-color: #ffffffaa;
padding: 2px;
}

.vl-popup-button:hover {
background-color: #161920;
outline-style: solid;
outline-width: 1px;
outline-color: #ffffff33;
padding: 2px;
}

@keyframes appear-vertical {
from {
height: 0px;
Expand Down
1 change: 1 addition & 0 deletions visual_lab.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def on_click(title: str, cell_number: int):

def clear_focused_cell(_):
set_focused_cell(None)
set_hovered_cell(None)

return html.div(
{
Expand Down
44 changes: 32 additions & 12 deletions widgets/cell.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

from reactpy import html, component, use_effect, use_ref, Ref, event

from css_utils import grid_position
from .tooltip import Tooltip
from css_utils import grid_position, colorize
from . import tooltip
from .popup import generate_popup
from consts import COLORS

STATUS_BAR_DELAY_OFFSET = 0.17 # trust me on this one
Expand All @@ -26,6 +27,10 @@ class CellDetails:
on_click: Callable[[], None]
on_hover: Callable[[bool], None]

@property
def cell_id(self) -> str:
return f'{self.cabinet}-{self.number}'


@component
def StatusBar(delay: float, should_animate: bool):
Expand Down Expand Up @@ -70,22 +75,37 @@ async def effect():
{'class_name': 'cell-text'},
details.number
),
StatusBar(STATUS_BAR_DELAY_OFFSET + details.delay, should_animate.current)
StatusBar(STATUS_BAR_DELAY_OFFSET +
details.delay, should_animate.current)
)
popup = None
if details.show_popup:
popup = CellPopup(details)
elif details.show_tooltip:
popup = CellTooltip(details)
if popup is not None:
return html.div(cell, popup)

if details.show_tooltip or details.show_popup:
return CellTooltip(details, hoverables=[cell])
return cell


@component
def CellTooltip(details: CellDetails, hoverables):
tooltip = html.div(
def CellPopup(details: CellDetails):
contents = html.div(
{
# Clicking the popup should not make it disappear
'onclick': event(lambda _: None, stop_propagation=True),
},
generate_popup(details),
)
return tooltip.Tooltip(contents, class_name=tooltip.POPUP)


@component
def CellTooltip(details: CellDetails):
contents = html.div(
{'style': {'width': '130px'}},
f"Device at {details.cabinet}-{details.number} has status ",
html.span(
{'style': {'color': COLORS[details.status]}},
details.status,
)
colorize(details.status, COLORS[details.status]),
)
return Tooltip(tooltip, hoverables)
return tooltip.Tooltip(contents)
79 changes: 79 additions & 0 deletions widgets/popup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
from reactpy import component, html
from reactpy.types import Component
from typing import TypeVar, Callable, cast
from . import cell
from .tooltip import PopupButton
from consts import Status, COLORS
from css_utils import colorize

POPUP_WIDTH = '250px'

PopupMaker = TypeVar(
'PopupMaker',
bound=Callable[['cell.CellDetails'], Component]
)
_POPUPS: dict[str, PopupMaker] = {}


@component
def default_handler(details: 'cell.CellDetails'):
return html.div(
{
'style': {
'width': POPUP_WIDTH,
}
},
colorize('Error', '#f12323'),
f': popup for status {details.status} has not been implemented yet!'
)


def get_handler(status: str) -> PopupMaker:
return _POPUPS.get(status, default_handler)


def generate_popup(details: 'cell.CellDetails'):
handler = get_handler(details.status)
return handler(details)


def popup_maker(status: str) -> Callable[[PopupMaker], PopupMaker]:
def wrapper(func: PopupMaker) -> PopupMaker:
_POPUPS[status] = func
return func
return wrapper


@popup_maker(Status.DOWN)
@component
def _popup_down(details: 'cell.CellDetails'):
return html.div(
{
'style': {
'width': POPUP_WIDTH,
},
},
f'The interface in cell {details.cell_id} is ',
colorize('DOWN', COLORS[Status.DOWN]),
'. Please make sure the cable is connected!',
)

@popup_maker(Status.MISCONFIGURED)
@component
def _popup_misconfigured(details: 'cell.CellDetails'):
# TODO: Improve the styling on the button in this component
def quick_fix(_):
# TODO: Reconfigure the DB
...

return html.div(
{
'style': {
'width': POPUP_WIDTH,
},
},
# TODO: Fix this message
f'Device #100 is in this cell, but is configured to cell A-1.\n',
f'Click the button below to move it to {details.cell_id}\n',
PopupButton('Quick Fix', quick_fix),
)
36 changes: 25 additions & 11 deletions widgets/tooltip.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,37 @@
from typing import Callable
from reactpy import html, component
from reactpy.types import Component

TOOLTIP = 'vl-tooltip'
POPUP = 'vl-popup'

@component
def Tooltip(tooltip_content: Component, hoverables):
if not hoverables:
return html.span()

tooltip = html.div(
{'class_name': 'vl-tooltip'},
tooltip_content
)

def Tooltip(tooltip_content: Component, class_name=TOOLTIP):
return html.div(
{
'style': {
'position': 'relative',
}
},
*hoverables,
tooltip
html.div(
{
'class_name': class_name
},
tooltip_content
)
)


@component
def PopupButton(text: str, onclick: Callable, override_style=None):
style = {}
if override_style:
style.update(override_style)
return html.span(
{
'class_name': 'vl-popup-button',
'onclick': onclick,
'style': style,
},
f' {text} '
)