Add dashboard UI foundation and map export workflow

This commit is contained in:
b0txec
2026-08-18 21:44:09 +03:00
parent 90631a7586
commit bb1d9fc78c
13 changed files with 90 additions and 87 deletions
+11 -8
View File
@@ -21,12 +21,15 @@ export function Cities() {
const [getGranularity, setGranularity] = createSignal("hour");
return (
<div class="aggregator">
<div class="aggregator pageWorkspace">
<div class="pageHeading"><div><span class="eyebrow">Historical observations</span><h1>City analysis</h1><p>Choose stations and a calculation, then compare results or prepare a map graphic.</p></div><div class="selectionCount">{getCities().size} cities selected</div></div>
<div class="container">
<div class="column">
<aside class="column panel cityPanel">
<h2>1. Choose cities</h2>
<SelectCity getCities={getCities} setCities={setCities} />
</div>
<div class="column">
</aside>
<aside class="column panel queryPanel">
<h2>2. Configure query</h2>
<div>
<SelectTimeRange
getStart={getStart}
@@ -43,8 +46,8 @@ export function Cities() {
<SelectKey getKey={getKey} setKey={setKey} />
<SelectGranularity getGranularity={getGranularity} setGranularity={setGranularity} />
</div>
</div>
<div class="column">
</aside>
<section class="column resultsPanel">
<QueryView
getCities={getCities}
getStart={getStart}
@@ -53,8 +56,8 @@ export function Cities() {
getKey={getKey}
getGranularity={getGranularity}
/>
</div>
</section>
</div>
</div>
);
}
}
+4 -5
View File
@@ -21,7 +21,7 @@ export const QueryView: Component<{
const [getTimestamp, setTimestamp] = createSignal<number>(0);
const fetchQuery = async (timestamp: number) => {
if (cities() === "") return new Error("ERROR: Select cities!");
if (cities() === "") return undefined;
await new Promise(resolve => setTimeout(resolve, FETCH_DELAY_MS))
const response = await fetch(`${apiHost}/api/query/city/${cities()}/${queryStart()}-${queryEnd()}/${props.getGranularity()}/${props.getField()}/${props.getKey()}`);
const json = await response.json();
@@ -36,18 +36,17 @@ export const QueryView: Component<{
type="button"
class="primary"
value="Query Data"
disabled={cities() === ""}
onClick={() => setTimestamp(Date.now())}
/>
{ queryResource.loading && <LoadingSpinner text="Loading query" /> }
{ queryResource.error && (
<div>Error while querying: ${queryResource.error}</div>
)}
{ queryResource() && queryResource() instanceof Error &&
<div>{ queryResource().message }</div>
}
{ cities() === "" && <div class="emptyState"><strong>Select at least one city</strong><span>Your results and map options will appear here after you choose cities and run the query.</span></div> }
{ queryResource() && isQueryResult( queryResource() ) &&
<ResultView result={queryResource} />
}
</div>
);
}
}
+3 -3
View File
@@ -9,6 +9,7 @@ import { GridResult } from "./GridResult";
type ResultView = "grid" | "list" | "map_1920x1080" | "map_1920x1080_wind" | "map_3840x1440" | "map_3840x1440_wind";
const resultViews: Array<ResultView> = ["grid", "list", "map_1920x1080", "map_1920x1080_wind", "map_3840x1440", "map_3840x1440_wind"];
const viewLabels: Record<ResultView,string> = {grid:'Cards',list:'List',map_1920x1080:'HD map',map_1920x1080_wind:'HD map + wind',map_3840x1440:'Ultrawide map',map_3840x1440_wind:'Ultrawide + wind'}
export const ResultView: Component<{
result: Resource<QueryResult>
@@ -40,11 +41,10 @@ export const ResultView: Component<{
<input
type="button"
class="secondary"
value={viewName}
value={viewLabels[viewName]}
disabled={!showViewButton(viewName)}
onClick={() => setResultView(viewName)}
/>
&nbsp; | &nbsp;
</>
)}
</span>
@@ -88,4 +88,4 @@ export const ResultView: Component<{
</div>
</div>
);
}
}