Skip to content

Commit

Permalink
Have DevTools rely on JSON proto serialization server-side instead of…
Browse files Browse the repository at this point in the history
… client-side toObject (closes #21)
  • Loading branch information
wwwillchen committed Dec 13, 2023
1 parent e660576 commit 8a893c9
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 73 deletions.
27 changes: 19 additions & 8 deletions optic/component_helpers/helper.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
from typing import Any, Callable, Type, TypeVar

from google.protobuf import json_format
from google.protobuf.message import Message

import optic.protos.ui_pb2 as pb
from optic.events import OpticEvent
from optic.key import Key
from optic.runtime import runtime


class ComponentWithChildren:
def __init__(
self,
component: pb.Component,
):
def __init__(self, type_name: str, proto: Message, key: str | None = None):
self.prev_current_node = runtime().context().current_node()
self.component = component
self.component = create_component(type_name=type_name, proto=proto, key=key)

def __enter__(self):
runtime().context().set_current_node(self.component)
Expand All @@ -24,13 +24,24 @@ def __exit__(self, exc_type, exc_val, exc_tb): # type: ignore
self.prev_current_node.children.append(self.component)


def insert_component(type: pb.Type, key: str | None = None):
def create_component(
type_name: str, proto: Message, key: str | None = None
) -> pb.Component:
type = pb.Type(name=type_name, value=proto.SerializeToString())
if runtime().debug_mode:
type.debug_json = json_format.MessageToJson(
proto, preserving_proto_field_name=True
)

return pb.Component(key=pb.Key(key=key) if key else None, type=type)


def insert_component(type_name: str, proto: Message, key: str | None = None):
"""
Inserts a component into the current context's current node.
"""

runtime().context().current_node().children.append(
pb.Component(key=pb.Key(key=key) if key else None, type=type)
create_component(type_name=type_name, proto=proto, key=key)
)


Expand Down
13 changes: 3 additions & 10 deletions optic/components/box/box.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from pydantic import validate_arguments

import optic.components.box.box_pb2 as box_pb
import optic.protos.ui_pb2 as pb
from optic.component_helpers import ComponentWithChildren


Expand All @@ -18,13 +17,7 @@ def box(
label (str): The text to be displayed
"""
return ComponentWithChildren(
component=pb.Component(
key=pb.Key(key=key or ""),
type=pb.Type(
name="box",
value=box_pb.BoxType(
background_color=background_color
).SerializeToString(),
),
),
key=key,
type_name="box",
proto=box_pb.BoxType(background_color=background_color),
)
16 changes: 8 additions & 8 deletions optic/components/button/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
from pydantic import validate_arguments

import optic.components.button.button_pb2 as button_pb
import optic.protos.ui_pb2 as pb
from optic.component_helpers import handler_type, insert_component
from optic.component_helpers import (
handler_type,
insert_component,
)
from optic.events import ClickEvent


Expand All @@ -24,11 +26,9 @@ def button(
"""
insert_component(
key=key,
type=pb.Type(
name="button",
value=button_pb.ButtonType(
label=label,
on_click_handler_id=handler_type(on_click),
).SerializeToString(),
type_name="button",
proto=button_pb.ButtonType(
label=label,
on_click_handler_id=handler_type(on_click),
),
)
11 changes: 4 additions & 7 deletions optic/components/checkbox/checkbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from pydantic import validate_arguments

import optic.components.checkbox.checkbox_pb2 as checkbox_pb
import optic.protos.ui_pb2 as pb
from optic.component_helpers import (
handler_type,
insert_component,
Expand Down Expand Up @@ -36,12 +35,10 @@ def checkbox(
"""
insert_component(
key=key,
type=pb.Type(
name="checkbox",
value=checkbox_pb.CheckboxType(
label=label,
on_update_handler_id=handler_type(on_update),
).SerializeToString(),
type_name="checkbox",
proto=checkbox_pb.CheckboxType(
label=label,
on_update_handler_id=handler_type(on_update),
),
)

Expand Down
6 changes: 1 addition & 5 deletions optic/components/text/text.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from pydantic import validate_arguments

import optic.components.text.text_pb2 as text_pb2
import optic.protos.ui_pb2 as pb
from optic.component_helpers import insert_component


Expand All @@ -12,8 +11,5 @@ def text(
key: str | None = None,
):
insert_component(
key=key,
type=pb.Type(
name="text", value=text_pb2.TextType(text=text).SerializeToString()
),
key=key, type_name="text", proto=text_pb2.TextType(text=text)
)
11 changes: 4 additions & 7 deletions optic/components/text_input/text_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from pydantic import validate_arguments

import optic.components.text_input.text_input_pb2 as text_input_pb
import optic.protos.ui_pb2 as pb
from optic.component_helpers import handler_type, insert_component
from optic.events import ChangeEvent

Expand All @@ -24,11 +23,9 @@ def text_input(
"""
insert_component(
key=key,
type=pb.Type(
name="text_input",
value=text_input_pb.TextInputType(
label=label,
on_change_handler_id=handler_type(on_change),
).SerializeToString(),
type_name="text_input",
proto=text_input_pb.TextInputType(
label=label,
on_change_handler_id=handler_type(on_change),
),
)
18 changes: 10 additions & 8 deletions optic/web/src/dev_tools/component_tree/component_tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import {CdkTreeModule} from '@angular/cdk/tree';
import {MatIconModule} from '@angular/material/icon';
import {MatButtonModule} from '@angular/material/button';
import {ComponentObject} from '../services/logger';

/** Flat node with expandable and level information */
export interface ExampleFlatNode {
Expand All @@ -26,7 +27,7 @@ export interface ExampleFlatNode {
imports: [CdkTreeModule, MatTreeModule, MatButtonModule, MatIconModule],
})
export class ComponentTree {
@Input({required: true}) component!: InputNode;
@Input({required: true}) component!: ComponentObject;
@Output() nodeSelected = new EventEmitter<ExampleFlatNode>();

keys() {
Expand Down Expand Up @@ -73,7 +74,7 @@ export class ComponentTree {
}
}

function mapObject(object: InputNode): DisplayNode {
function mapObject(object: ComponentObject): DisplayNode {
const node: DisplayNode = {
componentName: '<undefined>',
text: '',
Expand All @@ -87,15 +88,16 @@ function mapObject(object: InputNode): DisplayNode {
return `${key}=${JSON.stringify(value)}`;
})
.join(', ');
node.text = `${object.type.name}(${values})`;
node.properties = object.type.value;
(node.properties as any).key = object.key?.key;
node.componentName = object.type.name;
const name = object.type.name;
node.text = `${name}(${values})`;
node.properties = object.type as any;
(node.properties as any).key = object.key;
node.componentName = name;
} else {
node.text = `<root>`;
}
if (object.childrenList) {
node.children = object.childrenList.map((child) => mapObject(child));
if (object.children) {
node.children = object.children.map((child) => mapObject(child));
}
return node;
}
Expand Down
6 changes: 3 additions & 3 deletions optic/web/src/dev_tools/components_panel/components_panel.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Component} from '@angular/core';
import {Logger, RenderLogModel} from '../services/logger';
import {ComponentObject, Logger, RenderLogModel} from '../services/logger';
import {
ComponentTree,
ExampleFlatNode,
Expand All @@ -18,13 +18,13 @@ export class ComponentsPanel {
selectedNode!: ExampleFlatNode;
constructor(private logger: Logger) {}

component(): InputNode {
component(): ComponentObject {
const renderLog = this.logger
.getLogs()
.slice()
.reverse()
.find((log) => log.type === 'Render') as RenderLogModel;
return renderLog?.rootComponent as InputNode;
return renderLog?.rootComponent as ComponentObject;
}

onNodeSelected(node: ExampleFlatNode): void {
Expand Down
44 changes: 27 additions & 17 deletions optic/web/src/dev_tools/services/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
States,
UserEvent,
Component as ComponentProto,
Type,
} from 'optic/optic/protos/ui_jspb_proto_pb/optic/protos/ui_pb';
import {TypeDeserializer} from './type_deserializer';
import {Observable, Subject} from 'rxjs';
Expand Down Expand Up @@ -55,37 +56,46 @@ export class Logger {
duration,
};
case 'RenderLog':
const rootComponent = input.rootComponent.toObject();
this.updateComponent(rootComponent);
return {
type: 'Render',
timestamp: Date.now(),
duration,
states: input.states
.getStatesList()
.map((s) => jsonParse(s.getData())) as object[],
rootComponent,
rootComponent: this.mapComponent(input.rootComponent),
};
}
}

updateComponent(component: object): void {
const type = (component as any)['type'];
if (type) {
type['value'] = this._typeDeserializer.deserialize(
type['name'],
type['value'],
);
}
const children = (component as any)['childrenList'];
if (children) {
for (const child of children) {
this.updateComponent(child);
}
mapComponent(component: ComponentProto): ComponentObject {
const debugJson = component.getType()?.getDebugJson();
let type;
if (debugJson) {
type = {
name: component.getType()!.getName(),
value: jsonParse(debugJson) as object,
};
}
return {
type,
key: component.getKey()?.getKey(),
children: component
.getChildrenList()
.map((child) => this.mapComponent(child)),
};
}
}

export interface ComponentObject {
type?: {
name: string;
value: object;
};
key?: string;
children: ComponentObject[];
}

export interface BaseLogModel {
type: string;
timestamp: number; // Use Date.now()
Expand All @@ -107,7 +117,7 @@ export interface UserEventLogModel extends BaseLogModel {

export interface RenderLogModel extends BaseLogModel {
type: 'Render';
rootComponent: object;
rootComponent: ComponentObject;
states: object[];
}

Expand Down

0 comments on commit 8a893c9

Please sign in to comment.