mirror of
				https://github.com/KevinMidboe/brewPi.git
				synced 2025-10-29 16:50:12 +00:00 
			
		
		
		
	Feat/prerender and state (#8)
* pre-load data behind link elements on hover * Enable SSR and prerendering of pages in 'auto' mode * merge relay & regulator state in /api/state This helps when updating relays and receiving state of relays and regulator state (idle, heating or cooling) after emitting relay change.
This commit is contained in:
		| @@ -20,7 +20,7 @@ const routes: Array<IRoute> = [{ | ||||
|  | ||||
| <ul class="navigation-cards" on:click> | ||||
|   {#each routes as route} | ||||
|     <a href={route.path}> | ||||
|     <a href={route.path} data-sveltekit-preload-data="hover"> | ||||
|       <li> | ||||
|         <span>{ route.name }</span> | ||||
|  | ||||
|   | ||||
| @@ -7,13 +7,13 @@ | ||||
|   export let relays: IRelaysDTO[] = []; | ||||
|   const dispatch = createEventDispatcher(); | ||||
|  | ||||
|   function toggleRelay(controls: string) { | ||||
|   async function toggleRelay(controls: string) { | ||||
|     const url = `/api/relay/${controls}`; | ||||
|     const options = { | ||||
|       method: 'POST' | ||||
|     }; | ||||
|  | ||||
|     fetch(url, options) | ||||
|     await fetch(url, options) | ||||
|       .then((resp) => resp.json()) | ||||
|       .then((response) => { | ||||
|         const changedRelay = relays.findIndex((relay) => relay.pin === response.pin); | ||||
|   | ||||
							
								
								
									
										16
									
								
								src/routes/+layout.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/routes/+layout.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| // if you want to generate a static html file | ||||
| // for your page. | ||||
| // Documentation: https://kit.svelte.dev/docs/page-options#prerender | ||||
| export const prerender = 'auto'; | ||||
|  | ||||
| // if you want to Generate a SPA | ||||
| // you have to set ssr to false. | ||||
| // This is not the case (so set as true or comment the line) | ||||
| // Documentation: https://kit.svelte.dev/docs/page-options#ssr | ||||
| export const ssr = true; | ||||
|  | ||||
| // How to manage the trailing slashes in the URLs | ||||
| // the URL for about page witll be /about with 'ignore' (default) | ||||
| // the URL for about page witll be /about/ with 'always' | ||||
| // https://kit.svelte.dev/docs/page-options#trailingslash | ||||
| export const trailingSlash = 'ignore'; | ||||
| @@ -1,28 +1,51 @@ | ||||
| import { BREWLOGGER_HOST } from '$env/static/private'; | ||||
| import type { PageServerLoad } from './$types'; | ||||
| import type { ISensorDTO } from '../lib/interfaces/ISensorDTO' | ||||
| import type { PageServerLoad, RequestEvent } from './$types'; | ||||
| import type { ISensorDTO } from '../lib/interfaces/ISensorDTO'; | ||||
| import { IRelaysDTO } from '../lib/interfaces/IRelaysDTO'; | ||||
| import { IStateDTO } from '../lib/interfaces/IStateDTO'; | ||||
|  | ||||
| const sensorsUrl = `${BREWLOGGER_HOST}/api/sensors`; | ||||
| const relaysUrl = `${BREWLOGGER_HOST}/api/relays`; | ||||
| const stateUrl = `${BREWLOGGER_HOST}/api/regulator`; | ||||
| export const prerender = true; // explicitly pre-render | ||||
|  | ||||
| async function getFromEndpoint(endpoint: string)  { | ||||
|   return fetch(endpoint) | ||||
| async function fetchSensors(fetch: Fetch): Promise<ISensorDTO[]> { | ||||
|   return fetch(sensorsUrl) | ||||
|     .then((resp) => resp.json()) | ||||
|     .then((data) => data?.sensors || []) | ||||
|     .catch((error) => { | ||||
|       console.error('Failed to fetch endpoint:', endpoint); | ||||
|       console.error('failed to fetch sensors.'); | ||||
|       console.error(error); | ||||
|       return null | ||||
|       return null; | ||||
|     }); | ||||
| } | ||||
|  | ||||
| export const load: PageServerLoad = async () => { | ||||
|   const [sensorsResp, relaysResp, stateResp] = await Promise.all([getFromEndpoint(sensorsUrl), getFromEndpoint(relaysUrl), getFromEndpoint(stateUrl)]); | ||||
|   const sensors: ISensorDTO[] = sensorsResp?.sensors || [] | ||||
|   const relays: IRelaysDTO[] = relaysResp?.relays || [] | ||||
|   const state: IStateDTO = stateResp | ||||
| // calls internal sveltekit api endpoint. | ||||
| // this allows unified response in svelte app, even | ||||
| // though it requires multiple calls to regulator server | ||||
| async function fetchState(fetch: Fetch) { | ||||
|   return fetch('/api/state') | ||||
|     .then((resp) => resp.json()) | ||||
|     .catch((error) => { | ||||
|       console.error('failed to fetch state'); | ||||
|       console.error(error); | ||||
|       return null; | ||||
|     }); | ||||
| } | ||||
|  | ||||
| type Fetch = typeof fetch; | ||||
| type HandleFetch = { | ||||
|   event: RequestEvent; | ||||
|   request: Request; | ||||
|   fetch: Fetch; | ||||
| }; | ||||
|  | ||||
| export const load: PageServerLoad = async (input: HandleFetch) => { | ||||
|   const [stateResponse, sensorsResponse] = await Promise.all([ | ||||
|     fetchState(input.fetch), | ||||
|     fetchSensors(input.fetch) | ||||
|   ]); | ||||
|   const sensors: ISensorDTO[] = sensorsResponse || []; | ||||
|   const relays: IRelaysDTO[] = stateResponse?.relays || []; | ||||
|   const regulator: IStateDTO = stateResponse?.regulator; | ||||
|  | ||||
|   const inside = sensors.find((sensor: ISensorDTO) => sensor.location === 'inside'); | ||||
|   const outside = sensors.find((sensor: ISensorDTO) => sensor.location === 'outside'); | ||||
| @@ -30,7 +53,6 @@ export const load: PageServerLoad = async () => { | ||||
|   return { | ||||
|     inside: inside || null, | ||||
|     outside: outside || null, | ||||
|     relays, | ||||
|     state | ||||
|     state: { regulator, relays } | ||||
|   }; | ||||
| }; | ||||
|   | ||||
| @@ -8,14 +8,13 @@ | ||||
|  | ||||
|   export let data: PageData; | ||||
|   const { inside, outside } = data; | ||||
|   let { relays, state } = data; | ||||
|   let { relays, regulator } = data.state; | ||||
|  | ||||
|   const updateState = () => | ||||
|     setTimeout(() => { | ||||
|       fetch('/api/state') | ||||
|         .then((resp) => resp.json()) | ||||
|         .then((response: IStateDTO) => (state = response)); | ||||
|     }, 100); | ||||
|   const updateState = () => { | ||||
|     fetch('/api/state') | ||||
|       .then((resp) => resp.json()) | ||||
|       .then((response: IStateDTO) => ({ relays, regulator } = response)); | ||||
|     } | ||||
| </script> | ||||
|  | ||||
| <Logo /> | ||||
| @@ -23,7 +22,12 @@ | ||||
| <div class="vertical-grid"> | ||||
|   <BrewProgress /> | ||||
|  | ||||
|   <VerticalSensorDisplay {inside} {outside} {relays} {state} /> | ||||
|   <VerticalSensorDisplay | ||||
|     inside="{inside}" | ||||
|     outside="{outside}" | ||||
|     relays="{relays}" | ||||
|     state="{regulator}" | ||||
|   /> | ||||
|  | ||||
|   <RelayControls bind:relays="{relays}" on:relaySwitched="{updateState}" /> | ||||
| </div> | ||||
|   | ||||
| @@ -1,9 +1,19 @@ | ||||
| import { json, RequestEvent } from '@sveltejs/kit'; | ||||
| import { BREWLOGGER_HOST } from '$env/static/private'; | ||||
| import type { RequestHandler } from './$types'; | ||||
| import { IRelaysDTO } from '../../../lib/interfaces/IRelaysDTO'; | ||||
|  | ||||
| export const GET = (async (event: RequestEvent) => { | ||||
|   return fetch(BREWLOGGER_HOST + '/api/regulator') | ||||
| async function fetchRegulator(): Promise<Response | IRelaysDTO[]> { | ||||
|   return fetch(BREWLOGGER_HOST + '/api/regulator').then((resp) => resp.json()); | ||||
| } | ||||
|  | ||||
| async function fetchRelays(): Promise<Response | IRelaysDTO[]> { | ||||
|   return fetch(BREWLOGGER_HOST + '/api/relays') | ||||
|     .then((resp) => resp.json()) | ||||
|     .then((response) => json(response)); | ||||
|     .then((data) => data?.relays || []); | ||||
| } | ||||
|  | ||||
| export const GET = (async () => { | ||||
|   const [regulatorState, relaysState] = await Promise.all([fetchRegulator(), fetchRelays()]); | ||||
|   return json({ regulator: regulatorState, relays: relaysState }); | ||||
| }) satisfies RequestHandler; | ||||
|   | ||||
| @@ -17,7 +17,7 @@ | ||||
|   <ul> | ||||
|     {#each brews as brew} | ||||
|     <li class="brew"> | ||||
|       <a href="{path(brew.date)}"> | ||||
|       <a href="{path(brew.date)}" data-sveltekit-preload-data="hover"> | ||||
|         <img src="/images/{brew.image}" alt="Beer label of {brew.beer.name}" /> | ||||
|  | ||||
|         <div class="details"> | ||||
|   | ||||
| @@ -4,8 +4,9 @@ import { fetchHumidity, fetchTemperature } from '../../../lib/server/graphQueryG | ||||
| import type { PageLoad } from './$types'; | ||||
|  | ||||
| async function fetchGraphData(brew) { | ||||
|   const start = new Date(brew.date * 1000 - 86400000); | ||||
|   const end = new Date(brew.date * 1000 + 4838400000); | ||||
|   const { date } = brew; | ||||
|   const start = new Date(date * 1000 - 86400000); | ||||
|   const end = new Date(date * 1000 + 4838400000); | ||||
|   const size = 200; | ||||
|  | ||||
|   const [temperature, humidity] = await Promise.all([ | ||||
| @@ -13,10 +14,7 @@ async function fetchGraphData(brew) { | ||||
|     fetchHumidity(start, end, size) | ||||
|   ]); | ||||
|  | ||||
|   return { | ||||
|     temperature, | ||||
|     humidity | ||||
|   }; | ||||
|   return { temperature, humidity }; | ||||
| } | ||||
|  | ||||
| export const load = (async ({ params }) => { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user