diff --git a/dev_plugin/src/detail-view.tsx b/dev_plugin/src/detail-view.tsx
index 075d0a9..3040b48 100644
--- a/dev_plugin/src/detail-view.tsx
+++ b/dev_plugin/src/detail-view.tsx
@@ -60,8 +60,6 @@ export default function DetailView(): ReactElement {
const env = Deno.env.get("RUST_LOG");
console.log("RUST_LOG:", env);
- const logoData = assetData("logo.png");
-
console.error("DetailView error")
useEffect(() => {
@@ -113,7 +111,7 @@ export default function DetailView(): ReactElement {
H4 Title
H5 Title
H6 Title
-
+
Code block Test
diff --git a/js/api/src/gen/components.tsx b/js/api/src/gen/components.tsx
index 4f0f889..486b8b2 100644
--- a/js/api/src/gen/components.tsx
+++ b/js/api/src/gen/components.tsx
@@ -42,7 +42,7 @@ declare global {
children?: ElementComponent;
};
["gauntlet:image"]: {
- source: ImageSource;
+ source: ImageSource | Icons;
};
["gauntlet:h1"]: {
children?: StringComponent;
@@ -119,7 +119,7 @@ declare global {
["gauntlet:empty_view"]: {
title: string;
description?: string;
- image?: ImageSource;
+ image?: ImageSource | Icons;
};
["gauntlet:list_item"]: {
id: string;
@@ -163,6 +163,9 @@ export type EmptyNode = boolean | null | undefined;
export type ElementComponent> = Element | EmptyNode | Iterable>;
export type StringComponent = StringNode | EmptyNode | Iterable;
export type StringOrElementComponent> = StringNode | EmptyNode | Element | Iterable>;
+export type ImageSource = {
+ asset: string;
+};
export enum Icons {
PersonAdd = "PersonAdd",
Airplane = "Airplane",
@@ -336,9 +339,6 @@ export enum Icons {
Indent = "Indent",
Unindent = "Unindent"
}
-export type ImageSource = {
- data: ArrayBuffer;
-};
export interface ActionProps {
id?: string;
title: string;
@@ -429,7 +429,7 @@ Metadata.Value = MetadataValue;
Metadata.Icon = MetadataIcon;
Metadata.Separator = MetadataSeparator;
export interface ImageProps {
- source: ImageSource;
+ source: ImageSource | Icons;
}
export const Image: FC = (props: ImageProps): ReactNode => {
return ;
@@ -623,7 +623,7 @@ Inline.Center = Content;
export interface EmptyViewProps {
title: string;
description?: string;
- image?: ImageSource;
+ image?: ImageSource | Icons;
}
export const EmptyView: FC = (props: EmptyViewProps): ReactNode => {
return ;
diff --git a/js/api_build/src/index.ts b/js/api_build/src/index.ts
index 03e7648..3742f9e 100644
--- a/js/api_build/src/index.ts
+++ b/js/api_build/src/index.ts
@@ -241,6 +241,31 @@ function makeComponents(modelInput: Component[]): ts.SourceFile {
const root = modelInput.find((component): component is RootComponent => component.type === "root");
if (root != null) {
+ // image special case
+ // export type ImageSource = { asset: string } | { url: string };
+
+ const imageSourceDeclaration = ts.factory.createTypeAliasDeclaration(
+ [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
+ ts.factory.createIdentifier("ImageSource"),
+ undefined,
+ ts.factory.createUnionTypeNode([
+ ts.factory.createTypeLiteralNode([ts.factory.createPropertySignature(
+ undefined,
+ ts.factory.createIdentifier("asset"),
+ undefined,
+ ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
+ )]),
+ // ts.factory.createTypeLiteralNode([ts.factory.createPropertySignature( // TODO implement url imagesource
+ // undefined,
+ // ts.factory.createIdentifier("url"),
+ // undefined,
+ // ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
+ // )])
+ ])
+ );
+
+ publicDeclarations.push(imageSourceDeclaration)
+
for (const [name, sharedType] of Object.entries(root.sharedTypes)) {
switch (sharedType.type) {
@@ -633,9 +658,9 @@ function makeType(type: PropertyType): ts.TypeNode {
]
)
}
- case "image_data": {
+ case "image_source": {
return ts.factory.createTypeReferenceNode(
- ts.factory.createIdentifier("ArrayBuffer"),
+ ts.factory.createIdentifier("ImageSource"),
undefined
)
}
diff --git a/js/react_renderer/src/renderer.ts b/js/react_renderer/src/renderer.ts
index a41b0ca..269bbf8 100644
--- a/js/react_renderer/src/renderer.ts
+++ b/js/react_renderer/src/renderer.ts
@@ -116,49 +116,9 @@ export function getEntrypointPreferences(): Record {
}
function createWidget(hostContext: HostContext, type: ComponentType, properties: Props, children: UiWidget[] = []): Instance {
- const component = hostContext.componentModel[type];
- const rootComponent = hostContext.componentModel["gauntlet:root"] as RootComponent;
- const sharedTypes = rootComponent.sharedTypes;
-
const props = Object.fromEntries(
Object.entries(properties)
.filter(([key, _]) => key !== "children")
- .map(([key, value]) => {
- if (component.type === "standard" && !!value) {
- const prop = component.props.find(prop => prop.name === key)
-
- if (prop) {
- switch (prop.type.type) {
- case "image_data": {
- return [key, Array.from(new Uint8Array(value))]
- }
- case "object": {
- // TODO nested objects?
- const sharedType = sharedTypes[prop.type.name]!!;
- if (sharedType.type !== "object" || typeof value !== "object") {
- throw new Error(key + " property is expected to be an object")
- }
-
- const object = Object.fromEntries(
- Object.entries(value)
- .map(([key, value]) => {
- const prop = sharedType.items[key]
- if (prop.type === "image_data") {
- return [key, Array.from(new Uint8Array(value as any))] // TODO arraybuffer? fix when migrating to deno's op2
- }
-
- return [key, value]
- })
- );
-
- return [key, object]
- }
- }
- }
- }
-
- return [key, value]
- })
);
const instance: Instance = {
diff --git a/js/typings/index.d.ts b/js/typings/index.d.ts
index b598b67..cc3b9c9 100644
--- a/js/typings/index.d.ts
+++ b/js/typings/index.d.ts
@@ -182,7 +182,7 @@ type ComponentRef = {
componentName: string,
}
-type PropertyType = TypeString | TypeNumber | TypeBoolean | TypeComponent | TypeFunction | TypeImageData | TypeImageEnum | TypeImageUnion | TypeImageObject
+type PropertyType = TypeString | TypeNumber | TypeBoolean | TypeComponent | TypeFunction | TypeImageSource | TypeImageEnum | TypeImageUnion | TypeImageObject
type TypeString = {
type: "string"
@@ -201,8 +201,8 @@ type TypeFunction = {
type: "function"
arguments: Property[]
}
-type TypeImageData = {
- type: "image_data"
+type TypeImageSource = {
+ type: "image_source"
}
type TypeImageEnum = {
type: "enum"
diff --git a/rust/client/build.rs b/rust/client/build.rs
index 7caa4df..9412dfb 100644
--- a/rust/client/build.rs
+++ b/rust/client/build.rs
@@ -177,7 +177,7 @@ fn main() -> anyhow::Result<()> {
PropertyType::Component { .. } => {
// component properties are found in a children array
}
- PropertyType::ImageData => {
+ PropertyType::ImageSource => {
if prop.optional {
output.push_str(&format!(" {}: parse_bytes_optional(&properties, \"{}\")?,\n", prop.name, prop.name));
} else {
@@ -520,7 +520,7 @@ fn generate_required_type(property_type: &PropertyType, union_name: String) -> S
PropertyType::Boolean => "bool".to_owned(),
PropertyType::Function { .. } => panic!("client doesn't know about functions in properties"),
PropertyType::Component { .. } => panic!("component properties are found in children array"),
- PropertyType::ImageData => "Vec".to_owned(),
+ PropertyType::ImageSource => "Vec".to_owned(),
PropertyType::Union { .. } => union_name,
PropertyType::Object { name } => name.to_owned(),
PropertyType::Enum { name } => name.to_owned()
diff --git a/rust/client/src/ui/widget.rs b/rust/client/src/ui/widget.rs
index 70f228c..be44b70 100644
--- a/rust/client/src/ui/widget.rs
+++ b/rust/client/src/ui/widget.rs
@@ -4,7 +4,7 @@ use std::str::FromStr;
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
use anyhow::anyhow;
-use iced::{Alignment, Application, Font, Length};
+use iced::{Alignment, Font, Length};
use iced::alignment::Horizontal;
use iced::font::Weight;
use iced::widget::{button, checkbox, column, container, horizontal_rule, horizontal_space, image, pick_list, row, scrollable, Space, text, text_input, tooltip, vertical_rule};
@@ -435,8 +435,17 @@ impl ComponentWidgetWrapper {
ComponentWidget::Image { source } => {
let centered = context.is_content_centered();
- let content: Element<_> = image(Handle::from_memory(source.data.clone())) // FIXME really expensive clone
- .into();
+ let content: Element<_> = match source {
+ ImageSource::_0(bytes) => {
+ image(Handle::from_memory(bytes.clone())) // FIXME really expensive clone
+ .into()
+ }
+ ImageSource::_1(icon) => {
+ text(icon_to_bootstrap(icon))
+ .font(icons::BOOTSTRAP_FONT) // TODO size, height and width
+ .into()
+ }
+ };
let mut content = container(content)
.width(Length::Fill);
@@ -828,11 +837,20 @@ impl ComponentWidgetWrapper {
content
}
- ComponentWidget::EmptyView { title, description, image } => {
- let image: Option> = image.as_ref()
- .map(|image| {
- iced::widget::image(Handle::from_memory(image.data.clone())) // FIXME really expensive clone
- .themed(ImageStyle::EmptyViewImage)
+ ComponentWidget::EmptyView { title, description, image: empty_view_image } => {
+ let image: Option> = empty_view_image.as_ref()
+ .map(|empty_view_image| {
+ match empty_view_image {
+ EmptyViewImage::_0(bytes) => {
+ image(Handle::from_memory(bytes.clone())) // FIXME really expensive clone
+ .themed(ImageStyle::EmptyViewImage)
+ }
+ EmptyViewImage::_1(icon) => {
+ text(icon_to_bootstrap(icon))
+ .font(icons::BOOTSTRAP_FONT) // TODO size, height and width
+ .into()
+ }
+ }
});
let title: Element<_> = text(title)
@@ -875,7 +893,7 @@ impl ComponentWidgetWrapper {
.map(|icon| {
match icon {
ListItemIcon::_0(bytes) => {
- image(Handle::from_memory(bytes.data.clone())) // FIXME really expensive clone
+ image(Handle::from_memory(bytes.clone())) // FIXME really expensive clone
.into()
},
ListItemIcon::_1(icon) => {
@@ -1916,23 +1934,37 @@ impl UiPropertyValueToEnum for ListItemIcon {
fn convert(value: &UiPropertyValue) -> anyhow::Result {
match value {
UiPropertyValue::String(value) => Ok(ListItemIcon::_1(Icons::from_str(value)?)),
+ UiPropertyValue::Bytes(value) => Ok(ListItemIcon::_0(value.clone())), // FIXME really expensive clone
UiPropertyValue::Number(_) => Err(anyhow!("unexpected type number for ListItemIcon")),
UiPropertyValue::Bool(_) => Err(anyhow!("unexpected type bool for ListItemIcon")),
- UiPropertyValue::Bytes(_) => Err(anyhow!("unexpected type bytes for ListItemIcon")),
- UiPropertyValue::Object(value) => {
- Ok(ListItemIcon::_0(ImageSource {
- data: parse_bytes(value, "data")?,
- }))
- }
+ UiPropertyValue::Object(_) => Err(anyhow!("unexpected type object for ListItemIcon")),
UiPropertyValue::Undefined => Err(anyhow!("unexpected type undefined for ListItemIcon"))
}
}
}
-impl UiPropertyValueToStruct for ImageSource {
- fn convert(value: &HashMap) -> anyhow::Result {
- Ok(ImageSource {
- data: parse_bytes(value, "data")?,
- })
+impl UiPropertyValueToEnum for EmptyViewImage {
+ fn convert(value: &UiPropertyValue) -> anyhow::Result {
+ match value {
+ UiPropertyValue::String(value) => Ok(EmptyViewImage::_1(Icons::from_str(value)?)),
+ UiPropertyValue::Bytes(value) => Ok(EmptyViewImage::_0(value.clone())), // FIXME really expensive clone
+ UiPropertyValue::Number(_) => Err(anyhow!("unexpected type number for ListItemIcon")),
+ UiPropertyValue::Bool(_) => Err(anyhow!("unexpected type bool for ListItemIcon")),
+ UiPropertyValue::Object(_) => Err(anyhow!("unexpected type object for ListItemIcon")),
+ UiPropertyValue::Undefined => Err(anyhow!("unexpected type undefined for ListItemIcon"))
+ }
}
-}
\ No newline at end of file
+}
+
+impl UiPropertyValueToEnum for ImageSource {
+ fn convert(value: &UiPropertyValue) -> anyhow::Result {
+ match value {
+ UiPropertyValue::String(value) => Ok(ImageSource::_1(Icons::from_str(value)?)),
+ UiPropertyValue::Bytes(value) => Ok(ImageSource::_0(value.clone())), // FIXME really expensive clone
+ UiPropertyValue::Number(_) => Err(anyhow!("unexpected type number for ListItemIcon")),
+ UiPropertyValue::Bool(_) => Err(anyhow!("unexpected type bool for ListItemIcon")),
+ UiPropertyValue::Object(_) => Err(anyhow!("unexpected type object for ListItemIcon")),
+ UiPropertyValue::Undefined => Err(anyhow!("unexpected type undefined for ListItemIcon"))
+ }
+ }
+}
diff --git a/rust/component_model/src/lib.rs b/rust/component_model/src/lib.rs
index e6e7ead..50ee102 100644
--- a/rust/component_model/src/lib.rs
+++ b/rust/component_model/src/lib.rs
@@ -82,8 +82,8 @@ pub enum PropertyType {
Function {
arguments: Vec
},
- #[serde(rename = "image_data")]
- ImageData,
+ #[serde(rename = "image_source")]
+ ImageSource,
#[serde(rename = "enum")]
Enum {
name: String
@@ -477,10 +477,6 @@ fn root(children: &[&Component]) -> Component {
].into_iter().map(|s| s.to_string()).collect()
}),
- (
- "ImageSource".to_owned(),
- SharedType::Object { items: IndexMap::from([("data".to_owned(), PropertyType::ImageData)]) }
- )
]),
}
}
@@ -639,7 +635,7 @@ pub fn create_component_model() -> Vec {
mark_doc!("/image/description.md"),
"Image",
[
- property("source", mark_doc!("/image/props/source.md"), false, PropertyType::Object { name: "ImageSource".to_owned() })
+ property("source", mark_doc!("/image/props/source.md"), false, PropertyType::Union { items: vec![PropertyType::ImageSource, PropertyType::Enum { name: "Icons".to_owned() }] })
],
children_none(),
);
@@ -917,7 +913,7 @@ pub fn create_component_model() -> Vec {
[
property("title", mark_doc!("/empty_view/props/title.md"),false, PropertyType::String),
property("description", mark_doc!("/empty_view/props/description.md"),true, PropertyType::String),
- property("image", mark_doc!("/empty_view/props/image.md"),true, PropertyType::Object { name: "ImageSource".to_owned() }),
+ property("image", mark_doc!("/empty_view/props/image.md"),true, PropertyType::Union { items: vec![PropertyType::ImageSource, PropertyType::Enum { name: "Icons".to_owned() }] }),
],
children_none(),
);
@@ -930,7 +926,7 @@ pub fn create_component_model() -> Vec {
property("id", mark_doc!("/list_item/props/id.md"),false, PropertyType::String),
property("title", mark_doc!("/list_item/props/title.md"),false, PropertyType::String),
property("subtitle", mark_doc!("/list_item/props/subtitle.md"),true, PropertyType::String),
- property("icon", mark_doc!("/list_item/props/icon.md"),true, PropertyType::Union { items: vec![PropertyType::Object { name: "ImageSource".to_owned() }, PropertyType::Enum { name: "Icons".to_owned() }] }),
+ property("icon", mark_doc!("/list_item/props/icon.md"),true, PropertyType::Union { items: vec![PropertyType::ImageSource, PropertyType::Enum { name: "Icons".to_owned() }] }),
// accessories
],
children_none(),
diff --git a/rust/server/src/plugins/js/ui.rs b/rust/server/src/plugins/js/ui.rs
index d0597c4..6fe5117 100644
--- a/rust/server/src/plugins/js/ui.rs
+++ b/rust/server/src/plugins/js/ui.rs
@@ -3,8 +3,10 @@ use std::collections::HashMap;
use std::rc::Rc;
use anyhow::{anyhow, Context};
use deno_core::{op, OpState, serde_v8, v8};
+use deno_core::futures::executor::block_on;
use deno_core::v8::{GetPropertyNamesArgs, KeyConversionMode, PropertyFilter};
use indexmap::IndexMap;
+use serde::Deserialize;
use common::model::{EntrypointId, PhysicalKey, UiPropertyValue, UiWidget};
use component_model::{Component, Property, PropertyType, SharedType};
use crate::model::{JsUiRenderLocation, JsUiRequestData, JsUiResponseData, JsUiWidget};
@@ -88,7 +90,7 @@ fn op_react_replace_view(
entrypoint_id: EntrypointId::from_string(entrypoint_id),
render_location,
top_level_view,
- container: from_js_to_intermediate_widget(scope, container, component_model, shared_types)?,
+ container: from_js_to_intermediate_widget(state.clone(), scope, container, component_model, shared_types)?,
};
match make_request(&state, data).context("ReplaceView frontend response")? {
@@ -146,9 +148,9 @@ async fn fetch_action_id_for_shortcut(
Ok(result)
}
-fn from_js_to_intermediate_widget(scope: &mut v8::HandleScope, ui_widget: JsUiWidget, component_model: &ComponentModel, shared_types: &IndexMap) -> anyhow::Result {
+fn from_js_to_intermediate_widget(state: Rc>, scope: &mut v8::HandleScope, ui_widget: JsUiWidget, component_model: &ComponentModel, shared_types: &IndexMap) -> anyhow::Result {
let children = ui_widget.widget_children.into_iter()
- .map(|child| from_js_to_intermediate_widget(scope, child, component_model, shared_types))
+ .map(|child| from_js_to_intermediate_widget(state.clone(), scope, child, component_model, shared_types))
.collect::>>()?;
let component = component_model.components
@@ -167,7 +169,7 @@ fn from_js_to_intermediate_widget(scope: &mut v8::HandleScope, ui_widget: JsUiWi
.map(|prop| (&prop.name, &prop.property_type))
.collect::>();
- let properties = from_js_to_intermediate_properties(scope, ui_widget.widget_properties, &props, shared_types);
+ let properties = from_js_to_intermediate_properties(state.clone(), scope, ui_widget.widget_properties, &props, shared_types);
Ok(UiWidget {
widget_id: ui_widget.widget_id,
@@ -178,6 +180,7 @@ fn from_js_to_intermediate_widget(scope: &mut v8::HandleScope, ui_widget: JsUiWi
}
fn from_js_to_intermediate_properties(
+ state: Rc>,
scope: &mut v8::HandleScope,
v8_properties: HashMap,
component_props: &HashMap<&String, &PropertyType>,
@@ -193,7 +196,7 @@ fn from_js_to_intermediate_properties(
return Err(anyhow!("unknown property encountered {:?}", name))
};
- convert(scope, property_type, name, val, shared_types)
+ convert(state.clone(), scope, property_type, name, val, shared_types)
})
.collect::>>()?;
@@ -201,6 +204,7 @@ fn from_js_to_intermediate_properties(
}
fn convert(
+ state: Rc>,
scope: &mut v8::HandleScope,
property_type: &PropertyType,
name: String,
@@ -235,16 +239,13 @@ fn convert(
PropertyType::Function { .. } => {
panic!("functions are filtered out")
}
- PropertyType::ImageData => {
- if value.is_array() { // TODO arraybuffer? fix when migrating to deno's op2
- convert_bytes(scope, name, value)
- } else {
- invalid_type_err(name, value, property_type)
- }
+ PropertyType::ImageSource => {
+ let source: ImageSource = serde_v8::from_v8(scope, value)?;
+ convert_image_source(state.clone(), name, source)
}
PropertyType::Object { name: object_name } => {
if value.is_object() {
- convert_object(scope, name, value, object_name, shared_types)
+ convert_object(state.clone(), scope, name, value, object_name, shared_types)
} else {
invalid_type_err(name, value, property_type)
}
@@ -265,21 +266,34 @@ fn convert(
None => invalid_type_err(name, value, property_type),
Some(_) => convert_boolean(scope, name, value)
}
- } else if value.is_array() { // TODO arraybuffer? fix when migrating to deno's op2
- match items.iter().find(|prop_type| matches!(prop_type, PropertyType::ImageData)) {
- None => invalid_type_err(name, value, property_type),
- Some(_) => convert_bytes(scope, name, value)
- }
- } else if value.is_object() {
- match items.iter().find(|prop_type| matches!(prop_type, PropertyType::Object { .. })) {
- None => invalid_type_err(name, value, property_type),
- Some(PropertyType::Object { name: object_name }) => {
- convert_object(scope, name, value, object_name, shared_types)
- },
- _ => unreachable!()
- }
} else {
- invalid_type_err(name, value, property_type)
+ if !value.is_object() {
+ invalid_type_err(name, value, property_type)
+ } else {
+ let image_source = items.iter().find(|prop_type| matches!(prop_type, PropertyType::ImageSource));
+ let object = items.iter().find(|prop_type| matches!(prop_type, PropertyType::Object { .. }));
+
+ match (image_source, object) {
+ (Some(PropertyType::ImageSource), Some(PropertyType::Object { .. })) => {
+ panic!("image_source and object is conflicting prop_types")
+ }
+ (None, Some(PropertyType::Object { name: object_name })) => {
+ convert_object(state.clone(), scope, name, value, &object_name, shared_types)
+ }
+ (Some(PropertyType::ImageSource), None) => {
+ println!("test: {}", debug_object_to_json(scope, value.clone()));
+
+ let source: ImageSource = serde_v8::from_v8(scope, value)?;
+ convert_image_source(state.clone(), name, source)
+ }
+ (Some(_), Some(_)) | (Some(_), None) | (None, Some(_)) => {
+ unreachable!()
+ }
+ (None, None) => {
+ invalid_type_err(name, value, property_type)
+ }
+ }
+ }
}
}
}
@@ -297,11 +311,14 @@ fn convert_boolean(scope: &mut v8::HandleScope, name: String, value: v8::Local) -> anyhow::Result<(String, UiPropertyValue)> {
- Ok((name, UiPropertyValue::Bytes(serde_v8::from_v8(scope, value)?)))
-}
-
-fn convert_object(scope: &mut v8::HandleScope, name: String, value: v8::Local, object_name: &str, shared_types: &IndexMap) -> anyhow::Result<(String, UiPropertyValue)> {
+fn convert_object(
+ state: Rc>,
+ scope: &mut v8::HandleScope,
+ name: String,
+ value: v8::Local,
+ object_name: &str,
+ shared_types: &IndexMap
+) -> anyhow::Result<(String, UiPropertyValue)> {
let object: v8::Local = value.try_into().context(format!("error while reading property {}", name))?;
let props = object
@@ -324,7 +341,7 @@ fn convert_object(scope: &mut v8::HandleScope, name: String, value: v8::Local items.get(&key).unwrap()
};
- let (key, value) = convert(scope, property_type, key, value, shared_types)?;
+ let (key, value) = convert(state.clone(), scope, property_type, key, value, shared_types)?;
result_obj.insert(key, value);
}
@@ -347,7 +364,7 @@ fn expected_type(prop_type: &PropertyType) -> String {
PropertyType::Function { .. } => {
panic!("functions are filtered out")
}
- PropertyType::ImageData => "bytearray".to_owned(),
+ PropertyType::ImageSource => "ImageSource".to_owned(),
PropertyType::Enum { .. } => "enum".to_owned(),
PropertyType::Union { items } => {
items.into_iter()
@@ -358,3 +375,65 @@ fn expected_type(prop_type: &PropertyType) -> String {
PropertyType::Object { .. } => "object".to_owned(),
}
}
+
+fn convert_image_source(state: Rc>, name: String, source: ImageSource) -> anyhow::Result<(String, UiPropertyValue)> {
+ match source {
+ ImageSource::Asset { asset } => {
+ let bytes = {
+ let state = state.borrow();
+
+ let plugin_id = state
+ .borrow::()
+ .plugin_id()
+ .clone();
+
+ let repository = state
+ .borrow::()
+ .clone();
+
+ block_on(async {
+ repository.get_asset_data(&plugin_id.to_string(), &asset).await
+ })?
+ };
+
+ Ok((name, UiPropertyValue::Bytes(bytes)))
+ }
+ // ImageSource::Url { url } => { TODO implement url imagesource
+ // Ok((name, UiPropertyValue::Bytes()))
+ // }
+ }
+}
+
+fn debug_object_to_json(
+ scope: &mut v8::HandleScope,
+ val: v8::Local
+) -> String {
+ let local = scope.get_current_context();
+ let global = local.global(scope);
+ let json_string = v8::String::new(scope, "Deno").expect("Unable to create Deno string");
+ let json_object = global.get(scope, json_string.into()).expect("Global Deno object not found");
+ let json_object: v8::Local = json_object.try_into().expect("Deno value is not an object");
+ let inspect_string = v8::String::new(scope, "inspect").expect("Unable to create inspect string");
+ let inspect_object = json_object.get(scope, inspect_string.into()).expect("Unable to get inspect on global Deno object");
+ let stringify_fn: v8::Local = inspect_object.try_into().expect("inspect value is not a function");;
+ let undefined = v8::undefined(scope).into();
+
+ let json_object = stringify_fn.call(scope, undefined, &[val]).expect("Unable to get serialize prop");
+ let json_string: v8::Local = json_object.try_into().expect("result is not a string");
+
+ let result = json_string.to_rust_string_lossy(scope);
+
+ result
+}
+
+
+#[derive(Debug, Deserialize)]
+#[serde(untagged)]
+enum ImageSource {
+ Asset {
+ asset: String
+ },
+ // Url { TODO implement url imagesource
+ // url: String
+ // }
+}
\ No newline at end of file