Source code for sepal_ui.planetapi.planet_widgets

"""Widgets used to build the ``PLanetView`` interface."""

from datetime import datetime, timezone
from typing import List, Optional

import ipyvuetify as v
from typing_extensions import Self

import sepal_ui.sepalwidgets as sw
from sepal_ui.planetapi.planet_model import PlanetModel

# key_name: [label, [non_active_color, active_color]]
BTNS: dict = {
    "nicfi": ["NICFI", ["menu", "success"]],
    "others": ["Others", ["menu", "success"]],
}


[docs] class InfoView(sw.ExpansionPanels): model: Optional[PlanetModel] = None "Backend model to manipulate interface actions"
[docs] def __init__(self, model: PlanetModel, **kwargs) -> None: """Card to validate subscription. Custom optional card to be displayed within the planet view to validate the available subscriptions from the log-in credentials and show the info related with them, such as the quotas and remaining time of activation. Args: model: the planetModel associated with the display """ self.model = model self.v_model = 1 self.current = None self.readonly = True super().__init__(**kwargs) subs_btn = [ sw.Chip( children=[BTNS[label][0]], disabled=True, color=BTNS[label][1][0], x_small=True, class_="mr-2", attributes={"id": label}, link=True, label=True, ) for label in BTNS.keys() ] self.info_card = InfoCard().hide() self.children = [ v.ExpansionPanel( children=[ v.ExpansionPanelHeader( hide_actions=True, children=[v.Flex(children=subs_btn)] ), v.ExpansionPanelContent(v_model=1, children=[self.info_card]), ] ) ] [chip.on_event("click", self.open_info) for chip in subs_btn] self.model.observe(self._toggle_btns, "subscriptions")
[docs] def open_info(self, widget: v.VuetifyWidget, *args) -> None: """Shrink or srhunk the content of the expansion panel. It automatically sends a request to build the data. Args: widget: the widget to expand """ is_current = self.current == widget.attributes["id"] self.v_model = (not self.v_model) * 1 if is_current else 0 self.current = widget.attributes["id"] subs_group = self.model.subscriptions[widget.attributes["id"]] self.info_card.update(subs_group).show() return
def _turn_btn(self, btn_id: str, state: bool) -> None: """Update the status of the given button. Args: btn_id: the id of the btn object state: the state to apply to the btn """ btn = self.get_children(attr="id", value=btn_id)[0] btn.disabled = not state btn.color = BTNS[btn_id][1][state] return def _toggle_btns(self, change: dict) -> None: """Toggle the status of the btns.""" if not change["new"]: self.v_model = 1 [self._turn_btn(btn_id, False) for btn_id in BTNS.keys()] return for plan_type in BTNS.keys(): for subs in self.model.subscriptions[plan_type]: plan = subs.get("plan") # Turn on if at least one of them is True state = True if plan.get("state") else False self._turn_btn(plan_type, state) if state: break return
[docs] class InfoCard(sw.Layout):
[docs] def __init__(self) -> None: """Information card that will display the subscription data.""" self.style_ = "max-height: 240px; overflow: auto" self.class_ = "d-block" super().__init__() self.children = [v.CardText(children=[])]
def _make_content(self, sub: dict) -> List[v.VuetifyWidget]: """Creates individual subscription card from a subscription list. Args: sub: the subscriptions plan from a defined category (e.g. "nicfi") Returns: the children content of a category """ title = sub["plan"]["name"].replace("_", " ") state = sub["plan"]["state"] # Create an individual State icon for all the elements, it has to be # independent w_state = sw.StateIcon( states={ "non_active": ["Non active", "error"], "active": ["Active", "success"], } ) w_state.values = state w_title = sw.CardTitle(children=[title, v.Spacer(), w_state]) w_subtitle = v.CardSubtitle(children=[state.capitalize()]) from_ = datetime.fromisoformat(sub["active_from"]) to = sub["active_to"] is not None and datetime.fromisoformat(sub["active_to"]) now = datetime.now(timezone.utc) days_left = "∞" if not to else (to - now).days info_dict = { "from": ["From:", from_.strftime("%Y/%m/%d")], "to": ["Until:", "∞" if not to else to.strftime("%Y/%m/%d")], "days_left": ["Days left:", f"{days_left}"], } content = [ ( v.Flex( class_="d-block", children=[ v.Html(tag="strong", children=[values[0]]), v.Html(tag="div", children=[values[1]]), ], ), v.Divider(vertical=True, class_="mx-4"), ) for values in info_dict.values() ] # Flat the nested elements and remove the last divider content = [e for row in content for e in row][:-1] return [ w_title, w_subtitle, v.Layout(class_="d-flex flex-wrap", children=content), v.Divider(class_="my-2"), ]
[docs] def update(self, subs_group: List[dict]) -> Self: """Extract the info from the subscription and set it in the card. Args: subs_group: list of subscriptions belonging to the same category ('nicfi', 'others') """ content = [ v.Card(class_="pa-2", children=self._make_content(sub)) for sub in subs_group ] self.children = content return self