浏览代码

#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 年之前
父节点
当前提交
7ec184e135
共有 2 个文件被更改,包括 74 次插入75 次删除
  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,
   createSendActionNameAction,
   useDispatchRequestUpdateOnFirstRender,
+  createSendUpdateAction,
 } from "taipy-gui";
 
 enum NodeType {
@@ -51,9 +52,9 @@ enum NodeType {
   SCENARIO = 1,
 }
 
-type Scenario = [string, string, number, boolean];
+type Scenario = [string, string, undefined, number, boolean];
 type Scenarios = Array<Scenario>;
-type Cycles = Array<[string, string, number, boolean, Scenarios]>;
+type Cycles = Array<[string, string, Scenarios, number, boolean]>;
 
 interface ScenarioSelectorProps {
   id?: string;
@@ -63,14 +64,17 @@ interface ScenarioSelectorProps {
   displayCycles?: boolean;
   defaultShowPrimaryFlag: boolean;
   showPrimaryFlag?: boolean;
+  value?: Record<string, any>;
+  updateVarName?: string;
   scenarios?: Cycles | Scenarios;
   onScenarioCreate: string;
-  onCtxSelection: string;
-  onAction?: string;
+  onChange?: string;
   coreChanged?: Record<string, unknown>;
   updateVars: string;
   configs?: Array<[string, string]>;
   error?: string;
+  propagate?: boolean;
+  scenario?: Record<string, string>
 }
 
 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] : [];
   return (
     <>
-      {sc.map(([id, label, _, primary]) => (
+      {sc.map(([id, label, _, _nodeType, primary]) => (
         <TreeItem
           key={id}
           nodeId={id}
@@ -156,7 +160,7 @@ const DialogContentSx = {
 };
 
 const ScenarioSelector = (props: ScenarioSelectorProps) => {
-  const { id = "", scenarios = [] } = props;
+  const { id = "", scenarios = [], propagate = true } = props;
   const [open, setOpen] = useState(false);
   const [properties, setProperties] = useState<Property[]>([]);
   const [newProp, setNewProp] = useState<Property>({ id: "", key: "", value: "" });
@@ -228,11 +232,12 @@ const ScenarioSelector = (props: ScenarioSelectorProps) => {
 
   const onSelect = useCallback(
     (e: React.SyntheticEvent, nodeIds: Array<string> | string) => {
+      const scenariosVar = getUpdateVar(props.updateVars, "scenarios");
       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 (
@@ -241,7 +246,7 @@ const ScenarioSelector = (props: ScenarioSelectorProps) => {
         <TreeView defaultCollapseIcon={<ExpandMore />} defaultExpandIcon={<ChevronRight />} sx={TreeViewSx} onNodeSelect={onSelect}>
           {scenarios
             ? scenarios.map((item) => {
-                const [id, label, nodeType, _, scenarios] = item;
+                const [id, label, scenarios, nodeType, _] = item;
                 return (
                   <>
                     {displayCycles ? (

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

@@ -10,17 +10,39 @@
 # specific language governing permissions and limitations under the License.
 
 import typing as t
-import warnings
 
 from dateutil import parser
 
 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.event import Event
 from taipy.core.notification.notifier import Notifier
 from taipy.gui import Gui, State
 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):
@@ -33,9 +55,7 @@ class GuiCoreContext(CoreEventConsumerBase):
 
     def __init__(self, gui: Gui) -> None:
         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
         # register to taipy core notification
         reg_id, reg_queue = Notifier.register()
@@ -44,24 +64,26 @@ class GuiCoreContext(CoreEventConsumerBase):
 
     def process_event(self, event: Event):
         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})
 
-    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():
                 if cycle is None:
-                    add_scenarios(self.scenarios, scenarios)
+                    self.cycles_scenarios.extend(scenarios)
                 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):
         if self.scenario_configs is None:
@@ -71,7 +93,6 @@ class GuiCoreContext(CoreEventConsumerBase):
         return self.scenario_configs
 
     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")
         if args is None or not isinstance(args, list) or len(args) == 0 or not isinstance(args[0], dict):
             return
@@ -87,48 +108,17 @@ class GuiCoreContext(CoreEventConsumerBase):
         except Exception as e:
             state.assign(GuiCoreContext._ERROR_VAR, f"Invalid date ({date_str}).{e}")
             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):
         self.gui.broadcast(GuiCoreContext._CORE_CHANGED_NAME, "")
@@ -140,21 +130,25 @@ class GuiCore(ElementLibrary):
 
     __elts = {
         "scenario_selector": Element(
-            "scenario_id",
+            "value",
             {
                 "show_add_button": ElementProperty(PropertyType.dynamic_boolean, True),
                 "display_cycles": 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(
                     PropertyType.function, f"{{{__CTX_VAR_NAME}.create_new_scenario}}"
                 ),
                 "configs": ElementProperty(PropertyType.react, f"{{{__CTX_VAR_NAME}.get_scenario_configs()}}"),
                 "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),
             },
         )
     }