add Python server backend
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2024-05-11 14:06:39 +02:00
parent 14d63294a3
commit cd3afa4d61
22 changed files with 1896 additions and 119 deletions

78
src/api.d.ts vendored Normal file
View File

@@ -0,0 +1,78 @@
/**
* This file was auto-generated by openapi-typescript.
* Do not make direct changes to the file.
*/
export interface paths {
"/type/{type}/startDate/{start_date}/endDate/{end_date}/sample/{sample}": {
/** Get Sensor Data */
get: operations["get_sensor_data_type__type__startDate__start_date__endDate__end_date__sample__sample__get"];
};
}
export type webhooks = Record<string, never>;
export interface components {
schemas: {
/** Document */
Document: {
/** Date */
date: number;
/** Value */
value: number;
};
/** HTTPValidationError */
HTTPValidationError: {
/** Detail */
detail?: components["schemas"]["ValidationError"][];
};
/** ValidationError */
ValidationError: {
/** Location */
loc: (string | number)[];
/** Message */
msg: string;
/** Error Type */
type: string;
};
};
responses: never;
parameters: never;
requestBodies: never;
headers: never;
pathItems: never;
}
export type $defs = Record<string, never>;
export type external = Record<string, never>;
export interface operations {
/** Get Sensor Data */
get_sensor_data_type__type__startDate__start_date__endDate__end_date__sample__sample__get: {
parameters: {
path: {
type: "temperature" | "humidity";
start_date: number;
end_date: number;
sample: number;
};
};
responses: {
/** @description Successful Response */
200: {
content: {
"application/json": components["schemas"]["Document"][];
};
};
/** @description Validation Error */
422: {
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
}

View File

@@ -1,18 +1,17 @@
<template>
<div class="chart-container">
<Loader v-if="loading"></Loader>
<Loader v-if="isLoading"></Loader>
<div class="chart" id="chart" ref="chart" v-else></div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { ref, watch } from 'vue'
import * as Highcharts from 'highcharts'
import 'highcharts/css/highcharts.scss'
import Loader from '@/components/Loader.vue'
import { capitalizeFirstLetter } from '@/utils/helpers'
import type { Window, NavType } from '@/utils/types'
import { typeApi } from '@/utils/types'
import { useFetch } from '@vueuse/core'
import type { Window, NavTypes } from '@/utils/types'
import { useApi } from '@/composables/api'
Highcharts.setOptions({
time: {
@@ -22,26 +21,12 @@ Highcharts.setOptions({
const props = defineProps<{
activeWindow: Window
activeType: NavType | undefined
activeType: NavTypes | undefined
}>()
const chart = ref<HTMLElement | null>(null)
const fetchUrl = computed(() => {
const [start, end] = [props.activeWindow.getStart(), props.activeWindow.getEnd()]
const sample = Math.round((end - start) / 60 / 288) || 1
const host = import.meta.env.MODE === 'development' ? 'http://localhost:3000' : ''
const fetchUrl = `${host}/type/${
typeApi[props.activeType || 'temperatuur']
}/startDate/${start}/endDate/${end}/sample/${sample}`
return fetchUrl
})
interface ChartDataPoint {
date: Number
value: Number
}
const { data: chartData, isFetching: loading } = useFetch(fetchUrl, { refetch: true }).json<ChartDataPoint[]>()
const { chartData, isLoading } = useApi(props)
watch([chart, chartData], () => {
if (chart.value && chartData.value) renderChart()

View File

@@ -15,11 +15,13 @@ import NavBar from '@/components/NavBar.vue'
import TimeWindows from '@/components/TimeWindows.vue'
import Chart from '@/components/Chart.vue'
import { windows } from '@/utils/helpers'
import type { Window, NavType } from '@/utils/types'
import type { Window, NavTypes } from '@/utils/types'
import { navTypes } from '@/utils/types'
const defaultWindow = windows[1]
const defaultType = navTypes[0]
const activeType = ref<NavType>()
const activeType = ref<NavTypes>()
const activeWindow = ref<Window>(defaultWindow)
const router = useRouter()
@@ -27,9 +29,10 @@ const route = useRoute()
const urlEncodeWindow = (label: string) => label.replace(' ', '-')
if (route.params.type) activeType.value = route.params.type as NavType
if (route.params.type)
// activeType.value = (navTypes.includes(route.params.type.toString()) ? route.params.type : navTypes[0]) as NavTypes
activeType.value = (navTypes.find((t) => t === route.params.type) || defaultType) as NavTypes
if (route.params.window) {
console.log(route.params.window, windows)
activeWindow.value = windows.find((w) => urlEncodeWindow(w.label) === route.params.window) || defaultWindow
}

View File

@@ -34,17 +34,17 @@
<script setup lang="ts">
import { capitalizeFirstLetter } from '@/utils/helpers'
import { ref } from 'vue'
import type { NavType } from '@/utils/types'
import type { NavTypes } from '@/utils/types'
const activeType = defineModel<NavType>()
const activeType = defineModel<NavTypes>()
const setType = (type: NavType) => {
const setType = (type: NavTypes) => {
toggled.value = false
activeType.value = type
}
const toggled = ref(false)
const navTypes: NavType[] = ['temperatuur', 'luchtvochtigheid']
const navTypes: NavTypes[] = ['temperatuur', 'luchtvochtigheid']
if (!activeType.value) setType(navTypes[0])
const toggleMenu = () => (toggled.value = !toggled.value)
</script>

56
src/composables/api.ts Normal file
View File

@@ -0,0 +1,56 @@
import createClient from 'openapi-fetch'
import { navTypeToApiTypeMapping } from '@/utils/types'
import type { Window, NavTypes } from '@/utils/types'
import { computed, ref, watch } from 'vue'
import type { paths } from '@/api'
type Props = {
activeWindow: Window
activeType: NavTypes | undefined
}
type ApiParameters =
paths['/type/{type}/startDate/{start_date}/endDate/{end_date}/sample/{sample}']['get']['parameters']['path']
type ApiResponse =
paths['/type/{type}/startDate/{start_date}/endDate/{end_date}/sample/{sample}']['get']['responses']['200']['content']['application/json']
type ApiError =
paths['/type/{type}/startDate/{start_date}/endDate/{end_date}/sample/{sample}']['get']['responses']['422']['content']['application/json']
export function useApi(props: Props) {
const client = createClient<paths>({ baseUrl: import.meta.env.MODE === 'development' ? 'http://localhost:3000' : '' })
const chartData = ref<ApiResponse | null>(null)
const chartError = ref<ApiError | null>(null)
const isLoading = ref(false)
const apiParameters = computed<ApiParameters>(() => {
const [start_date, end_date] = [props.activeWindow.getStart(), props.activeWindow.getEnd()]
return {
type: navTypeToApiTypeMapping[props.activeType || 'temperatuur'],
start_date,
end_date,
sample: Math.round((start_date - end_date) / 60 / 288) || 1
}
})
const getData = async () => {
isLoading.value = true
const { data } = await client.GET('/type/{type}/startDate/{start_date}/endDate/{end_date}/sample/{sample}', {
params: { path: apiParameters.value }
})
if (data) chartData.value = data
isLoading.value = false
}
watch([() => [props.activeType, props.activeWindow]], () => getData(), { immediate: true })
return {
chartData,
chartError,
isLoading
}
}

View File

@@ -1,3 +1,5 @@
import type { paths } from '@/api'
export interface Window {
label: string
getStart: { (): number }
@@ -6,9 +8,18 @@ export interface Window {
interval: number
}
export const typeApi = {
export type ApiTypes =
paths['/type/{type}/startDate/{start_date}/endDate/{end_date}/sample/{sample}']['get']['parameters']['path']['type']
export type NavTypes = 'temperatuur' | 'luchtvochtigheid'
type NavTypeToApiTypeMapping = {
[key in NavTypes]: ApiTypes
}
export const navTypeToApiTypeMapping: NavTypeToApiTypeMapping = {
temperatuur: 'temperature',
luchtvochtigheid: 'humidity'
}
export type NavType = keyof typeof typeApi
export const navTypes = Object.keys(navTypeToApiTypeMapping)