Implement aggregation frontend, also http on prod
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import { createSignal } from "solid-js";
|
||||
import { Result } from "./Result";
|
||||
import { SelectAggregator } from "./SelectAggregator";
|
||||
import { SelectCity } from "./SelectCity";
|
||||
import { SelectTimeRange } from "./SelectTimeRange";
|
||||
|
||||
const dayAgoMs = Date.now() - 24 * 60 * 60 * 1000;
|
||||
|
||||
export function Aggregator() {
|
||||
const [getCities, setCities] = createSignal<Set<string>>(new Set([]));
|
||||
const [getStart, setStart] = createSignal(new Date(dayAgoMs));
|
||||
const [getEnd, setEnd] = createSignal(new Date());
|
||||
const [getField, setField] = createSignal("tempMax");
|
||||
const [getKey, setKey] = createSignal("max");
|
||||
|
||||
return (
|
||||
<div class="aggregator">
|
||||
<h2>Aggregator</h2>
|
||||
<div class="container">
|
||||
<div class="column">
|
||||
<SelectCity getCities={getCities} setCities={setCities} />
|
||||
</div>
|
||||
<div class="column">
|
||||
<div>
|
||||
<SelectTimeRange
|
||||
getStart={getStart}
|
||||
setStart={setStart}
|
||||
getEnd={getEnd}
|
||||
setEnd={setEnd}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<SelectAggregator
|
||||
getField={getField}
|
||||
setField={setField}
|
||||
getKey={getKey}
|
||||
setKey={setKey}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<Result
|
||||
getCities={getCities}
|
||||
getStart={getStart}
|
||||
getEnd={getEnd}
|
||||
getField={getField}
|
||||
getKey={getKey}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import moment from "moment";
|
||||
import { Accessor, Component, createResource, createSignal } from "solid-js";
|
||||
import { apiHost } from "../consts";
|
||||
|
||||
export const Result: Component<{
|
||||
getCities: Accessor<Set<string>>,
|
||||
getStart: Accessor<Date>,
|
||||
getEnd: Accessor<Date>,
|
||||
getField: Accessor<string>,
|
||||
getKey: Accessor<string>,
|
||||
}> = (props) => {
|
||||
const cities = () => [...props.getCities()].join(",")
|
||||
const startStr = () => moment(props.getStart()).format("YYYY/MM/DD, HH:mm");
|
||||
const endStr = () => moment(props.getEnd()).format("YYYY/MM/DD, HH:mm");
|
||||
const queryStart = () => moment(props.getStart()).format("YYYYMMDD_HHmm");
|
||||
const queryEnd = () => moment(props.getEnd()).format("YYYYMMDD_HHmm");
|
||||
const [getTimestamp, setTimestamp] = createSignal<number>(0);
|
||||
|
||||
const fetchQuery = async (timestamp: number) => {
|
||||
console.log("query:", new Date(timestamp));
|
||||
if (cities() === "") return "ERROR: Select cities!";
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
const response = await fetch(`${apiHost}/api/query/${queryStart()}-${queryEnd()}/${cities()}/${props.getField()}/${props.getKey()}`);
|
||||
const json = await response.json();
|
||||
return json;
|
||||
}
|
||||
|
||||
const [queryResource] = createResource(getTimestamp, fetchQuery);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3>Aggregate by:</h3>
|
||||
<input type="button" value="Query Data" onClick={() => setTimestamp(Date.now())} />
|
||||
<p>cities: { cities() }</p>
|
||||
<p>time range: { startStr() } - { endStr() }</p>
|
||||
<p>weather field: { props.getField() }</p>
|
||||
<p>aggregation field: { props.getKey() }</p>
|
||||
<h3>Result:</h3>
|
||||
<p>
|
||||
{ queryResource.loading && (
|
||||
<div>
|
||||
<span class="spinner"></span>
|
||||
<span style={{ "padding-left": "16px" }}>Loading query</span>
|
||||
</div>
|
||||
)}
|
||||
{ queryResource.error && (
|
||||
<div>Error while querying: ${queryResource.error}</div>
|
||||
)}
|
||||
{ queryResource() && (
|
||||
<span>{JSON.stringify(queryResource())}</span>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Accessor, Component, Setter } from "solid-js";
|
||||
import { aggregateKey, weatherField } from "../consts";
|
||||
|
||||
export const SelectAggregator: Component<{
|
||||
getField: Accessor<string>,
|
||||
setField: Setter<string>,
|
||||
getKey: Accessor<string>,
|
||||
setKey: Setter<string>,
|
||||
}> = (props) => {
|
||||
return (
|
||||
<div>
|
||||
<h3>Select aggregator</h3>
|
||||
<select onChange={(e) => props.setField(e.target.value)}>
|
||||
{ weatherField.map(field =>
|
||||
<option
|
||||
value={field}
|
||||
selected={field === props.getField() ? true : false}
|
||||
>{field}</option>
|
||||
)}
|
||||
</select>
|
||||
<ul>
|
||||
{ aggregateKey.map(key =>
|
||||
<label><li><input
|
||||
type="checkbox"
|
||||
name="aggregateKey"
|
||||
value={key}
|
||||
checked={key === props.getKey() ? true : false}
|
||||
onClick={() => props.setKey(key)}
|
||||
/>{key}</li></label>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Accessor, Component, Setter } from "solid-js";
|
||||
import { cityList } from "../consts";
|
||||
|
||||
export const SelectCity: Component<{
|
||||
getCities: Accessor<Set<string>>,
|
||||
setCities: Setter<Set<string>>,
|
||||
}> = (props) => {
|
||||
function handleSelect(e: MouseEvent) {
|
||||
if (!e.target) return;
|
||||
const target = e.target as HTMLInputElement;
|
||||
const { checked: selected, value: city } = target;
|
||||
const cityList = new Set([...props.getCities()]);
|
||||
if (selected) cityList.add(city);
|
||||
else cityList.delete(city);
|
||||
|
||||
props.setCities(cityList);
|
||||
}
|
||||
|
||||
return (
|
||||
<ul>{cityList.map(city =>
|
||||
<label>
|
||||
<li>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="city"
|
||||
value={city}
|
||||
onClick={handleSelect}
|
||||
/>
|
||||
{city}
|
||||
</li>
|
||||
</label>
|
||||
)}</ul>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
import moment from 'moment';
|
||||
import { Accessor, Component, Setter } from "solid-js";
|
||||
|
||||
export const SelectTimeRange: Component<{
|
||||
getStart: Accessor<Date>,
|
||||
setStart: Setter<Date>,
|
||||
getEnd: Accessor<Date>,
|
||||
setEnd: Setter<Date>,
|
||||
}> = (props) => {
|
||||
const startStr = () => moment(props.getStart()).format("YYYY-MM-DDTHH:mm");
|
||||
const endStr = () => moment(props.getEnd()).format("YYYY-MM-DDTHH:mm");
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3>Select time range</h3>
|
||||
<p>
|
||||
<input
|
||||
type="datetime-local"
|
||||
value={startStr()}
|
||||
onChange={e => props.setStart(new Date(e.target.value))}
|
||||
/> start
|
||||
</p>
|
||||
<p>
|
||||
<input
|
||||
type="datetime-local"
|
||||
value={endStr()}
|
||||
onChange={e => props.setEnd(new Date(e.target.value))}
|
||||
/> end
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user