Added support for dial box
This commit is contained in:
parent
39b7d5e73a
commit
009332dccf
|
|
@ -19,3 +19,16 @@ export const getSensorValues = ({
|
|||
from.getTime() / 1000
|
||||
)}&to=${Math.round(to.getTime() / 1000)}`
|
||||
)
|
||||
|
||||
export const getLatestSensorValue = ({
|
||||
to,
|
||||
sensor,
|
||||
}: {
|
||||
to: Date
|
||||
sensor: string
|
||||
}) =>
|
||||
request<SensorValue>(
|
||||
`/api/sensors/${encodeURI(sensor)}/values/latest?to=${Math.round(
|
||||
to.getTime() / 1000
|
||||
)}`
|
||||
)
|
||||
|
|
|
|||
|
|
@ -214,6 +214,8 @@ form.horizontal .input label {
|
|||
|
||||
.grid-sensors .grid-box .box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.grid-sensors .grid-box .box .resize-h {
|
||||
|
|
@ -245,6 +247,8 @@ form.horizontal .input label {
|
|||
|
||||
.grid-sensors .grid-box .box .header {
|
||||
display: flex;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.grid-sensors .grid-box .box .header .drag-handle {
|
||||
|
|
@ -256,6 +260,19 @@ form.horizontal .input label {
|
|||
margin-left: auto;
|
||||
}
|
||||
|
||||
.grid-sensors .grid-box .box .body {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.grid-sensors .grid-box .box .dial {
|
||||
text-align: center;
|
||||
font-size: 150%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.grid-sensors .box-preview {
|
||||
position: absolute;
|
||||
background-color: #3988FF;
|
||||
|
|
|
|||
|
|
@ -59,8 +59,7 @@ export const NewDashboardPage = () => {
|
|||
return b
|
||||
})
|
||||
|
||||
setBoxes([box, ...otherBoxes])
|
||||
// TODO: Save
|
||||
handleChange(() => [box, ...otherBoxes])
|
||||
}
|
||||
|
||||
// Terrible code - ensure there's default dashboard
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
import { getLatestSensorValue } from '@/api/sensorValues'
|
||||
import { DashboardDialData } from '@/utils/parseDashboard'
|
||||
import { useQuery } from 'react-query'
|
||||
import { useDashboardContext } from '../contexts/DashboardContext'
|
||||
import { BoxDefinition } from '../types'
|
||||
|
||||
type Props = {
|
||||
box: BoxDefinition
|
||||
data: DashboardDialData
|
||||
}
|
||||
|
||||
export const BoxDialContent = ({ box, data }: Props) => {
|
||||
const { filter } = useDashboardContext()
|
||||
|
||||
const valuesQuery = {
|
||||
sensor: box.sensor ?? '-1',
|
||||
to: filter.customTo,
|
||||
}
|
||||
|
||||
const value = useQuery(['/sensor/values/latest', valuesQuery], () =>
|
||||
getLatestSensorValue(valuesQuery)
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="dial">
|
||||
{value.data && (
|
||||
<>
|
||||
{value.data.value}
|
||||
{data.unit}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
import { getSensors } from '@/api/sensors'
|
||||
import { DashboardDialData, DashboardGraphData } from '@/utils/parseDashboard'
|
||||
import { useState } from 'preact/hooks'
|
||||
import { useQuery } from 'react-query'
|
||||
import { BoxDefinition } from '../../types'
|
||||
import { DialSettings } from './components/DialSettings'
|
||||
import { GraphSettings } from './components/GraphSettings'
|
||||
|
||||
type Props = {
|
||||
|
|
@ -88,11 +90,22 @@ export const BoxSettings = ({ value, onSave, onClose }: Props) => {
|
|||
onChange={handleChange}
|
||||
>
|
||||
<option value="graph">Graph</option>
|
||||
<option value="dial">Dial</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{formState.type === 'graph' && (
|
||||
<GraphSettings value={data} onChange={setData} />
|
||||
<GraphSettings
|
||||
value={data as DashboardGraphData}
|
||||
onChange={setData}
|
||||
/>
|
||||
)}
|
||||
|
||||
{formState.type === 'dial' && (
|
||||
<DialSettings
|
||||
value={data as DashboardDialData}
|
||||
onChange={setData}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="actions">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
import { DashboardDialData } from '@/utils/parseDashboard'
|
||||
import { useEffect, useState } from 'preact/hooks'
|
||||
|
||||
type Props = {
|
||||
value?: DashboardDialData
|
||||
onChange: (data: DashboardDialData) => void
|
||||
}
|
||||
|
||||
export const DialSettings = ({ value, onChange }: Props) => {
|
||||
const [formState, setFormState] = useState(() => ({ unit: value?.unit }))
|
||||
|
||||
const handleChange = (e: Event) => {
|
||||
const target = e.target as HTMLSelectElement | HTMLInputElement
|
||||
|
||||
setFormState({
|
||||
...formState,
|
||||
[target.name]: target.value,
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
onChange({ ...formState, type: 'dial' })
|
||||
}, [formState])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="input">
|
||||
<label>Unit</label>
|
||||
<input name="unit" value={formState.unit} onChange={handleChange} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import { useDashboardContext } from '../contexts/DashboardContext'
|
|||
import { useDragging } from '../hooks/useDragging'
|
||||
import { ResizingMode, useResize } from '../hooks/useResize'
|
||||
import { BoxDefinition } from '../types'
|
||||
import { BoxDialContent } from './BoxDialContent'
|
||||
import { BoxGraphContent } from './BoxGraphContent'
|
||||
import { BoxSettings } from './BoxSettings/BoxSettings'
|
||||
|
||||
|
|
@ -129,6 +130,9 @@ export const EditableBox = ({
|
|||
{box.sensor && box.data?.type === 'graph' && (
|
||||
<BoxGraphContent box={box} data={box.data} />
|
||||
)}
|
||||
{box.sensor && box.data?.type === 'dial' && (
|
||||
<BoxDialContent box={box} data={box.data} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export const useDragging = ({ cellWidth, boxes, box }: Props) => {
|
|||
Math.min(GRID_WIDTH - box.w, Math.round(state.x / cellWidth))
|
||||
)
|
||||
|
||||
const dragY = Math.round(state.y / GRID_H_SNAP) * GRID_H_SNAP
|
||||
const dragY = Math.max(0, Math.round(state.y / GRID_H_SNAP) * GRID_H_SNAP)
|
||||
|
||||
const gridHeights = Array(GRID_WIDTH)
|
||||
.fill(null)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export type DashboardContentBox = {
|
|||
h: number
|
||||
sensor?: string
|
||||
title?: string
|
||||
data?: DashboardGraphData
|
||||
data?: DashboardGraphData | DashboardDialData
|
||||
}
|
||||
|
||||
export type DashboardGraphData = {
|
||||
|
|
@ -22,6 +22,11 @@ export type DashboardGraphData = {
|
|||
graphType?: string
|
||||
}
|
||||
|
||||
export type DashboardDialData = {
|
||||
type: 'dial'
|
||||
unit?: string
|
||||
}
|
||||
|
||||
export const parseDashboard = (input: string) => {
|
||||
return JSON.parse(input) as DashboardContent
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,15 @@ type postSensorValueBody struct {
|
|||
Value float64 `json:"value"`
|
||||
}
|
||||
|
||||
type getSensorQuery struct {
|
||||
type getSensorValuesQuery struct {
|
||||
From int64 `form:"from"`
|
||||
To int64 `form:"to"`
|
||||
}
|
||||
|
||||
type getLatestSensorValueQuery struct {
|
||||
To int64 `form:"to"`
|
||||
}
|
||||
|
||||
func PostSensorValues(s *app.Server) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var newValue postSensorValueBody
|
||||
|
|
@ -37,7 +41,7 @@ func PostSensorValues(s *app.Server) gin.HandlerFunc {
|
|||
|
||||
func GetSensorValues(s *app.Server) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var query getSensorQuery
|
||||
var query getSensorValuesQuery
|
||||
|
||||
sensor := c.Param("sensor")
|
||||
|
||||
|
|
@ -58,7 +62,7 @@ func GetSensorValues(s *app.Server) gin.HandlerFunc {
|
|||
|
||||
func GetSensorLatestValue(s *app.Server) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var query getSensorQuery
|
||||
var query getLatestSensorValueQuery
|
||||
|
||||
sensor := c.Param("sensor")
|
||||
|
||||
|
|
@ -67,7 +71,7 @@ func GetSensorLatestValue(s *app.Server) gin.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
value, err := s.Services.SensorValues.GetLatest(sensor, query.From, query.To)
|
||||
value, err := s.Services.SensorValues.GetLatest(sensor, query.To)
|
||||
|
||||
if err != nil {
|
||||
c.AbortWithError(500, err)
|
||||
|
|
|
|||
|
|
@ -51,10 +51,10 @@ func (s *SensorValuesService) GetList(sensor string, from int64, to int64) ([]se
|
|||
return values, nil
|
||||
}
|
||||
|
||||
func (s *SensorValuesService) GetLatest(sensor string, from int64, to int64) (*sensorValue, error) {
|
||||
func (s *SensorValuesService) GetLatest(sensor string, to int64) (*sensorValue, error) {
|
||||
var value = sensorValue{}
|
||||
|
||||
row := s.ctx.DB.QueryRow("SELECT timestamp, value FROM sensor_values WHERE sensor = ? AND timestamp > ? AND timestamp < ? ORDER BY timestamp DESC LIMIT 1", sensor, from, to)
|
||||
row := s.ctx.DB.QueryRow("SELECT timestamp, value FROM sensor_values WHERE sensor = ? timestamp < ? ORDER BY timestamp DESC LIMIT 1", sensor, to)
|
||||
|
||||
err := row.Scan(&value.Timestamp, &value.Value)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Reference in New Issue