default Alova v2

This commit is contained in:
proddy
2024-08-10 10:22:14 +02:00
parent efa9718081
commit bb98042957
38 changed files with 574 additions and 287 deletions

View File

@@ -19,7 +19,8 @@ import {
Table
} from '@table-library/react-table-library/table';
import { useTheme } from '@table-library/react-table-library/theme';
import { updateState, useRequest } from 'alova/client';
import { updateState, useRequest } from 'alova';
// import { updateState, useRequest } from 'alova/client'; // TODO replace when Alova 3 is released
import {
BlockNavigation,
ButtonRow,

View File

@@ -39,7 +39,8 @@ import {
} from '@table-library/react-table-library/table';
import { useTheme } from '@table-library/react-table-library/theme';
import { dialogStyle } from 'CustomTheme';
import { useRequest } from 'alova/client';
import { useRequest } from 'alova';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import RestartMonitor from 'app/status/RestartMonitor';
import {
BlockNavigation,
@@ -110,13 +111,25 @@ const Customizations = () => {
}
);
const { send: sendDeviceEntities } = useRequest(
// TODO Alova 3 code...
// const { send: sendDeviceEntities } = useRequest(
// (data: number) => readDeviceEntities(data),
// {
// initialData: [],
// immediate: false
// }
// ).onSuccess((event) => {
// setOriginalSettings(event.data);
// });
const { send: sendDeviceEntities, onSuccess } = useRequest(
(data: number) => readDeviceEntities(data),
{
initialData: [],
immediate: false
}
).onSuccess((event) => {
);
onSuccess((event) => {
setOriginalSettings(event.data);
});

View File

@@ -15,8 +15,8 @@ import PlaylistAddIcon from '@mui/icons-material/PlaylistAdd';
import { DeviceType } from './types';
export default function DeviceIcon({ type_id }) {
switch (type_id as DeviceType) {
const DeviceIcon = ({ type_id }: { type_id: DeviceType }) => {
switch (type_id) {
case DeviceType.TEMPERATURESENSOR:
case DeviceType.ANALOGSENSOR:
return <MdOutlineSensors />;
@@ -55,4 +55,6 @@ export default function DeviceIcon({ type_id }) {
default:
return null;
}
}
};
export default DeviceIcon;

View File

@@ -56,7 +56,8 @@ import {
import { useTheme } from '@table-library/react-table-library/theme';
import type { Action, State } from '@table-library/react-table-library/types/common';
import { dialogStyle } from 'CustomTheme';
import { useRequest } from 'alova/client';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import { useRequest } from 'alova';
import { ButtonRow, MessageBox, SectionContent, useLayoutTitle } from 'components';
import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from 'i18n/i18n-react';

View File

@@ -17,9 +17,8 @@ import {
Typography
} from '@mui/material';
import { readSystemStatus } from 'api/system';
import { useRequest } from 'alova/client';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import { useRequest } from 'alova';
import { SectionContent, useLayoutTitle } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
@@ -30,24 +29,43 @@ const Help = () => {
const { LL } = useI18nContext();
useLayoutTitle(LL.HELP_OF(''));
const { send: getAPI } = useRequest((data: APIcall) => API(data), {
immediate: false
}).onSuccess((event) => {
const { send: getAPI, onSuccess: onGetAPI } = useRequest(
(data: APIcall) => API(data),
{
immediate: false
}
);
onGetAPI((event) => {
const anchor = document.createElement('a');
anchor.href = URL.createObjectURL(
new Blob([JSON.stringify(event.data, null, 2)], {
type: 'text/plain'
})
);
anchor.download =
'emsesp_' + event.args[0].device + '_' + event.args[0].entity + '.txt';
'emsesp_' + event.sendArgs[0].device + '_' + event.sendArgs[0].entity + '.txt';
anchor.click();
URL.revokeObjectURL(anchor.href);
toast.info(LL.DOWNLOAD_SUCCESSFUL());
});
const { data, loading } = useRequest(readSystemStatus);
// Alova 3 code...
// const { send: getAPI } = useRequest((data: APIcall) => API(data), {
// immediate: false
// }).onSuccess((event) => {
// const anchor = document.createElement('a');
// anchor.href = URL.createObjectURL(
// new Blob([JSON.stringify(event.data, null, 2)], {
// type: 'text/plain'
// })
// );
//
// anchor.download =
// 'emsesp_' + event.args[0].device + '_' + event.args[0].entity + '.txt';
// anchor.click();
// URL.revokeObjectURL(anchor.href);
// toast.info(LL.DOWNLOAD_SUCCESSFUL());
// });
const callAPI = async (device: string, entity: string) => {
await getAPI({ device, entity, id: 0 }).catch((error: Error) => {
@@ -55,15 +73,8 @@ const Help = () => {
});
};
// TODO remove debug testing useRequest preact hook
console.log('loading: ' + loading + ' data2: ' + data);
if (loading) {
return <div>Loading...</div>;
}
return (
<>
<div>version is {data.emsesp_version}</div>
<SectionContent>
<List sx={{ borderRadius: 3, border: '2px solid grey' }}>
<ListItem>

View File

@@ -17,7 +17,8 @@ import {
Table
} from '@table-library/react-table-library/table';
import { useTheme } from '@table-library/react-table-library/theme';
import { updateState, useRequest } from 'alova/client';
import { updateState, useRequest } from 'alova';
// import { updateState, useRequest } from 'alova/client'; // TODO replace when Alova 3 is released
import {
BlockNavigation,
ButtonRow,

View File

@@ -30,11 +30,13 @@ const OPTION_ICONS: {
favorite: [StarIcon, StarOutlineIcon]
};
export default function OptionIcon({ type, isSet }) {
const OptionIcon = ({ type, isSet }: { type: OptionType; isSet: boolean }) => {
const Icon = OPTION_ICONS[type][isSet ? 0 : 1];
return isSet ? (
<Icon color="primary" sx={{ fontSize: 16, verticalAlign: 'middle' }} />
) : (
<Icon sx={{ fontSize: 16, verticalAlign: 'middle' }} />
);
}
};
export default OptionIcon;

View File

@@ -18,7 +18,8 @@ import {
Table
} from '@table-library/react-table-library/table';
import { useTheme } from '@table-library/react-table-library/theme';
import { updateState, useRequest } from 'alova/client';
// import { updateState, useRequest } from 'alova/client'; // TODO replace when Alova 3 is released
import { updateState, useRequest } from 'alova';
import {
BlockNavigation,
ButtonRow,

View File

@@ -20,7 +20,8 @@ import {
} from '@table-library/react-table-library/table';
import { useTheme } from '@table-library/react-table-library/theme';
import type { State } from '@table-library/react-table-library/types/common';
import { useRequest } from 'alova/client';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import { useRequest } from 'alova';
import { ButtonRow, SectionContent, useLayoutTitle } from 'components';
import { AuthenticatedContext } from 'contexts/authentication';
import { useI18nContext } from 'i18n/i18n-react';

View File

@@ -18,7 +18,8 @@ import {
import { readHardwareStatus, restart } from 'api/system';
import { useRequest } from 'alova/client';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import { useRequest } from 'alova';
import RestartMonitor from 'app/status/RestartMonitor';
import type { ValidateFieldsError } from 'async-validator';
import {
@@ -49,9 +50,7 @@ export function boardProfileSelectItems() {
}
const ApplicationSettings = () => {
const { data: hardwareData } = useRequest(readHardwareStatus, {
initialData: { psram: false }
});
const { data: hardwareData } = useRequest(readHardwareStatus);
const {
loadData,
@@ -83,12 +82,15 @@ const ApplicationSettings = () => {
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
const { loading: processingBoard, send: readBoardProfile } = useRequest(
(boardProfile: string) => getBoardProfile(boardProfile),
{
immediate: false
}
).onSuccess((event) => {
const {
loading: processingBoard,
send: readBoardProfile,
onSuccess: onSuccessBoardProfile
} = useRequest((boardProfile: string) => getBoardProfile(boardProfile), {
immediate: false
});
onSuccessBoardProfile((event) => {
const response = event.data as Settings;
updateDataValue({
...data,
@@ -105,6 +107,29 @@ const ApplicationSettings = () => {
});
});
// TODO replace with Alova 3
// const { loading: processingBoard, send: readBoardProfile } = useRequest(
// (boardProfile: string) => getBoardProfile(boardProfile),
// {
// immediate: false
// }
// ).onSuccess((event) => {
// const response = event.data as Settings;
// updateDataValue({
// ...data,
// board_profile: response.board_profile,
// led_gpio: response.led_gpio,
// dallas_gpio: response.dallas_gpio,
// rx_gpio: response.rx_gpio,
// tx_gpio: response.tx_gpio,
// pbutton_gpio: response.pbutton_gpio,
// phy_type: response.phy_type,
// eth_power: response.eth_power,
// eth_phy_addr: response.eth_phy_addr,
// eth_clock_mode: response.eth_clock_mode
// });
// });
const { send: restartCommand } = useRequest(restart(), {
immediate: false
});
@@ -118,7 +143,7 @@ const ApplicationSettings = () => {
useLayoutTitle(LL.SETTINGS_OF(LL.APPLICATION()));
const content = () => {
if (!data) {
if (!data || !hardwareData) {
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
}

View File

@@ -7,7 +7,8 @@ import { Button, Checkbox, MenuItem } from '@mui/material';
import * as NTPApi from 'api/ntp';
import { readNTPSettings } from 'api/ntp';
import { updateState } from 'alova/client';
// import { updateState } from 'alova/client'; // TODO replace when Alova 3 is released
import { updateState } from 'alova';
import type { ValidateFieldsError } from 'async-validator';
import {
BlockFormControlLabel,

View File

@@ -24,7 +24,8 @@ import {
import * as SystemApi from 'api/system';
import { dialogStyle } from 'CustomTheme';
import { useRequest } from 'alova/client';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import { useRequest } from 'alova';
import { SectionContent, useLayoutTitle } from 'components';
import ListMenuItem from 'components/layout/ListMenuItem';
import { useI18nContext } from 'i18n/i18n-react';

View File

@@ -14,7 +14,8 @@ import {
} from 'api/app';
import { getDevVersion, getStableVersion } from 'api/system';
import { useRequest } from 'alova/client';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import { useRequest } from 'alova';
import type { APIcall } from 'app/main/types';
import {
FormLoader,
@@ -31,6 +32,92 @@ const UploadDownload = () => {
const [restarting, setRestarting] = useState<boolean>();
const [md5, setMd5] = useState<string>();
const { send: sendSettings, onSuccess: onSuccessGetSettings } = useRequest(
getSettings(),
{
immediate: false
}
);
const { send: sendCustomizations, onSuccess: onSuccessGetCustomizations } =
useRequest(getCustomizations(), {
immediate: false
});
const { send: sendEntities, onSuccess: onSuccessGetEntities } = useRequest(
getEntities(),
{
immediate: false
}
);
const { send: sendSchedule, onSuccess: onSuccessGetSchedule } = useRequest(
getSchedule(),
{
immediate: false
}
);
const { send: getAPI, onSuccess: onGetAPI } = useRequest(
(data: APIcall) => API(data),
{
immediate: false
}
);
// Alova 3 code...
// const {
// loading: isUploading,
// uploading: progress,
// send: sendUpload,
// abort: cancelUpload
// } = useRequest(SystemApi.uploadFile, {
// immediate: false
// }).onSuccess(({ data }) => {
// if (data) {
// setMd5(data.md5);
// toast.success(LL.UPLOAD() + ' MD5 ' + LL.SUCCESSFUL());
// } else {
// setRestarting(true);
// }
// });
const {
loading: isUploading,
uploading: progress,
send: sendUpload,
onSuccess: onSuccessUpload,
abort: cancelUpload
} = useRequest(SystemApi.uploadFile, {
immediate: false
});
onSuccessUpload(({ data }) => {
if (data) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
setMd5(data.md5);
toast.success(LL.UPLOAD() + ' MD5 ' + LL.SUCCESSFUL());
} else {
setRestarting(true);
}
});
onSuccessGetSettings((event) => {
saveFile(event.data, 'settings.json');
});
onSuccessGetCustomizations((event) => {
saveFile(event.data, 'customizations.json');
});
onSuccessGetEntities((event) => {
saveFile(event.data, 'entities.json');
});
onSuccessGetSchedule((event) => {
saveFile(event.data, 'schedule.json');
});
onGetAPI((event) => {
saveFile(
event.data,
event.sendArgs[0].device + '_' + event.sendArgs[0].entity + '.txt'
);
});
// TODO Alova 3 code...
/*
const { send: sendSettings } = useRequest(getSettings(), {
immediate: false
}).onSuccess((event) => {
@@ -64,6 +151,8 @@ const UploadDownload = () => {
);
});
*/
const {
data: data,
send: loadData,
@@ -96,22 +185,6 @@ const UploadDownload = () => {
return data.esp_platform;
};
const {
loading: isUploading,
uploading: progress,
send: sendUpload,
abort: cancelUpload
} = useRequest(SystemApi.uploadFile, {
immediate: false
}).onSuccess(({ data }) => {
if (data) {
setMd5(data.md5);
toast.success(LL.UPLOAD() + ' MD5 ' + LL.SUCCESSFUL());
} else {
setRestarting(true);
}
});
const startUpload = async (files: File[]) => {
await sendUpload(files[0]).catch((error: Error) => {
if (error.message === 'The user aborted a request') {

View File

@@ -25,7 +25,8 @@ import {
import * as NetworkApi from 'api/network';
import * as SystemApi from 'api/system';
import { updateState, useRequest } from 'alova/client';
import { updateState, useRequest } from 'alova';
// import { updateState, useRequest } from 'alova/client'; // TODO replace when Alova 3 is released
import type { ValidateFieldsError } from 'async-validator';
import {
BlockFormControlLabel,

View File

@@ -5,7 +5,8 @@ import { Button } from '@mui/material';
import * as NetworkApi from 'api/network';
import { updateState, useRequest } from 'alova/client';
// import { updateState, useRequest } from 'alova/client'; // TODO replace when Alova 3 is released
import { updateState, useRequest } from 'alova';
import { ButtonRow, FormLoader, SectionContent } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
@@ -20,22 +21,18 @@ const WiFiNetworkScanner = () => {
const [errorMessage, setErrorMessage] = useState<string>();
// is called on page load to start network scan
const { send: scanNetworks } = useRequest(NetworkApi.scanNetworks).onComplete(
() => {
pollCount.current = 0;
setErrorMessage(undefined);
void updateState(NetworkApi.listNetworks(), () => undefined);
void getNetworkList();
}
);
const { data: networkList, send: getNetworkList } = useRequest(
NetworkApi.listNetworks,
{
immediate: false
}
).onSuccess((event) => {
// is called when network scan is completed
const { send: scanNetworks, onComplete: onCompleteScanNetworks } = useRequest(
NetworkApi.scanNetworks
);
const {
data: networkList,
send: getNetworkList,
onSuccess: onSuccessNetworkList
} = useRequest(NetworkApi.listNetworks, {
immediate: false
});
onSuccessNetworkList((event) => {
if (!event.data) {
const completedPollCount = pollCount.current + 1;
if (completedPollCount < NUM_POLLS) {
@@ -48,6 +45,42 @@ const WiFiNetworkScanner = () => {
}
});
onCompleteScanNetworks(() => {
pollCount.current = 0;
setErrorMessage(undefined);
updateState('listNetworks', () => undefined);
void getNetworkList();
});
// Alova 3 code...
// const { send: scanNetworks } = useRequest(NetworkApi.scanNetworks).onComplete(
// () => {
// pollCount.current = 0;
// setErrorMessage(undefined);
// void updateState(NetworkApi.listNetworks(), () => undefined);
// void getNetworkList();
// }
// );
// const { data: networkList, send: getNetworkList } = useRequest(
// NetworkApi.listNetworks,
// {
// immediate: false
// }
// ).onSuccess((event) => {
// // is called when network scan is completed
// if (!event.data) {
// const completedPollCount = pollCount.current + 1;
// if (completedPollCount < NUM_POLLS) {
// pollCount.current = completedPollCount;
// setTimeout(getNetworkList, POLLING_FREQUENCY);
// } else {
// setErrorMessage(LL.PROBLEM_LOADING());
// pollCount.current = 0;
// }
// }
// });
const renderNetworkScanner = () => {
if (!networkList) {
return (

View File

@@ -17,7 +17,7 @@ import type { Theme } from '@mui/material';
import { MessageBox } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
import type { WiFiNetwork } from 'types';
import type { WiFiNetwork, WiFiNetworkList } from 'types';
import { WiFiEncryptionType } from 'types';
import { WiFiConnectionContext } from './WiFiConnectionContext';
@@ -57,7 +57,7 @@ const networkQualityHighlight = ({ rssi }: WiFiNetwork, theme: Theme) => {
return theme.palette.success.main;
};
function WiFiNetworkSelector({ networkList }) {
const WiFiNetworkSelector = ({ networkList }: { networkList: WiFiNetworkList }) => {
const { LL } = useI18nContext();
const theme = useTheme();
@@ -95,6 +95,6 @@ function WiFiNetworkSelector({ networkList }) {
}
return <List>{networkList.networks.map(renderNetwork)}</List>;
}
};
export default WiFiNetworkSelector;

View File

@@ -16,11 +16,17 @@ import {
import * as SecurityApi from 'api/security';
import { dialogStyle } from 'CustomTheme';
import { useRequest } from 'alova/client';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import { useRequest } from 'alova';
import { MessageBox } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
export default function GenerateToken({ username, onClose }) {
interface GenerateTokenProps {
username?: string;
onClose: () => void;
}
const GenerateToken = ({ username, onClose }: GenerateTokenProps) => {
const { LL } = useI18nContext();
const open = !!username;
@@ -79,4 +85,6 @@ export default function GenerateToken({ username, onClose }) {
</DialogActions>
</Dialog>
);
}
};
export default GenerateToken;

View File

@@ -16,7 +16,8 @@ import type { Theme } from '@mui/material';
import * as APApi from 'api/ap';
import { useRequest } from 'alova/client';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import { useRequest } from 'alova';
import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
import type { APStatusType } from 'types';

View File

@@ -13,7 +13,8 @@ import {
Table
} from '@table-library/react-table-library/table';
import { useTheme as tableTheme } from '@table-library/react-table-library/theme';
import { useRequest } from 'alova/client';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import { useRequest } from 'alova';
import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
import type { Translation } from 'i18n/i18n-types';

View File

@@ -20,7 +20,8 @@ import {
import * as SystemApi from 'api/system';
import { useRequest } from 'alova/client';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import { useRequest } from 'alova';
import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components';
import { useI18nContext } from 'i18n/i18n-react';

View File

@@ -17,7 +17,8 @@ import type { Theme } from '@mui/material';
import * as MqttApi from 'api/mqtt';
import { useRequest } from 'alova/client';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import { useRequest } from 'alova';
import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
import type { MqttStatusType } from 'types';

View File

@@ -29,7 +29,8 @@ import type { Theme } from '@mui/material';
import * as NTPApi from 'api/ntp';
import { dialogStyle } from 'CustomTheme';
import { useRequest } from 'alova/client';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import { useRequest } from 'alova';
import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
import type { NTPStatusType, Time } from 'types';

View File

@@ -20,7 +20,8 @@ import type { Theme } from '@mui/material';
import * as NetworkApi from 'api/network';
import { useRequest } from 'alova/client';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import { useRequest } from 'alova';
import { ButtonRow, FormLoader, SectionContent, useLayoutTitle } from 'components';
import { useI18nContext } from 'i18n/i18n-react';
import type { NetworkStatusType } from 'types';

View File

@@ -2,7 +2,8 @@ import { useEffect, useRef, useState } from 'react';
import * as SystemApi from 'api/system';
import { useRequest } from 'alova/client';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import { useRequest } from 'alova';
import { FormLoader } from 'components';
import { useI18nContext } from 'i18n/i18n-react';

View File

@@ -34,7 +34,8 @@ import {
import * as SystemApi from 'api/system';
import { dialogStyle } from 'CustomTheme';
import { useRequest } from 'alova/client';
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
import { useRequest } from 'alova';
import { busConnectionStatus } from 'app/main/types';
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
import ListMenuItem from 'components/layout/ListMenuItem';
@@ -67,8 +68,8 @@ const SystemStatus = () => {
const {
data: data,
loading,
send: loadData
send: loadData,
error
} = useRequest(SystemApi.readSystemStatus, {
initialData: []
});
@@ -272,11 +273,6 @@ const SystemStatus = () => {
);
const content = () => {
// TODO remove test code
if (loading) {
return <>not loaded!</>;
}
if (!data) {
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
}

View File

@@ -16,7 +16,9 @@ import {
import * as SystemApi from 'api/system';
import { fetchLogES } from 'api/system';
import { useRequest, useSSE } from 'alova/client';
// import { useRequest, useSSE } from 'alova/client'; // TODO replace when Alova 3 is released
import { useSSE } from '@alova/scene-react';
import { useRequest } from 'alova';
import {
BlockFormControlLabel,
BlockNavigation,