Implement instance tree visualization

This commit is contained in:
Lucien Greathouse
2019-09-24 16:46:19 -07:00
parent e8a5e44319
commit 7a1eda98ca
3 changed files with 130 additions and 14 deletions

View File

@@ -11,22 +11,29 @@
html { html {
box-sizing: border-box; box-sizing: border-box;
font-family: sans-serif; font-family: sans-serif;
font-size: 18px;
text-decoration: none; text-decoration: none;
height: 100%; height: 100%;
} }
body { body {
height: 100%; min-height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
} }
img {
max-width:100%;
max-height:100%;
height: auto;
}
.root { .root {
flex: 0 0; flex: 0 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin: 0 auto; margin: 0.5rem auto;
width: 100%; width: 100%;
max-width: 50rem; max-width: 50rem;
background-color: #efefef; background-color: #efefef;
@@ -48,8 +55,7 @@ body {
} }
.main-logo { .main-logo {
flex: 0 0; flex: 0 0 10rem;
width: 10rem;
margin: 1rem; margin: 1rem;
} }
@@ -71,7 +77,8 @@ body {
flex: 0 0; flex: 0 0;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: space-around;
margin: -1rem;
} }
.button { .button {
@@ -80,3 +87,24 @@ body {
padding: 0.3em 1em; padding: 0.3em 1em;
margin: 1rem; margin: 1rem;
} }
.instance {
border: 1px solid #666;
border-right-style: none;
border-bottom-style: none;
background-color: #fff;
margin-bottom: 0.5rem;
}
.instance-title {
font-size: 1.5rem;
padding: 0.5rem;
}
.instance-properties {
padding: 0.5rem;
}
.instance-children {
padding: 0.5rem 0 0.5rem 1rem;
}

View File

@@ -1,5 +1,3 @@
use std::{fs, path::Path};
static LOGO: &[u8] = include_bytes!("../../assets/logo-512.png"); static LOGO: &[u8] = include_bytes!("../../assets/logo-512.png");
static ICON: &[u8] = include_bytes!("../../assets/icon-32.png"); static ICON: &[u8] = include_bytes!("../../assets/icon-32.png");
static HOME_CSS: &str = include_str!("../../assets/index.css"); static HOME_CSS: &str = include_str!("../../assets/index.css");
@@ -8,12 +6,14 @@ macro_rules! declare_asset {
($name: ident, $path: expr) => { ($name: ident, $path: expr) => {
pub fn $name() -> &'static str { pub fn $name() -> &'static str {
if cfg!(feature = "dev-live-assets") { if cfg!(feature = "dev-live-assets") {
use std::{fs::read_to_string, path::Path};
let file_path = Path::new(file!()); let file_path = Path::new(file!());
let asset_path = file_path.parent().unwrap().join($path); let asset_path = file_path.parent().unwrap().join($path);
println!("Reloading {}", asset_path.display()); println!("Reloading {}", asset_path.display());
let content = fs::read_to_string(asset_path) let content = read_to_string(asset_path)
.expect("Couldn't read dev live asset") .expect("Couldn't read dev live asset")
.into_boxed_str(); .into_boxed_str();

View File

@@ -4,11 +4,13 @@ use std::{sync::Arc, time::Duration};
use futures::{future, Future}; use futures::{future, Future};
use hyper::{header, service::Service, Body, Method, Request, Response, StatusCode}; use hyper::{header, service::Service, Body, Method, Request, Response, StatusCode};
use ritz::{html, HtmlContent}; use rbx_dom_weak::{RbxId, RbxValue};
use ritz::{html, Fragment, HtmlContent};
use crate::{ use crate::{
imfs::ImfsFetcher, imfs::ImfsFetcher,
serve_session::ServeSession, serve_session::ServeSession,
snapshot::RojoTree,
web::{ web::{
assets, assets,
interface::{ErrorResponse, SERVER_VERSION}, interface::{ErrorResponse, SERVER_VERSION},
@@ -80,19 +82,103 @@ impl<F: ImfsFetcher> UiService<F> {
} }
fn handle_show_instances(&self) -> Response<Body> { fn handle_show_instances(&self) -> Response<Body> {
let tree = self.serve_session.tree();
let root_id = tree.get_root_id();
let page = self.normal_page(html! {
{ Self::instance(&tree, root_id) }
});
Response::builder() Response::builder()
.header(header::CONTENT_TYPE, "text/plain") .header(header::CONTENT_TYPE, "text/html")
.body(Body::from("TODO: /show-instances")) .body(Body::from(format!("<!DOCTYPE html>{}", page)))
.unwrap() .unwrap()
} }
fn handle_show_imfs(&self) -> Response<Body> { fn handle_show_imfs(&self) -> Response<Body> {
let page = self.normal_page(html! {
"TODO /show/imfs"
});
Response::builder() Response::builder()
.header(header::CONTENT_TYPE, "text/plain") .header(header::CONTENT_TYPE, "text/html")
.body(Body::from("TODO: /show-imfs")) .body(Body::from(format!("<!DOCTYPE html>{}", page)))
.unwrap() .unwrap()
} }
fn instance(tree: &RojoTree, id: RbxId) -> HtmlContent<'_> {
let instance = tree.get_instance(id).unwrap();
let children_list: Vec<_> = instance
.children()
.iter()
.copied()
.map(|id| Self::instance(tree, id))
.collect();
let children_container = if children_list.is_empty() {
HtmlContent::None
} else {
html! {
<div class="instance-children">
{ Fragment::new(children_list) }
</div>
}
};
let mut properties: Vec<_> = instance.properties().iter().collect();
properties.sort_by_key(|pair| pair.0);
let property_list: Vec<_> = properties
.into_iter()
.map(|(key, value)| {
html! {
<div class="instance-property" title={ Self::display_value(value) }>
{ key.clone() } ": " { format!("{:?}", value.get_type()) }
</div>
}
})
.collect();
let property_container = if property_list.is_empty() {
HtmlContent::None
} else {
html! {
<div class="instance-properties">
{ Fragment::new(property_list) }
</div>
}
};
let class_name_specifier = if instance.name() == instance.class_name() {
HtmlContent::None
} else {
html! {
<span>
" (" { instance.class_name().to_owned() } ")"
</span>
}
};
html! {
<div class="instance">
<div class="instance-title">
{ instance.name().to_owned() }
{ class_name_specifier }
</div>
{ property_container }
{ children_container }
</div>
}
}
fn display_value(value: &RbxValue) -> String {
match value {
RbxValue::String { value } => value.clone(),
RbxValue::Bool { value } => value.to_string(),
_ => format!("{:?}", value),
}
}
fn stat_item<S: Into<String>>(name: &str, value: S) -> HtmlContent<'_> { fn stat_item<S: Into<String>>(name: &str, value: S) -> HtmlContent<'_> {
html! { html! {
<span class="stat"> <span class="stat">
@@ -124,7 +210,9 @@ impl<F: ImfsFetcher> UiService<F> {
Self::page(html! { Self::page(html! {
<div class="root"> <div class="root">
<header class="header"> <header class="header">
<img class="main-logo" src="/logo.png" /> <a class="main-logo" href="/">
<img src="/logo.png" />
</a>
<div class="stats"> <div class="stats">
{ Self::stat_item("Server Version", SERVER_VERSION) } { Self::stat_item("Server Version", SERVER_VERSION) }
{ Self::stat_item("Project", project_name) } { Self::stat_item("Project", project_name) }