From 1310af27a0cf76f1d23ec892945e0d6338c96cf2 Mon Sep 17 00:00:00 2001 From: mmikita95 Date: Thu, 22 Feb 2024 15:51:19 +0300 Subject: [PATCH] chore: prepare UI component handling for enhanced session and CMC integration - Include session-specific component tree in EventResponse payload - Update SessionComponentTree.to_dict to properly merge session-specific and base components, prioritizing session-specific ones - Add optional `flag` attribute to Component class for CMC control - Extend frontend Component type with `flag` property - Implement Component.from_dict class method to enable deserialization - Introduce frontend core logic to update components based on backend session tree data --- src/streamsync/app_runner.py | 1 + src/streamsync/core.py | 33 +++++++++++++++++++++++++++++---- src/streamsync/ss_types.py | 1 + ui/src/core/index.ts | 20 +++++++++++++++++++- ui/src/streamsyncTypes.ts | 1 + 5 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/streamsync/app_runner.py b/src/streamsync/app_runner.py index e0c316264..934cc2e9e 100644 --- a/src/streamsync/app_runner.py +++ b/src/streamsync/app_runner.py @@ -177,6 +177,7 @@ def _handle_event(self, session: StreamsyncSession, event: StreamsyncEvent) -> E res_payload = EventResponsePayload( result=result, mutations=mutations, + components=session.session_component_tree.to_dict(), mail=mail ) diff --git a/src/streamsync/core.py b/src/streamsync/core.py index 793d570d0..3222c40fa 100644 --- a/src/streamsync/core.py +++ b/src/streamsync/core.py @@ -477,9 +477,10 @@ def call_frontend_function(self, module_key: str, function_name: str, args: List class Component: - def __init__(self, id: str, type: str, content: Dict[str, str] = {}): + def __init__(self, id: str, type: str, content: Dict[str, str] = {}, flag: Optional[str] = None): self.id = id self.type = type + self.flag = flag self.content = content self.position: int = 0 self.parentId: Optional[str] = None @@ -487,13 +488,31 @@ def __init__(self, id: str, type: str, content: Dict[str, str] = {}): self.visible: Optional[bool] = None self.binding: Optional[Dict] = None + @classmethod + def from_dict(cls, c_dict: Dict) -> 'Component': + # Create a new Component instance with basic properties. + component = cls( + id=c_dict["id"], + type=c_dict["type"], + content=c_dict.get("content", {}), + flag=c_dict.get("flag") + ) + # Set optional properties if they exist in the dictionary. + component.parentId = c_dict.get("parentId") + component.position = c_dict.get("position", 0) + component.handlers = c_dict.get("handlers") + component.visible = c_dict.get("visible") + component.binding = c_dict.get("binding") + + return component + def to_dict(self) -> Dict: c_dict = { "id": self.id, "type": self.type, "content": self.content, "parentId": self.parentId, - "position": self.position, + "position": self.position } if self.handlers is not None: c_dict["handlers"] = self.handlers @@ -501,6 +520,8 @@ def to_dict(self) -> Dict: c_dict["binding"] = self.binding if self.visible is not None: c_dict["visible"] = self.visible + if self.flag is not None: + c_dict["flag"] = self.flag return c_dict @@ -565,8 +586,12 @@ def get_component(self, component_id: str) -> Optional[Component]: return self.components.get(component_id) def to_dict(self) -> Dict: - active_components = {} - for id, component in {**self.components, **self.base_component_tree.components}.items(): + active_components = { + k: v.to_dict() + for k, v in self.base_component_tree.components.items() + } + for id, component in {**self.components}.items(): + # Overriding base tree components with session-specific ones active_components[id] = component.to_dict() return active_components diff --git a/src/streamsync/ss_types.py b/src/streamsync/ss_types.py index cd3335d09..d48cd5d5c 100644 --- a/src/streamsync/ss_types.py +++ b/src/streamsync/ss_types.py @@ -134,6 +134,7 @@ class EventResponsePayload(BaseModel): result: Any mutations: Dict[str, Any] mail: List + components: Dict class StateEnquiryResponsePayload(BaseModel): diff --git a/ui/src/core/index.ts b/ui/src/core/index.ts index 69c5c3096..1440ddc44 100644 --- a/ui/src/core/index.ts +++ b/ui/src/core/index.ts @@ -158,6 +158,11 @@ export function generateCore() { }); } + function updateComponents(newComponents: Record) { + if (!newComponents) return; + components.value = newComponents + } + function clearFrontendMap() { frontendMessageMap.value.forEach(({ callback }) => { callback?.({ ok: false }); @@ -198,6 +203,7 @@ export function generateCore() { ) { ingestMutations(message.payload?.mutations); collateMail(message.payload?.mail); + updateComponents(message.payload?.components); } const mapItem = frontendMessageMap.value.get(message.trackingId); @@ -429,8 +435,20 @@ export function generateCore() { * @returns */ async function sendComponentUpdate(): Promise { + /* + Only send components created by the frontend (static), to avoid re-feeding the backend + those components created by the backend. + */ + + const staticComponents = {}; + + Object.entries(components.value).forEach(([componentId, component]) => { + if (component.flag === 'cmc') return; + staticComponents[componentId] = component; + }); + const payload = { - components: components.value, + components: staticComponents, }; return new Promise((resolve, reject) => { diff --git a/ui/src/streamsyncTypes.ts b/ui/src/streamsyncTypes.ts index 6d18f31c4..2cafbed30 100644 --- a/ui/src/streamsyncTypes.ts +++ b/ui/src/streamsyncTypes.ts @@ -12,6 +12,7 @@ export type Component = { type: string; position: number; content: Record; + flag?: string; handlers?: Record; visible?: boolean | string; binding?: {