data is being loaded into preact SPA
This commit is contained in:
parent
a0436f8c87
commit
d7baadec6c
|
@ -211,6 +211,8 @@ dependencies = [
|
||||||
"libsqlite3-sys",
|
"libsqlite3-sys",
|
||||||
"rocket",
|
"rocket",
|
||||||
"rocket_contrib",
|
"rocket_contrib",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -978,6 +980,20 @@ name = "serde"
|
||||||
version = "1.0.114"
|
version = "1.0.114"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3"
|
checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.114"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.18",
|
||||||
|
"quote 1.0.7",
|
||||||
|
"syn 1.0.34",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
|
|
|
@ -13,4 +13,6 @@ anyhow = "1.0"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
diesel = { version = "1.4.5", features = ["sqlite"] }
|
diesel = { version = "1.4.5", features = ["sqlite"] }
|
||||||
dotenv = "0.15.0"
|
dotenv = "0.15.0"
|
||||||
libsqlite3-sys = { version = "0.18.0", features = ["bundled"] }
|
libsqlite3-sys = { version = "0.18.0", features = ["bundled"] }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
File diff suppressed because one or more lines are too long
|
@ -2,7 +2,7 @@ import { FunctionalComponent, h } from "preact";
|
||||||
import { Route, Router, RouterOnChangeArgs } from "preact-router";
|
import { Route, Router, RouterOnChangeArgs } from "preact-router";
|
||||||
|
|
||||||
import Home from "../routes/home";
|
import Home from "../routes/home";
|
||||||
import Profile from "../routes/profile";
|
import Dataset from "../routes/dataset";
|
||||||
import NotFoundPage from '../routes/notfound';
|
import NotFoundPage from '../routes/notfound';
|
||||||
import Header from "./header";
|
import Header from "./header";
|
||||||
|
|
||||||
|
@ -23,8 +23,7 @@ const App: FunctionalComponent = () => {
|
||||||
<Header />
|
<Header />
|
||||||
<Router onChange={handleRoute}>
|
<Router onChange={handleRoute}>
|
||||||
<Route path="/" component={Home} />
|
<Route path="/" component={Home} />
|
||||||
<Route path="/profile/" component={Profile} user="me" />
|
<Route path="/view/:name" component={Dataset} />
|
||||||
<Route path="/profile/:user" component={Profile} />
|
|
||||||
<NotFoundPage default />
|
<NotFoundPage default />
|
||||||
</Router>
|
</Router>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,17 +5,11 @@ import * as style from "./style.css";
|
||||||
const Header: FunctionalComponent = () => {
|
const Header: FunctionalComponent = () => {
|
||||||
return (
|
return (
|
||||||
<header class={style.header}>
|
<header class={style.header}>
|
||||||
<h1>Preact App</h1>
|
<h1>datalog viewer thing</h1>
|
||||||
<nav>
|
<nav>
|
||||||
<Link activeClassName={style.active} href="/">
|
<Link activeClassName={style.active} href="/">
|
||||||
Home
|
Home
|
||||||
</Link>
|
</Link>
|
||||||
<Link activeClassName={style.active} href="/profile">
|
|
||||||
Me
|
|
||||||
</Link>
|
|
||||||
<Link activeClassName={style.active} href="/profile/john">
|
|
||||||
John
|
|
||||||
</Link>
|
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { Component, h } from "preact";
|
||||||
|
import { useEffect, useState } from "preact/hooks";
|
||||||
|
import * as style from "./style.css";
|
||||||
|
|
||||||
|
export interface DatasetProps {
|
||||||
|
name: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Datapoint {
|
||||||
|
id: number,
|
||||||
|
devicename: string,
|
||||||
|
value: number,
|
||||||
|
timestamp: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DatasetState {
|
||||||
|
data: Datapoint[],
|
||||||
|
}
|
||||||
|
|
||||||
|
class Dataset extends Component<DatasetProps, DatasetState> {
|
||||||
|
constructor(){
|
||||||
|
super();
|
||||||
|
this.state = { data: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
var devicesResponse = await fetch(`/api/device/${this.props.name}`);
|
||||||
|
this.setState({ data: await devicesResponse.json() as Datapoint[] })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lifecycle: Called just before our component will be destroyed
|
||||||
|
componentWillUnmount() {
|
||||||
|
// stop when not renderable
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
var deviceLinks = this.state.data.map((d) => <div>{d.devicename},{d.value},{d.timestamp}</div>)
|
||||||
|
return <div class={style.profile}>{this.props.name}<span>{deviceLinks}</span></div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Dataset;
|
|
@ -1,13 +1,35 @@
|
||||||
import { FunctionalComponent, h } from "preact";
|
import { Component, h } from "preact";
|
||||||
|
import { Link } from "preact-router/match";
|
||||||
import * as style from "./style.css";
|
import * as style from "./style.css";
|
||||||
|
|
||||||
const Home: FunctionalComponent = () => {
|
export interface HomeProps {
|
||||||
return (
|
|
||||||
<div class={style.home}>
|
}
|
||||||
<h1>Home</h1>
|
|
||||||
<p>This is the Home component.</p>
|
export interface HomeState {
|
||||||
</div>
|
devices: string[],
|
||||||
);
|
}
|
||||||
};
|
|
||||||
|
class Home extends Component<HomeProps, HomeState> {
|
||||||
|
constructor(){
|
||||||
|
super();
|
||||||
|
this.state = { devices: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
var devicesResponse = await fetch('/api/devices');
|
||||||
|
this.setState({ devices: await devicesResponse.json() as string[] })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lifecycle: Called just before our component will be destroyed
|
||||||
|
componentWillUnmount() {
|
||||||
|
// stop when not renderable
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
var deviceLinks = this.state.devices.map((d) => <div><Link href={`/view/${d}`}>{d}</Link></div>)
|
||||||
|
return <div class={style.home}><span>{deviceLinks}</span></div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default Home;
|
export default Home;
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
import { FunctionalComponent, h } from "preact";
|
|
||||||
import { useEffect, useState } from "preact/hooks";
|
|
||||||
import * as style from "./style.css";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
user: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Profile: FunctionalComponent<Props> = (props: Props) => {
|
|
||||||
const { user } = props;
|
|
||||||
const [time, setTime] = useState<number>(Date.now());
|
|
||||||
const [count, setCount] = useState<number>(0);
|
|
||||||
|
|
||||||
// gets called when this route is navigated to
|
|
||||||
useEffect(() => {
|
|
||||||
const timer = window.setInterval(() => setTime(Date.now()), 1000);
|
|
||||||
|
|
||||||
// gets called just before navigating away from the route
|
|
||||||
return () => {
|
|
||||||
clearInterval(timer);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// update the current time
|
|
||||||
const increment = () => {
|
|
||||||
setCount(count + 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class={style.profile}>
|
|
||||||
<h1>Profile: {user}</h1>
|
|
||||||
<p>This is the user profile for a user named {user}.</p>
|
|
||||||
|
|
||||||
<div>Current time: {new Date(time).toLocaleString()}</div>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<button onClick={increment}>Click Me</button> Clicked {count}{" "}
|
|
||||||
times.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Profile;
|
|
26
src/main.rs
26
src/main.rs
|
@ -9,6 +9,9 @@ extern crate rocket_contrib;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate anyhow;
|
extern crate anyhow;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde;
|
||||||
|
|
||||||
extern crate chrono;
|
extern crate chrono;
|
||||||
|
|
||||||
pub mod models;
|
pub mod models;
|
||||||
|
@ -81,6 +84,27 @@ fn log_get(device_name: &RawStr, conn: DbConn) -> Result<String, anyhow::Error>
|
||||||
Ok(lines)
|
Ok(lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("/devices")]
|
||||||
|
fn devices_get(conn: DbConn) -> Result<String, anyhow::Error> {
|
||||||
|
use self::schema::events::dsl::*;
|
||||||
|
let devices = events
|
||||||
|
.select(devicename)
|
||||||
|
.distinct()
|
||||||
|
.load::<String>(&*conn)?;
|
||||||
|
|
||||||
|
Ok(serde_json::to_string(&devices)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/device/<name>")]
|
||||||
|
fn device_get(name: &RawStr, conn: DbConn) -> Result<String, anyhow::Error> {
|
||||||
|
use self::schema::events::dsl::*;
|
||||||
|
let results = events
|
||||||
|
.filter(devicename.eq(name.as_str()))
|
||||||
|
.load::<Event>(&*conn)?;
|
||||||
|
|
||||||
|
Ok(serde_json::to_string(&results)?)
|
||||||
|
}
|
||||||
|
|
||||||
#[catch(404)]
|
#[catch(404)]
|
||||||
fn not_found() -> Option<NamedFile> {
|
fn not_found() -> Option<NamedFile> {
|
||||||
NamedFile::open("frontend/build/index.html").ok()
|
NamedFile::open("frontend/build/index.html").ok()
|
||||||
|
@ -93,7 +117,7 @@ fn main() {
|
||||||
"/",
|
"/",
|
||||||
rocket_contrib::serve::StaticFiles::from("frontend/build"),
|
rocket_contrib::serve::StaticFiles::from("frontend/build"),
|
||||||
)
|
)
|
||||||
.mount("/api", routes![log_new, log_get])
|
.mount("/api", routes![log_new, log_get, devices_get, device_get])
|
||||||
.register(catchers![not_found])
|
.register(catchers![not_found])
|
||||||
.launch();
|
.launch();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use super::schema::events;
|
use super::schema::events;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
#[derive(Queryable, Debug)]
|
#[derive(Queryable, Debug, Serialize)]
|
||||||
pub struct Event {
|
pub struct Event {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub devicename: String,
|
pub devicename: String,
|
||||||
|
|
Loading…
Reference in New Issue