Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: prepare UI component handling for enhanced session and CMC integration #258

Merged
merged 7 commits into from
Mar 1, 2024
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
48 changes: 39 additions & 9 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':
mmikita95 marked this conversation as resolved.
Show resolved Hide resolved
# 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 @@ -550,7 +571,7 @@ def to_dict(self) -> Dict:
for id, component in self.components.items():
active_components[id] = component.to_dict()
return active_components


class SessionComponentTree(ComponentTree):

Expand All @@ -559,14 +580,23 @@ def __init__(self, base_component_tree: ComponentTree):
self.base_component_tree = base_component_tree

def get_component(self, component_id: str) -> Optional[Component]:
base_component = self.base_component_tree.get_component(component_id)
if base_component:
return base_component
return self.components.get(component_id)
session_component_present = component_id in self.components
session_component = self.components.get(component_id)

if session_component_present:
return session_component

return self.base_component_tree.get_component(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()
mmikita95 marked this conversation as resolved.
Show resolved Hide resolved
}
for id, component in {**self.components}.items():
mmikita95 marked this conversation as resolved.
Show resolved Hide resolved
# 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>) {
mmikita95 marked this conversation as resolved.
Show resolved Hide resolved
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
mmikita95 marked this conversation as resolved.
Show resolved Hide resolved
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
Loading