Merge pull request #2089 from proddy/ft_dashboard

Ft dashboard - ui changes
This commit is contained in:
Proddy
2024-10-14 00:08:38 +01:00
committed by GitHub
9 changed files with 46 additions and 37 deletions

View File

@@ -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;
} }
` `
}); });

View File

@@ -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: `

View File

@@ -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

View File

@@ -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;
} }
` `
}); });

View File

@@ -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: `

View File

@@ -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';

View File

@@ -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;
}; };

View 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];
};

View File

@@ -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();
} }
} }
} }