Skip to content

Commit

Permalink
chore: prepare UI component handling for enhanced session and CMC int…
Browse files Browse the repository at this point in the history
…egration

- 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
  • Loading branch information
mmikita95 committed Feb 22, 2024
1 parent 0db0d6f commit 1310af2
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/streamsync/app_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

Expand Down
33 changes: 29 additions & 4 deletions src/streamsync/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,30 +477,51 @@ 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
self.handlers: Optional[Dict[str, str]] = None
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
if self.binding is not None:
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


Expand Down Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions src/streamsync/ss_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ class EventResponsePayload(BaseModel):
result: Any
mutations: Dict[str, Any]
mail: List
components: Dict


class StateEnquiryResponsePayload(BaseModel):
Expand Down
20 changes: 19 additions & 1 deletion ui/src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ export function generateCore() {
});
}

function updateComponents(newComponents: Record<string, any>) {
if (!newComponents) return;
components.value = newComponents
}

function clearFrontendMap() {
frontendMessageMap.value.forEach(({ callback }) => {
callback?.({ ok: false });
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -429,8 +435,20 @@ export function generateCore() {
* @returns
*/
async function sendComponentUpdate(): Promise<void> {
/*
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) => {
Expand Down
1 change: 1 addition & 0 deletions ui/src/streamsyncTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type Component = {
type: string;
position: number;
content: Record<string, string>;
flag?: string;
handlers?: Record<string, string>;
visible?: boolean | string;
binding?: {
Expand Down

0 comments on commit 1310af2

Please sign in to comment.