mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
Merge pull request #2089 from proddy/ft_dashboard
Ft dashboard - ui changes
This commit is contained in:
@@ -125,15 +125,10 @@ const CustomEntities = () => {
|
|||||||
position: relative;
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
.td {
|
.td {
|
||||||
border-top: 1px solid #565656;
|
|
||||||
border-bottom: 1px solid #565656;
|
border-bottom: 1px solid #565656;
|
||||||
}
|
}
|
||||||
&:hover .td {
|
&:hover .td {
|
||||||
border-top: 1px solid #177ac9;
|
background-color: #177ac9;
|
||||||
border-bottom: 1px solid #177ac9;
|
|
||||||
}
|
|
||||||
&:nth-of-type(odd) .td {
|
|
||||||
background-color: #303030;
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -190,10 +190,7 @@ const Customizations = () => {
|
|||||||
}
|
}
|
||||||
&:hover .td {
|
&:hover .td {
|
||||||
border-top: 1px solid #177ac9;
|
border-top: 1px solid #177ac9;
|
||||||
border-bottom: 1px solid #177ac9;
|
background-color: #177ac9;
|
||||||
}
|
|
||||||
&:nth-of-type(odd) .td {
|
|
||||||
background-color: #303030;
|
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
Cell: `
|
Cell: `
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import { useRequest } from 'alova/client';
|
|||||||
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
|
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
|
||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { useInterval } from 'utils';
|
import { useInterval, usePersistState } from 'utils';
|
||||||
|
|
||||||
import { readDashboard, writeDeviceValue } from '../../api/app';
|
import { readDashboard, writeDeviceValue } from '../../api/app';
|
||||||
import DeviceIcon from './DeviceIcon';
|
import DeviceIcon from './DeviceIcon';
|
||||||
@@ -44,11 +44,10 @@ const Dashboard = () => {
|
|||||||
|
|
||||||
useLayoutTitle(LL.DASHBOARD());
|
useLayoutTitle(LL.DASHBOARD());
|
||||||
|
|
||||||
const [firstLoad, setFirstLoad] = useState<boolean>(true);
|
const [showAll, setShowAll] = usePersistState(true, 'showAll');
|
||||||
const [showAll, setShowAll] = useState<boolean>(true);
|
|
||||||
|
|
||||||
const [deviceValueDialogOpen, setDeviceValueDialogOpen] = useState<boolean>(false);
|
const [deviceValueDialogOpen, setDeviceValueDialogOpen] = useState<boolean>(false);
|
||||||
|
const [parentNodes, setParentNodes] = useState<number>(0);
|
||||||
const [selectedDashboardItem, setSelectedDashboardItem] =
|
const [selectedDashboardItem, setSelectedDashboardItem] =
|
||||||
useState<DashboardItem>();
|
useState<DashboardItem>();
|
||||||
|
|
||||||
@@ -59,6 +58,10 @@ const Dashboard = () => {
|
|||||||
loading
|
loading
|
||||||
} = useRequest(readDashboard, {
|
} = useRequest(readDashboard, {
|
||||||
initialData: []
|
initialData: []
|
||||||
|
}).onSuccess((event) => {
|
||||||
|
if (event.data.length !== parentNodes) {
|
||||||
|
setParentNodes(event.data.length); // count number of parents/devices
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { loading: submitting, send: sendDeviceValue } = useRequest(
|
const { loading: submitting, send: sendDeviceValue } = useRequest(
|
||||||
@@ -145,13 +148,11 @@ const Dashboard = () => {
|
|||||||
}
|
}
|
||||||
}, 3000);
|
}, 3000);
|
||||||
|
|
||||||
// auto expand on first load
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (firstLoad && Array.isArray(data) && data.length && !tree.state.ids.length) {
|
showAll
|
||||||
tree.fns.onToggleAll({});
|
? tree.fns.onAddAll(data.map((item: DashboardItem) => item.id)) // expand tree
|
||||||
setFirstLoad(false);
|
: tree.fns.onRemoveAll(); // collapse tree
|
||||||
}
|
}, [parentNodes]);
|
||||||
}, [loading]);
|
|
||||||
|
|
||||||
const showType = (n?: string, t?: number) => {
|
const showType = (n?: string, t?: number) => {
|
||||||
// if we have a name show it
|
// if we have a name show it
|
||||||
|
|||||||
@@ -117,15 +117,10 @@ const Scheduler = () => {
|
|||||||
position: relative;
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
.td {
|
.td {
|
||||||
border-top: 1px solid #565656;
|
|
||||||
border-bottom: 1px solid #565656;
|
border-bottom: 1px solid #565656;
|
||||||
}
|
}
|
||||||
&:hover .td {
|
&:hover .td {
|
||||||
border-top: 1px solid #177ac9;
|
background-color: #177ac9;
|
||||||
border-bottom: 1px solid #177ac9;
|
|
||||||
}
|
|
||||||
&:nth-of-type(odd) .td {
|
|
||||||
background-color: #303030;
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -116,19 +116,10 @@ const Sensors = () => {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
.td {
|
.td {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
border-top: 1px solid #565656;
|
|
||||||
border-bottom: 1px solid #565656;
|
border-bottom: 1px solid #565656;
|
||||||
}
|
}
|
||||||
&.tr.tr-body.row-select.row-select-single-selected {
|
|
||||||
background-color: #3d4752;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
&:hover .td {
|
&:hover .td {
|
||||||
border-top: 1px solid #177ac9;
|
background-color: #177ac9;
|
||||||
border-bottom: 1px solid #177ac9;
|
|
||||||
}
|
|
||||||
&:nth-of-type(odd) .td {
|
|
||||||
background-color: #303030;
|
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
Cell: `
|
Cell: `
|
||||||
|
|||||||
@@ -6,3 +6,4 @@ export * from './useRest';
|
|||||||
export * from './useInterval';
|
export * from './useInterval';
|
||||||
export * from './props';
|
export * from './props';
|
||||||
export * from './file';
|
export * from './file';
|
||||||
|
export * from './usePersistState';
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import { useEffect, useRef } from 'react';
|
|||||||
export const useInterval = (callback: () => void, delay: number) => {
|
export const useInterval = (callback: () => void, delay: number) => {
|
||||||
const intervalRef = useRef<number | null>(null);
|
const intervalRef = useRef<number | null>(null);
|
||||||
const savedCallback = useRef<() => void>(callback);
|
const savedCallback = useRef<() => void>(callback);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
savedCallback.current = callback;
|
savedCallback.current = callback;
|
||||||
}, [callback]);
|
}, [callback]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const tick = () => savedCallback.current();
|
const tick = () => savedCallback.current();
|
||||||
if (typeof delay === 'number') {
|
if (typeof delay === 'number') {
|
||||||
@@ -18,5 +20,6 @@ export const useInterval = (callback: () => void, delay: number) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, [delay]);
|
}, [delay]);
|
||||||
|
|
||||||
return intervalRef;
|
return intervalRef;
|
||||||
};
|
};
|
||||||
|
|||||||
26
interface/src/utils/usePersistState.ts
Normal file
26
interface/src/utils/usePersistState.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
|
export const usePersistState = <T>(
|
||||||
|
initial_value: T,
|
||||||
|
id: string
|
||||||
|
): [T, (new_state: T) => void] => {
|
||||||
|
// Set initial value
|
||||||
|
const _initial_value = useMemo(() => {
|
||||||
|
const local_storage_value_str = localStorage.getItem('state:' + id);
|
||||||
|
// If there is a value stored in localStorage, use that
|
||||||
|
if (local_storage_value_str) {
|
||||||
|
return JSON.parse(local_storage_value_str);
|
||||||
|
}
|
||||||
|
// Otherwise use initial_value that was passed to the function
|
||||||
|
return initial_value;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const [state, setState] = useState(_initial_value);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const state_str = JSON.stringify(state); // Stringified state
|
||||||
|
localStorage.setItem('state:' + id, state_str); // Set stringified state as item in localStorage
|
||||||
|
}, [state]);
|
||||||
|
|
||||||
|
return [state, setState];
|
||||||
|
};
|
||||||
@@ -422,11 +422,11 @@ void WebDataService::dashboard_data(AsyncWebServerRequest * request) {
|
|||||||
l.add(Helpers::render_boolean(s, true, true));
|
l.add(Helpers::render_boolean(s, true, true));
|
||||||
} else {
|
} else {
|
||||||
dv["v"] = Helpers::transformNumFloat(sensor.value(), 0);
|
dv["v"] = Helpers::transformNumFloat(sensor.value(), 0);
|
||||||
|
dv["u"] = sensor.uom();
|
||||||
}
|
}
|
||||||
if (sensor.type() == AnalogSensor::AnalogType::COUNTER || sensor.type() >= AnalogSensor::AnalogType::DIGITAL_OUT) {
|
if (sensor.type() == AnalogSensor::AnalogType::COUNTER || sensor.type() >= AnalogSensor::AnalogType::DIGITAL_OUT) {
|
||||||
dv["c"] = sensor.name();
|
dv["c"] = sensor.name();
|
||||||
}
|
}
|
||||||
dv["u"] = sensor.uom();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user