data is being loaded into preact SPA
This commit is contained in:
parent
a0436f8c87
commit
d7baadec6c
|
@ -211,6 +211,8 @@ dependencies = [
|
|||
"libsqlite3-sys",
|
||||
"rocket",
|
||||
"rocket_contrib",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -978,6 +980,20 @@ name = "serde"
|
|||
version = "1.0.114"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "serde_json"
|
||||
|
|
|
@ -13,4 +13,6 @@ anyhow = "1.0"
|
|||
chrono = "0.4"
|
||||
diesel = { version = "1.4.5", features = ["sqlite"] }
|
||||
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 Home from "../routes/home";
|
||||
import Profile from "../routes/profile";
|
||||
import Dataset from "../routes/dataset";
|
||||
import NotFoundPage from '../routes/notfound';
|
||||
import Header from "./header";
|
||||
|
||||
|
@ -23,8 +23,7 @@ const App: FunctionalComponent = () => {
|
|||
<Header />
|
||||
<Router onChange={handleRoute}>
|
||||
<Route path="/" component={Home} />
|
||||
<Route path="/profile/" component={Profile} user="me" />
|
||||
<Route path="/profile/:user" component={Profile} />
|
||||
<Route path="/view/:name" component={Dataset} />
|
||||
<NotFoundPage default />
|
||||
</Router>
|
||||
</div>
|
||||
|
|
|
@ -5,17 +5,11 @@ import * as style from "./style.css";
|
|||
const Header: FunctionalComponent = () => {
|
||||
return (
|
||||
<header class={style.header}>
|
||||
<h1>Preact App</h1>
|
||||
<h1>datalog viewer thing</h1>
|
||||
<nav>
|
||||
<Link activeClassName={style.active} href="/">
|
||||
Home
|
||||
</Link>
|
||||
<Link activeClassName={style.active} href="/profile">
|
||||
Me
|
||||
</Link>
|
||||
<Link activeClassName={style.active} href="/profile/john">
|
||||
John
|
||||
</Link>
|
||||
</nav>
|
||||
</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";
|
||||
|
||||
const Home: FunctionalComponent = () => {
|
||||
return (
|
||||
<div class={style.home}>
|
||||
<h1>Home</h1>
|
||||
<p>This is the Home component.</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export interface HomeProps {
|
||||
|
||||
}
|
||||
|
||||
export interface HomeState {
|
||||
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;
|
||||
|
|
|
@ -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]
|
||||
extern crate anyhow;
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
|
||||
extern crate chrono;
|
||||
|
||||
pub mod models;
|
||||
|
@ -81,6 +84,27 @@ fn log_get(device_name: &RawStr, conn: DbConn) -> Result<String, anyhow::Error>
|
|||
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)]
|
||||
fn not_found() -> Option<NamedFile> {
|
||||
NamedFile::open("frontend/build/index.html").ok()
|
||||
|
@ -93,7 +117,7 @@ fn main() {
|
|||
"/",
|
||||
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])
|
||||
.launch();
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::schema::events;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Queryable, Debug)]
|
||||
#[derive(Queryable, Debug, Serialize)]
|
||||
pub struct Event {
|
||||
pub id: i32,
|
||||
pub devicename: String,
|
||||
|
|
Loading…
Reference in New Issue