diff --git a/client/src/assets/components/_grid-sensors.scss b/client/src/assets/components/_grid-sensors.scss index 8ca5cfa..557d6ee 100644 --- a/client/src/assets/components/_grid-sensors.scss +++ b/client/src/assets/components/_grid-sensors.scss @@ -33,14 +33,14 @@ display: flex; align-items: center; justify-content: center; - left: 0; right: 0; - top: 0; bottom: 0; background-color: var(--box-loader-bg-color); color: var(--box-loader-fg-color); - font-size: 300%; + font-size: 125%; + padding: 0.25rem; z-index: 2; + border-top-left-radius: var(--border-radius); .svg-icon { animation-name: grid-loader-rotate; diff --git a/client/src/assets/themes/_basic.scss b/client/src/assets/themes/_basic.scss index daa1fd6..281d5f1 100644 --- a/client/src/assets/themes/_basic.scss +++ b/client/src/assets/themes/_basic.scss @@ -24,8 +24,8 @@ --box-bg-color: #fff; --box-fg-color: #111; --box-border-color: #ddd; - --box-loader-bg-color: rgba(128, 128, 128, 0.3); - --box-loader-fg-color: #fff; + --box-loader-bg-color: rgba(128, 128, 128, 0.1); + --box-loader-fg-color: #666; --box-action-fg-color: #666; --box-preview-bg-color: #3988ff; --box-shadow: 0px 10px 15px -3px rgba(0, 0, 0, 0.1); diff --git a/client/src/pages/dashboard/components/DashboardGrid/DashboardGrid.tsx b/client/src/pages/dashboard/components/DashboardGrid/DashboardGrid.tsx index 0c192a3..15e5ebf 100644 --- a/client/src/pages/dashboard/components/DashboardGrid/DashboardGrid.tsx +++ b/client/src/pages/dashboard/components/DashboardGrid/DashboardGrid.tsx @@ -1,6 +1,6 @@ import { useDashboardContext } from '../../contexts/DashboardContext' import { normalizeBoxes } from '../../utils/normalizeBoxes' -import { EditableBox } from './components/EditableBox' +import { GeneralBox } from './components/GeneralBox' export const DashboardGrid = () => { const { isDashboardSelected, boxes, setBoxes } = useDashboardContext() @@ -9,7 +9,7 @@ export const DashboardGrid = () => {
{boxes.map((b) => ( - { diff --git a/client/src/pages/dashboard/components/DashboardGrid/components/BoxDialContent.tsx b/client/src/pages/dashboard/components/DashboardGrid/components/BoxDialContent.tsx index 211f885..6f1ac14 100644 --- a/client/src/pages/dashboard/components/DashboardGrid/components/BoxDialContent.tsx +++ b/client/src/pages/dashboard/components/DashboardGrid/components/BoxDialContent.tsx @@ -1,25 +1,26 @@ import { getLatestSensorValue } from '@/api/sensorValues' import { DashboardDialData } from '@/utils/dashboard/parseDashboard' -import { RefObject } from 'preact' import { useMemo } from 'preact/hooks' import { useQuery } from 'react-query' import { useDashboardContext } from '../../../contexts/DashboardContext' -import { BoxDefinition } from '../../../types' import { BoxLoader } from './BoxLoader' +import { EditableBox, EditableBoxProps } from './EditableBox' +import { useDelayedState } from '@/utils/hooks/useDelayedState' -type Props = { - box: BoxDefinition +type Props = EditableBoxProps & { data: DashboardDialData - refreshRef: RefObject<() => void> } -export const BoxDialContent = ({ data, refreshRef }: Props) => { +export const BoxDialContent = ({ data, ...editableBoxProps }: Props) => { const { filter } = useDashboardContext() - const valuesQuery = { - sensor: data.sensor ?? '-1', - to: filter.customTo, - } + const valuesQuery = useMemo( + () => ({ + sensor: data.sensor ?? '-1', + to: filter.customTo, + }), + [data.sensor, filter.customTo] + ) const value = useQuery( ['/sensor/values/latest', valuesQuery], @@ -27,9 +28,7 @@ export const BoxDialContent = ({ data, refreshRef }: Props) => { { enabled: !!data.sensor } ) - refreshRef.current = () => { - value.refetch() - } + const showFetchLoading = useDelayedState(value.isLoading, 500) const displayValue = useMemo(() => { if (!value.data) { @@ -49,16 +48,18 @@ export const BoxDialContent = ({ data, refreshRef }: Props) => { }, [value.data, data]) return ( - <> - {value.isFetching && } -
- {value.data && ( - <> - {displayValue} - {data.unit && ` ${data.unit}`} - - )} -
- + value.refetch()}> + <> + {showFetchLoading && } +
+ {value.data && ( + <> + {displayValue} + {data.unit && ` ${data.unit}`} + + )} +
+ +
) } diff --git a/client/src/pages/dashboard/components/DashboardGrid/components/BoxGraphContent.tsx b/client/src/pages/dashboard/components/DashboardGrid/components/BoxGraphContent.tsx index 7c99831..de0b064 100644 --- a/client/src/pages/dashboard/components/DashboardGrid/components/BoxGraphContent.tsx +++ b/client/src/pages/dashboard/components/DashboardGrid/components/BoxGraphContent.tsx @@ -1,21 +1,20 @@ import { getSensorValues } from '@/api/sensorValues' import { useDashboardContext } from '@/pages/dashboard/contexts/DashboardContext' -import { BoxDefinition } from '@/pages/dashboard/types' import { DashboardGraphData } from '@/utils/dashboard/parseDashboard' import { max } from '@/utils/max' import { min } from '@/utils/min' -import { RefObject } from 'preact' import { useEffect, useRef } from 'preact/hooks' import { useQuery } from 'react-query' import { BoxLoader } from './BoxLoader' +import { EditableBox, EditableBoxProps } from './EditableBox' +import { useDelayedState } from '@/utils/hooks/useDelayedState' -type Props = { - box: BoxDefinition +type Props = EditableBoxProps & { data: DashboardGraphData - refreshRef: RefObject<() => void> } -export const BoxGraphContent = ({ box, data, refreshRef }: Props) => { +export const BoxGraphContent = ({ data, ...editableBoxProps }: Props) => { + const box = editableBoxProps.box const { filter } = useDashboardContext() const bodyRef = useRef(null) @@ -32,9 +31,7 @@ export const BoxGraphContent = ({ box, data, refreshRef }: Props) => { { enabled: !!data.sensor } ) - refreshRef.current = () => { - values.refetch() - } + const showFetchLoading = useDelayedState(values.isLoading, 500) useEffect(() => { if (bodyRef.current && values.data) { @@ -137,9 +134,9 @@ export const BoxGraphContent = ({ box, data, refreshRef }: Props) => { }, [values.data, box, data]) return ( - <> - {values.isFetching && } + values.refetch()}> + {showFetchLoading && }
- + ) } diff --git a/client/src/pages/dashboard/components/DashboardGrid/components/EditableBox.tsx b/client/src/pages/dashboard/components/DashboardGrid/components/EditableBox.tsx index f70e0d6..a89bd65 100644 --- a/client/src/pages/dashboard/components/DashboardGrid/components/EditableBox.tsx +++ b/client/src/pages/dashboard/components/DashboardGrid/components/EditableBox.tsx @@ -1,17 +1,16 @@ -import { useWindowEvent } from '@/utils/hooks/useWindowEvent' -import { useRef, useState } from 'preact/hooks' -import { BoxDialContent } from './BoxDialContent' -import { BoxGraphContent } from './BoxGraphContent' -import { useElementOffsets } from '@/utils/hooks/useElementOffsets' import { RefreshIcon, SettingsIcon } from '@/icons' -import { BoxDefinition } from '@/pages/dashboard/types' import { GRID_WIDTH } from '@/pages/dashboard/constants' import { useDashboardContext } from '@/pages/dashboard/contexts/DashboardContext' import { useDragging } from '@/pages/dashboard/hooks/useDragging' -import { useResize, ResizingMode } from '@/pages/dashboard/hooks/useResize' +import { ResizingMode, useResize } from '@/pages/dashboard/hooks/useResize' +import { BoxDefinition } from '@/pages/dashboard/types' +import { useElementOffsets } from '@/utils/hooks/useElementOffsets' +import { useWindowEvent } from '@/utils/hooks/useWindowEvent' +import { ComponentChild } from 'preact' +import { useState } from 'preact/hooks' import { BoxSettings } from '../../BoxSettings/BoxSettings' -type Props = { +export type EditableBoxProps = { box: BoxDefinition onPosition: (p: { x: number; y: number }) => void onResize: (p: { w: number; h: number }) => void @@ -19,17 +18,23 @@ type Props = { onRemove: () => void } +type EditableBoxPropsWithExtra = EditableBoxProps & { + children: ComponentChild + onRefresh: () => void +} + export const EditableBox = ({ box, + children, onPosition, onResize, onEdit, onRemove, -}: Props) => { + onRefresh, +}: EditableBoxPropsWithExtra) => { const { boxes } = useDashboardContext() const [boxRef, setBoxRef] = useState() - const refreshRef = useRef<() => void>(null) const { verticalMode } = useDashboardContext() @@ -135,7 +140,7 @@ export const EditableBox = ({
{box.title || ''}
-
refreshRef.current?.()}> +
setEditing(true)}> @@ -143,22 +148,7 @@ export const EditableBox = ({
-
- {box.data?.type === 'graph' && ( - - )} - {box.data?.type === 'dial' && ( - - )} -
+
{children}
{ + switch (props.box.data?.type) { + case 'dial': + return + case 'graph': + return + default: + return
Unknown box type
+ } +} diff --git a/client/src/pages/dashboard/contexts/DashboardContext.tsx b/client/src/pages/dashboard/contexts/DashboardContext.tsx index 24d30ec..76b9ddf 100644 --- a/client/src/pages/dashboard/contexts/DashboardContext.tsx +++ b/client/src/pages/dashboard/contexts/DashboardContext.tsx @@ -119,7 +119,6 @@ export const DashboardContextProvider = ({ const customTo = queryFilterTo ? new Date(queryFilterTo) : new Date() const range = intervalToRange(presetInterval, customFrom, customTo) - console.log({ presetInterval, range }) return { interval: presetInterval, diff --git a/client/src/utils/hooks/useDelayedState.ts b/client/src/utils/hooks/useDelayedState.ts new file mode 100644 index 0000000..413c6d2 --- /dev/null +++ b/client/src/utils/hooks/useDelayedState.ts @@ -0,0 +1,21 @@ +import { useEffect, useState } from 'preact/hooks' +import { useTimeout } from './useTimeout' + +export const useDelayedState = (enabled: boolean, delay: number) => { + const [state, setState] = useState(false) + + useTimeout( + () => { + setState(true) + }, + enabled ? delay : false + ) + + useEffect(() => { + if (!enabled) { + setState(false) + } + }, [enabled]) + + return state +} diff --git a/client/src/utils/hooks/useQueryString.ts b/client/src/utils/hooks/useQueryString.ts index decc02f..293bb7b 100644 --- a/client/src/utils/hooks/useQueryString.ts +++ b/client/src/utils/hooks/useQueryString.ts @@ -13,8 +13,6 @@ export const useQueryString = () => { const search = location.slice(queryIndex + 1) - console.log('search', search) - return [location.slice(0, queryIndex), new URLSearchParams(search)] as const }, [location]) diff --git a/client/src/utils/hooks/useTimeout.ts b/client/src/utils/hooks/useTimeout.ts new file mode 100644 index 0000000..39c7692 --- /dev/null +++ b/client/src/utils/hooks/useTimeout.ts @@ -0,0 +1,14 @@ +import { useEffect, useRef } from 'preact/hooks' + +export const useTimeout = (cb: () => void, timeout: number | false) => { + const cbRef = useRef(cb) + cbRef.current = cb + + useEffect(() => { + if (timeout !== false) { + const id = setTimeout(() => cbRef.current(), timeout) + + return () => clearTimeout(id) + } + }, [timeout]) +}