Fixes and proper box settings

This commit is contained in:
Jan Zípek 2022-08-24 09:31:10 +02:00
parent 8bff4d083e
commit ec690ebbcb
Signed by: kamen
GPG Key ID: A17882625B33AC31
5 changed files with 99 additions and 42 deletions

View File

@ -1,4 +1,5 @@
import { getSensorValues } from '@/api/sensorValues' import { getSensorValues } from '@/api/sensorValues'
import { DashboardGraphData } from '@/utils/parseDashboard'
import { useEffect, useRef } from 'preact/hooks' import { useEffect, useRef } from 'preact/hooks'
import { useQuery } from 'react-query' import { useQuery } from 'react-query'
import { useDashboardContext } from '../contexts/DashboardContext' import { useDashboardContext } from '../contexts/DashboardContext'
@ -6,9 +7,10 @@ import { BoxDefinition } from '../types'
type Props = { type Props = {
box: BoxDefinition box: BoxDefinition
data: DashboardGraphData
} }
export const BoxGraphContent = ({ box }: Props) => { export const BoxGraphContent = ({ box, data }: Props) => {
const { filter } = useDashboardContext() const { filter } = useDashboardContext()
const bodyRef = useRef<HTMLDivElement>(null) const bodyRef = useRef<HTMLDivElement>(null)
@ -27,8 +29,8 @@ export const BoxGraphContent = ({ box }: Props) => {
// TODO: These should be probably returned by server, could be outdated // TODO: These should be probably returned by server, could be outdated
const from = filter.customFrom const from = filter.customFrom
const to = filter.customTo const to = filter.customTo
const minValue = parseFloat(box.min ?? '') const minValue = parseFloat(data.min ?? '')
const maxValue = parseFloat(box.max ?? '') const maxValue = parseFloat(data.max ?? '')
const customRange = !isNaN(minValue) && !isNaN(maxValue) const customRange = !isNaN(minValue) && !isNaN(maxValue)
if (bodyRef.current && values.data) { if (bodyRef.current && values.data) {
@ -36,19 +38,19 @@ export const BoxGraphContent = ({ box }: Props) => {
bodyRef.current, bodyRef.current,
[ [
{ {
...(box.graphType === 'line' && { ...(data.graphType === 'line' && {
type: 'scatter', type: 'scatter',
mode: 'lines', mode: 'lines',
}), }),
...(box.graphType === 'points' && { ...(data.graphType === 'points' && {
type: 'scatter', type: 'scatter',
mode: 'markers', mode: 'markers',
}), }),
...(box.graphType === 'lineAndPoints' && { ...(data.graphType === 'lineAndPoints' && {
type: 'scatter', type: 'scatter',
mode: 'lines+markers', mode: 'lines+markers',
}), }),
...(box.graphType === 'bar' && { type: 'bar' }), ...(data.graphType === 'bar' && { type: 'bar' }),
x: values.data.map((v) => new Date(v.timestamp * 1000)), x: values.data.map((v) => new Date(v.timestamp * 1000)),
y: values.data.map((v) => v.value), y: values.data.map((v) => v.value),
line: { line: {
@ -60,7 +62,7 @@ export const BoxGraphContent = ({ box }: Props) => {
xaxis: { range: [from, to], type: 'date' }, xaxis: { range: [from, to], type: 'date' },
yaxis: { yaxis: {
...(customRange && { range: [minValue, maxValue] }), ...(customRange && { range: [minValue, maxValue] }),
...(box.unit && { ticksuffix: ` ${box.unit}` }), ...(data.unit && { ticksuffix: ` ${data.unit}` }),
}, },
margin: { margin: {
l: 70, l: 70,
@ -76,7 +78,7 @@ export const BoxGraphContent = ({ box }: Props) => {
} }
) )
} }
}, [values.data, box]) }, [values.data, box, data])
return <div ref={bodyRef} /> return <div ref={bodyRef} />
} }

View File

@ -1,7 +1,8 @@
import { getSensors } from '@/api/sensors' import { getSensors } from '@/api/sensors'
import { useState } from 'preact/hooks' import { useState } from 'preact/hooks'
import { useQuery } from 'react-query' import { useQuery } from 'react-query'
import { BoxDefinition } from '../types' import { BoxDefinition } from '../../types'
import { GraphSettings } from './components/GraphSettings'
type Props = { type Props = {
value: BoxDefinition value: BoxDefinition
@ -15,12 +16,11 @@ export const BoxSettings = ({ value, onSave, onClose }: Props) => {
const [formState, setFormState] = useState(() => ({ const [formState, setFormState] = useState(() => ({
sensor: value.sensor, sensor: value.sensor,
title: value.title, title: value.title,
min: value.min, type: value.data?.type ?? 'graph',
max: value.max,
graphType: value.graphType,
unit: value.unit,
})) }))
const [data, setData] = useState(() => value.data)
const handleSave = async (e: Event) => { const handleSave = async (e: Event) => {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
@ -29,7 +29,9 @@ export const BoxSettings = ({ value, onSave, onClose }: Props) => {
onSave({ onSave({
...value, ...value,
...formState, sensor: formState.sensor,
title: formState.title,
data: data,
}) })
} }
@ -81,33 +83,17 @@ export const BoxSettings = ({ value, onSave, onClose }: Props) => {
<div className="input"> <div className="input">
<label>Type</label> <label>Type</label>
<select <select
name="graphType" name="type"
value={formState.graphType || 'line'} value={formState.type}
onChange={handleChange} onChange={handleChange}
> >
<option value="line">Line</option> <option value="graph">Graph</option>
<option value="points">Points</option>
<option value="lineAndPoints">Line + Points</option>
<option value="bar">Bar</option>
</select> </select>
</div> </div>
<div className="input"> {formState.type === 'graph' && (
<label>Unit</label> <GraphSettings value={data} onChange={setData} />
<input )}
name="unit"
value={formState.unit}
onChange={handleChange}
/>
</div>
<div className="input">
<label>Min value</label>
<input name="min" value={formState.min} onChange={handleChange} />
</div>
<div className="input">
<label>Max value</label>
<input name="max" value={formState.max} onChange={handleChange} />
</div>
<div className="actions"> <div className="actions">
<button className="cancel" onClick={onClose} type="button"> <button className="cancel" onClick={onClose} type="button">

View File

@ -0,0 +1,60 @@
import { DashboardGraphData } from '@/utils/parseDashboard'
import { useEffect, useState } from 'preact/hooks'
type Props = {
value?: DashboardGraphData
onChange: (data: DashboardGraphData) => void
}
export const GraphSettings = ({ value, onChange }: Props) => {
const [formState, setFormState] = useState(() => ({
min: value?.min,
max: value?.max,
graphType: value?.graphType,
unit: value?.unit,
}))
const handleChange = (e: Event) => {
const target = e.target as HTMLSelectElement | HTMLInputElement
setFormState({
...formState,
[target.name]: target.value,
})
}
useEffect(() => {
onChange({ ...formState, type: 'graph' })
}, [formState])
return (
<>
<div className="input">
<label>Graph Type</label>
<select
name="graphType"
value={formState.graphType || 'line'}
onChange={handleChange}
>
<option value="line">Line</option>
<option value="points">Points</option>
<option value="lineAndPoints">Line + Points</option>
<option value="bar">Bar</option>
</select>
</div>
<div className="input">
<label>Unit</label>
<input name="unit" value={formState.unit} onChange={handleChange} />
</div>
<div className="input">
<label>Min value</label>
<input name="min" value={formState.min} onChange={handleChange} />
</div>
<div className="input">
<label>Max value</label>
<input name="max" value={formState.max} onChange={handleChange} />
</div>
</>
)
}

View File

@ -1,12 +1,11 @@
import { getElementPosition } from '@/utils/getElementPosition'
import { useWindowEvent } from '@/utils/hooks/useWindowEvent' import { useWindowEvent } from '@/utils/hooks/useWindowEvent'
import { useRef, useState } from 'preact/hooks' import { useRef, useState } from 'preact/hooks'
import { GRID_WIDTH } from '../constants' import { GRID_WIDTH } from '../constants'
import { ResizingMode, useResize } from '../hooks/useResize'
import { useDragging } from '../hooks/useDragging' import { useDragging } from '../hooks/useDragging'
import { ResizingMode, useResize } from '../hooks/useResize'
import { BoxDefinition } from '../types' import { BoxDefinition } from '../types'
import { BoxSettings } from './BoxSettings'
import { BoxGraphContent } from './BoxGraphContent' import { BoxGraphContent } from './BoxGraphContent'
import { BoxSettings } from './BoxSettings/BoxSettings'
type Props = { type Props = {
box: BoxDefinition box: BoxDefinition
@ -46,7 +45,10 @@ export const EditableBox = ({
e.preventDefault() e.preventDefault()
if (!dragging.active && boxRef.current) { if (!dragging.active && boxRef.current) {
const pos = getElementPosition(boxRef.current) const pos = {
top: boxRef.current.offsetTop,
left: boxRef.current.offsetLeft,
}
setDragging({ setDragging({
active: true, active: true,
@ -115,7 +117,9 @@ export const EditableBox = ({
</div> </div>
</div> </div>
<div className="body"> <div className="body">
{box.sensor && <BoxGraphContent box={box} />} {box.sensor && box.data?.type === 'graph' && (
<BoxGraphContent box={box} data={box.data} />
)}
</div> </div>
<div <div

View File

@ -11,6 +11,11 @@ export type DashboardContentBox = {
h: number h: number
sensor?: string sensor?: string
title?: string title?: string
data?: DashboardGraphData
}
export type DashboardGraphData = {
type: 'graph'
min?: string min?: string
max?: string max?: string
unit?: string unit?: string