Forráskód Böngészése

#119 aligning with taipy-gui (#131)

* #119 aligning with taipy-gui

* format

* mypy

* sort

* black

---------

Co-authored-by: Fred Lefévère-Laoide <Fred.Lefevere-Laoide@Taipy.io>
Fred Lefévère-Laoide 2 éve
szülő
commit
7ec184e135
2 módosított fájl, 74 hozzáadás és 75 törlés
  1. 14 9
      gui/src/ScenarioSelector.tsx
  2. 60 66
      src/taipy/gui_core/GuiCoreLib.py

+ 14 - 9
gui/src/ScenarioSelector.tsx

@@ -44,6 +44,7 @@ import {
   getUpdateVar,
   getUpdateVar,
   createSendActionNameAction,
   createSendActionNameAction,
   useDispatchRequestUpdateOnFirstRender,
   useDispatchRequestUpdateOnFirstRender,
+  createSendUpdateAction,
 } from "taipy-gui";
 } from "taipy-gui";
 
 
 enum NodeType {
 enum NodeType {
@@ -51,9 +52,9 @@ enum NodeType {
   SCENARIO = 1,
   SCENARIO = 1,
 }
 }
 
 
-type Scenario = [string, string, number, boolean];
+type Scenario = [string, string, undefined, number, boolean];
 type Scenarios = Array<Scenario>;
 type Scenarios = Array<Scenario>;
-type Cycles = Array<[string, string, number, boolean, Scenarios]>;
+type Cycles = Array<[string, string, Scenarios, number, boolean]>;
 
 
 interface ScenarioSelectorProps {
 interface ScenarioSelectorProps {
   id?: string;
   id?: string;
@@ -63,14 +64,17 @@ interface ScenarioSelectorProps {
   displayCycles?: boolean;
   displayCycles?: boolean;
   defaultShowPrimaryFlag: boolean;
   defaultShowPrimaryFlag: boolean;
   showPrimaryFlag?: boolean;
   showPrimaryFlag?: boolean;
+  value?: Record<string, any>;
+  updateVarName?: string;
   scenarios?: Cycles | Scenarios;
   scenarios?: Cycles | Scenarios;
   onScenarioCreate: string;
   onScenarioCreate: string;
-  onCtxSelection: string;
-  onAction?: string;
+  onChange?: string;
   coreChanged?: Record<string, unknown>;
   coreChanged?: Record<string, unknown>;
   updateVars: string;
   updateVars: string;
   configs?: Array<[string, string]>;
   configs?: Array<[string, string]>;
   error?: string;
   error?: string;
+  propagate?: boolean;
+  scenario?: Record<string, string>
 }
 }
 
 
 interface ScenarioNodesProps {
 interface ScenarioNodesProps {
@@ -100,7 +104,7 @@ const ScenarioNodes = ({ scenarios = [], showPrimary = true }: ScenarioNodesProp
   const sc = Array.isArray(scenarios) && scenarios.length && Array.isArray(scenarios[0]) ? (scenarios as Scenarios) : scenarios ? [scenarios as Scenario] : [];
   const sc = Array.isArray(scenarios) && scenarios.length && Array.isArray(scenarios[0]) ? (scenarios as Scenarios) : scenarios ? [scenarios as Scenario] : [];
   return (
   return (
     <>
     <>
-      {sc.map(([id, label, _, primary]) => (
+      {sc.map(([id, label, _, _nodeType, primary]) => (
         <TreeItem
         <TreeItem
           key={id}
           key={id}
           nodeId={id}
           nodeId={id}
@@ -156,7 +160,7 @@ const DialogContentSx = {
 };
 };
 
 
 const ScenarioSelector = (props: ScenarioSelectorProps) => {
 const ScenarioSelector = (props: ScenarioSelectorProps) => {
-  const { id = "", scenarios = [] } = props;
+  const { id = "", scenarios = [], propagate = true } = props;
   const [open, setOpen] = useState(false);
   const [open, setOpen] = useState(false);
   const [properties, setProperties] = useState<Property[]>([]);
   const [properties, setProperties] = useState<Property[]>([]);
   const [newProp, setNewProp] = useState<Property>({ id: "", key: "", value: "" });
   const [newProp, setNewProp] = useState<Property>({ id: "", key: "", value: "" });
@@ -228,11 +232,12 @@ const ScenarioSelector = (props: ScenarioSelectorProps) => {
 
 
   const onSelect = useCallback(
   const onSelect = useCallback(
     (e: React.SyntheticEvent, nodeIds: Array<string> | string) => {
     (e: React.SyntheticEvent, nodeIds: Array<string> | string) => {
+      const scenariosVar = getUpdateVar(props.updateVars, "scenarios");
       dispatch(
       dispatch(
-        createSendActionNameAction(id, module, props.onCtxSelection, { ids: Array.isArray(nodeIds) ? nodeIds : [nodeIds], user_action: props.onAction })
+        createSendUpdateAction(props.updateVarName, nodeIds, module, props.onChange, propagate, scenariosVar)
       );
       );
     },
     },
-    [props.onCtxSelection, module, props.onAction]
+    [props.updateVarName, props.updateVars, props.onChange, propagate, module]
   );
   );
 
 
   return (
   return (
@@ -241,7 +246,7 @@ const ScenarioSelector = (props: ScenarioSelectorProps) => {
         <TreeView defaultCollapseIcon={<ExpandMore />} defaultExpandIcon={<ChevronRight />} sx={TreeViewSx} onNodeSelect={onSelect}>
         <TreeView defaultCollapseIcon={<ExpandMore />} defaultExpandIcon={<ChevronRight />} sx={TreeViewSx} onNodeSelect={onSelect}>
           {scenarios
           {scenarios
             ? scenarios.map((item) => {
             ? scenarios.map((item) => {
-                const [id, label, nodeType, _, scenarios] = item;
+                const [id, label, scenarios, nodeType, _] = item;
                 return (
                 return (
                   <>
                   <>
                     {displayCycles ? (
                     {displayCycles ? (

+ 60 - 66
src/taipy/gui_core/GuiCoreLib.py

@@ -10,17 +10,39 @@
 # specific language governing permissions and limitations under the License.
 # specific language governing permissions and limitations under the License.
 
 
 import typing as t
 import typing as t
-import warnings
 
 
 from dateutil import parser
 from dateutil import parser
 
 
 import taipy as tp
 import taipy as tp
-from taipy.core import Scenario
+from taipy.core import Cycle, Scenario
 from taipy.core.notification import CoreEventConsumerBase, EventEntityType
 from taipy.core.notification import CoreEventConsumerBase, EventEntityType
 from taipy.core.notification.event import Event
 from taipy.core.notification.event import Event
 from taipy.core.notification.notifier import Notifier
 from taipy.core.notification.notifier import Notifier
 from taipy.gui import Gui, State
 from taipy.gui import Gui, State
 from taipy.gui.extension import Element, ElementLibrary, ElementProperty, PropertyType
 from taipy.gui.extension import Element, ElementLibrary, ElementProperty, PropertyType
+from taipy.gui.utils import _TaipyBase
+
+
+class GuiCoreScenarioAdapter(_TaipyBase):
+    def get(self):
+        data = super().get()
+        if isinstance(data, Scenario):
+            return [
+                data.id,
+                data.is_primary,
+                data.config_id,
+                data.creation_date,
+                data.get_label(),
+                list(data.tags),
+                list(data.properties.items()),
+                [(p.id, p.get_simple_label()) for p in data.pipelines.values()],
+                list(data.properties.get("authorized_tags", set())),
+            ]
+        return data
+
+    @staticmethod
+    def get_hash():
+        return _TaipyBase._HOLDER_PREFIX + "Sc"
 
 
 
 
 class GuiCoreContext(CoreEventConsumerBase):
 class GuiCoreContext(CoreEventConsumerBase):
@@ -33,9 +55,7 @@ class GuiCoreContext(CoreEventConsumerBase):
 
 
     def __init__(self, gui: Gui) -> None:
     def __init__(self, gui: Gui) -> None:
         self.gui = gui
         self.gui = gui
-        self.scenarios: t.Optional[
-            t.List[t.Tuple[str, str, int, bool, t.Optional[t.List[t.Tuple[str, str, int, bool, None]]]]]
-        ] = None
+        self.cycles_scenarios: t.Optional[t.List[t.Union[Cycle, Scenario]]] = None
         self.scenario_configs: t.Optional[t.List[t.Tuple[str, str]]] = None
         self.scenario_configs: t.Optional[t.List[t.Tuple[str, str]]] = None
         # register to taipy core notification
         # register to taipy core notification
         reg_id, reg_queue = Notifier.register()
         reg_id, reg_queue = Notifier.register()
@@ -44,24 +64,26 @@ class GuiCoreContext(CoreEventConsumerBase):
 
 
     def process_event(self, event: Event):
     def process_event(self, event: Event):
         if event.entity_type == EventEntityType.SCENARIO or event.entity_type == EventEntityType.CYCLE:
         if event.entity_type == EventEntityType.SCENARIO or event.entity_type == EventEntityType.CYCLE:
-            self.scenarios = None
+            self.cycles_scenarios = None
             self.gui.broadcast(GuiCoreContext._CORE_CHANGED_NAME, {"scenario": True})
             self.gui.broadcast(GuiCoreContext._CORE_CHANGED_NAME, {"scenario": True})
 
 
-    def get_scenarios(self):
-        if self.scenarios is None:
-
-            def add_scenarios(res, scens):
-                for scenario in scens:
-                    res.append((scenario.id, scenario.name, 1, scenario.is_primary, None))
-                return res
+    @staticmethod
+    def scenario_adapter(data):
+        if isinstance(data, Cycle):
+            return (data.id, data.name, tp.get_scenarios(data), 0, False)
+        elif isinstance(data, Scenario):
+            return (data.id, data.name, None, 1, data.is_primary)
+        return data
 
 
-            self.scenarios = []
+    def get_scenarios(self):
+        if self.cycles_scenarios is None:
+            self.cycles_scenarios = []
             for cycle, scenarios in tp.get_cycles_scenarios().items():
             for cycle, scenarios in tp.get_cycles_scenarios().items():
                 if cycle is None:
                 if cycle is None:
-                    add_scenarios(self.scenarios, scenarios)
+                    self.cycles_scenarios.extend(scenarios)
                 else:
                 else:
-                    self.scenarios.append((cycle.id, cycle.name, 0, False, add_scenarios([], scenarios)))
-        return self.scenarios
+                    self.cycles_scenarios.append(cycle)
+        return self.cycles_scenarios
 
 
     def get_scenario_configs(self):
     def get_scenario_configs(self):
         if self.scenario_configs is None:
         if self.scenario_configs is None:
@@ -71,7 +93,6 @@ class GuiCoreContext(CoreEventConsumerBase):
         return self.scenario_configs
         return self.scenario_configs
 
 
     def create_new_scenario(self, state: State, id: str, action: str, payload: t.Dict[str, str]):
     def create_new_scenario(self, state: State, id: str, action: str, payload: t.Dict[str, str]):
-        print(f"create_new_scenario(state, {id}, {action}, {payload}")
         args = payload.get("args")
         args = payload.get("args")
         if args is None or not isinstance(args, list) or len(args) == 0 or not isinstance(args[0], dict):
         if args is None or not isinstance(args, list) or len(args) == 0 or not isinstance(args[0], dict):
             return
             return
@@ -87,48 +108,17 @@ class GuiCoreContext(CoreEventConsumerBase):
         except Exception as e:
         except Exception as e:
             state.assign(GuiCoreContext._ERROR_VAR, f"Invalid date ({date_str}).{e}")
             state.assign(GuiCoreContext._ERROR_VAR, f"Invalid date ({date_str}).{e}")
             return
             return
-        scenario = tp.create_scenario(scenario_config, date, data.get(GuiCoreContext.__PROP_SCENARIO_NAME))
-        if props := data.get("properties"):
-            with scenario as sc:
-                for prop in props:
-                    key = prop.get("key")
-                    if key and key not in GuiCoreContext.__SCENARIO_PROPS:
-                        sc._properties[key] = prop.get("value")
-        state.assign(GuiCoreContext._ERROR_VAR, "")
-
-    def select_scenario(self, state: State, id: str, action: str, payload: t.Dict[str, str]):
-        print(f"select_scenario(state, {id}, {action}, {payload}")
-        args = payload.get("args")
-        if args is None or not isinstance(args, list) or len(args) == 0 or not isinstance(args[0], dict):
-            return
-        data = args[0]
-        action = data.get("user_action")
-        action_function = None
-        if action:
-            action_function = self.gui._get_user_function(action)
-            if not callable(action_function):
-                action_function = None
-                warnings.warn(f"on_select ({action_function}) function is not callable.")
-                return
-        if action_function is None:
-            if not hasattr(self.gui, "on_action"):
-                return
-            action_function = self.gui.on_action
-        ids = data.get("ids")
-        if not isinstance(ids, list) or len(ids) == 0:
-            state.assign(GuiCoreContext._ERROR_VAR, "Invalid selection.")
-            return
-        scenarios: t.List[Scenario] = []
-        for id in ids:
-            try:
-                entity = tp.get(id)
-                if isinstance(entity, Scenario):
-                    scenarios.append(entity)
-            except Exception:
-                pass
-        if len(scenarios) == 0:
-            return
-        self.gui._call_function_with_state(action_function, [id, action_function.__name__, scenarios[0]])
+        try:
+            scenario = tp.create_scenario(scenario_config, date, data.get(GuiCoreContext.__PROP_SCENARIO_NAME))
+            if props := data.get("properties"):
+                with scenario as sc:
+                    for prop in props:
+                        key = prop.get("key")
+                        if key and key not in GuiCoreContext.__SCENARIO_PROPS:
+                            sc._properties[key] = prop.get("value")
+            state.assign(GuiCoreContext._ERROR_VAR, "")
+        except Exception as e:
+            state.assign(GuiCoreContext._ERROR_VAR, f"Error creating Scenario. {e}")
 
 
     def broadcast_core_changed(self):
     def broadcast_core_changed(self):
         self.gui.broadcast(GuiCoreContext._CORE_CHANGED_NAME, "")
         self.gui.broadcast(GuiCoreContext._CORE_CHANGED_NAME, "")
@@ -140,21 +130,25 @@ class GuiCore(ElementLibrary):
 
 
     __elts = {
     __elts = {
         "scenario_selector": Element(
         "scenario_selector": Element(
-            "scenario_id",
+            "value",
             {
             {
                 "show_add_button": ElementProperty(PropertyType.dynamic_boolean, True),
                 "show_add_button": ElementProperty(PropertyType.dynamic_boolean, True),
                 "display_cycles": ElementProperty(PropertyType.dynamic_boolean, True),
                 "display_cycles": ElementProperty(PropertyType.dynamic_boolean, True),
                 "show_primary_flag": ElementProperty(PropertyType.dynamic_boolean, True),
                 "show_primary_flag": ElementProperty(PropertyType.dynamic_boolean, True),
-                "scenario_id": ElementProperty(PropertyType.dynamic_string),
-                "scenarios": ElementProperty(PropertyType.react, f"{{{__CTX_VAR_NAME}.get_scenarios()}}"),
+                "value": ElementProperty(PropertyType.lov_value),
+                "on_change": ElementProperty(PropertyType.function),
+                "scenario": ElementProperty(GuiCoreScenarioAdapter),
+            },
+            inner_properties={
+                "scenarios": ElementProperty(PropertyType.lov, f"{{{__CTX_VAR_NAME}.get_scenarios()}}"),
                 "on_scenario_create": ElementProperty(
                 "on_scenario_create": ElementProperty(
                     PropertyType.function, f"{{{__CTX_VAR_NAME}.create_new_scenario}}"
                     PropertyType.function, f"{{{__CTX_VAR_NAME}.create_new_scenario}}"
                 ),
                 ),
                 "configs": ElementProperty(PropertyType.react, f"{{{__CTX_VAR_NAME}.get_scenario_configs()}}"),
                 "configs": ElementProperty(PropertyType.react, f"{{{__CTX_VAR_NAME}.get_scenario_configs()}}"),
                 "core_changed": ElementProperty(PropertyType.broadcast, GuiCoreContext._CORE_CHANGED_NAME),
                 "core_changed": ElementProperty(PropertyType.broadcast, GuiCoreContext._CORE_CHANGED_NAME),
-                "error": ElementProperty(PropertyType.react, GuiCoreContext._ERROR_VAR),
-                "on_ctx_selection": ElementProperty(PropertyType.function, f"{{{__CTX_VAR_NAME}.select_scenario}}"),
-                "on_action": ElementProperty(PropertyType.function),
+                "error": ElementProperty(PropertyType.react, f"{{{GuiCoreContext._ERROR_VAR}}}"),
+                "type": ElementProperty(PropertyType.inner, Scenario),
+                "adapter": ElementProperty(PropertyType.inner, GuiCoreContext.scenario_adapter),
             },
             },
         )
         )
     }
     }