mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-08 00:39:50 +03:00
default Alova v2
This commit is contained in:
@@ -22,7 +22,7 @@ const RootRedirect = ({ message, signOut }: SecurityRedirectProps) => {
|
||||
return <Navigate to="/" />;
|
||||
};
|
||||
|
||||
export default function AppRouting() {
|
||||
const AppRouting = () => {
|
||||
const { LL } = useI18nContext();
|
||||
|
||||
return (
|
||||
@@ -55,4 +55,6 @@ export default function AppRouting() {
|
||||
</Routes>
|
||||
</Authentication>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default AppRouting;
|
||||
|
||||
@@ -5,7 +5,8 @@ import ForwardIcon from '@mui/icons-material/Forward';
|
||||
import { Box, Button, Paper, Typography } from '@mui/material';
|
||||
|
||||
import * as AuthenticationApi from 'components/routing/authentication';
|
||||
import { useRequest } from 'alova/client';
|
||||
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
|
||||
import { useRequest } from 'alova';
|
||||
import type { ValidateFieldsError } from 'async-validator';
|
||||
import {
|
||||
LanguageSelector,
|
||||
@@ -31,12 +32,26 @@ const SignIn = () => {
|
||||
const [processing, setProcessing] = useState<boolean>(false);
|
||||
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
||||
|
||||
const { send: callSignIn } = useRequest(
|
||||
// TODO ALova 3 code...
|
||||
// const { send: callSignIn } = useRequest(
|
||||
// (request: SignInRequest) => AuthenticationApi.signIn(request),
|
||||
// {
|
||||
// immediate: false
|
||||
// }
|
||||
// ).onSuccess((response) => {
|
||||
// if (response.data) {
|
||||
// authenticationContext.signIn(response.data.access_token);
|
||||
// }
|
||||
// });
|
||||
|
||||
const { send: callSignIn, onSuccess } = useRequest(
|
||||
(request: SignInRequest) => AuthenticationApi.signIn(request),
|
||||
{
|
||||
immediate: false
|
||||
}
|
||||
).onSuccess((response) => {
|
||||
);
|
||||
|
||||
onSuccess((response) => {
|
||||
if (response.data) {
|
||||
authenticationContext.signIn(response.data.access_token);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,8 @@ export const readDeviceEntities = (id: number) =>
|
||||
alovaInstance.Get<DeviceEntity[]>(`/rest/deviceEntities`, {
|
||||
params: { id },
|
||||
responseType: 'arraybuffer',
|
||||
transform(data) {
|
||||
// transform(data) { // TODO alova 3
|
||||
transformData(data) {
|
||||
return (data as DeviceEntity[]).map((de: DeviceEntity) => ({
|
||||
...de,
|
||||
o_m: de.m,
|
||||
@@ -88,7 +89,8 @@ export const writeDeviceName = (data: { id: number; name: string }) =>
|
||||
// SettingsScheduler
|
||||
export const readSchedule = () =>
|
||||
alovaInstance.Get<ScheduleItem[]>('/rest/schedule', {
|
||||
transform(data) {
|
||||
// transform(data) { // TODO alova 3
|
||||
transformData(data) {
|
||||
return (data as Schedule).schedule.map((si: ScheduleItem) => ({
|
||||
...si,
|
||||
o_id: si.id,
|
||||
@@ -108,7 +110,8 @@ export const writeSchedule = (data: Schedule) =>
|
||||
// Modules
|
||||
export const readModules = () =>
|
||||
alovaInstance.Get<ModuleItem[]>('/rest/modules', {
|
||||
transform(data) {
|
||||
// transform(data) { // TODO alova 3
|
||||
transformData(data) {
|
||||
return (data as Modules).modules.map((mi: ModuleItem) => ({
|
||||
...mi,
|
||||
o_enabled: mi.enabled,
|
||||
@@ -125,7 +128,8 @@ export const writeModules = (data: {
|
||||
// SettingsEntities
|
||||
export const readCustomEntities = () =>
|
||||
alovaInstance.Get<EntityItem[]>('/rest/customEntities', {
|
||||
transform(data) {
|
||||
// transform(data) { // TODO alova 3
|
||||
transformData(data) {
|
||||
return (data as Entities).entities.map((ei: EntityItem) => ({
|
||||
...ei,
|
||||
o_id: ei.id,
|
||||
|
||||
@@ -8,25 +8,10 @@ export const ACCESS_TOKEN = 'access_token';
|
||||
|
||||
export const alovaInstance = createAlova({
|
||||
statesHook: ReactHook,
|
||||
cacheFor: null,
|
||||
// TODO fix cache
|
||||
// cacheFor: {
|
||||
// // Set the cache mode for POST uniformly
|
||||
// POST: {
|
||||
// mode: 'restore',
|
||||
// expire: 60 * 10 * 1000
|
||||
// },
|
||||
// // Set the cache mode for HEAD requests uniformly
|
||||
// HEAD: 60 * 10 * 1000
|
||||
// },
|
||||
// timeout: 3000, // 3 seconds but throwing a timeout error
|
||||
// localCache: null,
|
||||
// localCache: {
|
||||
// GET: {
|
||||
// mode: 'placeholder', // see https://alova.js.org/learning/response-cache/#cache-replaceholder-mode
|
||||
// expire: 2000
|
||||
// }
|
||||
// },
|
||||
timeout: 3000, // 3 seconds but throwing a timeout error
|
||||
localCache: null,
|
||||
// TODO Alova v3 code...
|
||||
// cacheFor: null,
|
||||
requestAdapter: xhrRequestAdapter(),
|
||||
beforeRequest(method) {
|
||||
if (localStorage.getItem(ACCESS_TOKEN)) {
|
||||
|
||||
@@ -24,15 +24,29 @@ export const fetchLog = () => alovaInstance.Post('/rest/fetchLog');
|
||||
export const fetchLogES = () => alovaInstance.Get('/es/log');
|
||||
|
||||
// Get versions from github
|
||||
|
||||
// Alova 3 code...
|
||||
// export const getStableVersion = () =>
|
||||
// alovaInstanceGH.Get('latest', {
|
||||
// transform(response: { data: { name: string } }) {
|
||||
// return response.data.name.substring(1);
|
||||
// }
|
||||
// });
|
||||
// export const getDevVersion = () =>
|
||||
// alovaInstanceGH.Get('tags/latest', {
|
||||
// transform(response: { data: { name: string } }) {
|
||||
// return response.data.name.split(/\s+/).splice(-1)[0].substring(1);
|
||||
// }
|
||||
// });
|
||||
export const getStableVersion = () =>
|
||||
alovaInstanceGH.Get('latest', {
|
||||
transform(response: { data: { name: string } }) {
|
||||
transformData(response: { data: { name: string } }) {
|
||||
return response.data.name.substring(1);
|
||||
}
|
||||
});
|
||||
export const getDevVersion = () =>
|
||||
alovaInstanceGH.Get('tags/latest', {
|
||||
transform(response: { data: { name: string } }) {
|
||||
transformData(response: { data: { name: string } }) {
|
||||
return response.data.name.split(/\s+/).splice(-1)[0].substring(1);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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} />;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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') {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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} />;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -6,7 +6,12 @@ import { AppBar, IconButton, Toolbar, Typography } from '@mui/material';
|
||||
|
||||
export const DRAWER_WIDTH = 210;
|
||||
|
||||
export default function LayoutAppBar({ title, onToggleDrawer }) {
|
||||
interface LayoutAppBarProps {
|
||||
title: string;
|
||||
onToggleDrawer: () => void;
|
||||
}
|
||||
|
||||
const LayoutAppBar = ({ title, onToggleDrawer }: LayoutAppBarProps) => {
|
||||
const pathnames = useLocation()
|
||||
.pathname.split('/')
|
||||
.filter((x) => x);
|
||||
@@ -50,4 +55,6 @@ export default function LayoutAppBar({ title, onToggleDrawer }) {
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default LayoutAppBar;
|
||||
|
||||
@@ -16,7 +16,12 @@ const LayoutDrawerLogo = styled('img')(({ theme }) => ({
|
||||
}
|
||||
}));
|
||||
|
||||
export default function LayoutDrawerProps({ mobileOpen, onClose }) {
|
||||
interface LayoutDrawerProps {
|
||||
mobileOpen: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const LayoutDrawerProps = ({ mobileOpen, onClose }: LayoutDrawerProps) => {
|
||||
const drawer = (
|
||||
<>
|
||||
<Toolbar disableGutters>
|
||||
@@ -59,4 +64,6 @@ export default function LayoutDrawerProps({ mobileOpen, onClose }) {
|
||||
</Drawer>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default LayoutDrawerProps;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { Blocker } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
@@ -9,7 +11,7 @@ import {
|
||||
import { dialogStyle } from 'CustomTheme';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
|
||||
export default function BlockNavigation({ blocker }) {
|
||||
const BlockNavigation = ({ blocker }: { blocker: Blocker }) => {
|
||||
const { LL } = useI18nContext();
|
||||
|
||||
return (
|
||||
@@ -34,4 +36,6 @@ export default function BlockNavigation({ blocker }) {
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default BlockNavigation;
|
||||
|
||||
@@ -6,7 +6,8 @@ import { toast } from 'react-toastify';
|
||||
import { ACCESS_TOKEN } from 'api/endpoints';
|
||||
|
||||
import * as AuthenticationApi from 'components/routing/authentication';
|
||||
import { useRequest } from 'alova/client';
|
||||
// import { useRequest } from 'alova/client' // TODO replace when Alova 3 is released
|
||||
import { useRequest } from 'alova';
|
||||
import { LoadingSpinner } from 'components';
|
||||
import { verifyAuthorization } from 'components/routing/authentication';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
|
||||
@@ -1,14 +1,90 @@
|
||||
// TODO Alova 3 code....
|
||||
// import { useState } from 'react';
|
||||
// import { useBlocker } from 'react-router-dom';
|
||||
// import { toast } from 'react-toastify';
|
||||
// import type { AlovaGenerics, Method } from 'alova';
|
||||
// import { useRequest } from 'alova/client';
|
||||
// import { useI18nContext } from 'i18n/i18n-react';
|
||||
// export interface RestRequestOptions<D> {
|
||||
// read: () => Method<AlovaGenerics>;
|
||||
// update: (value: D) => Method<AlovaGenerics>;
|
||||
// }
|
||||
// export const useRest = <D>({ read, update }: RestRequestOptions<D>) => {
|
||||
// const { LL } = useI18nContext();
|
||||
// const [errorMessage, setErrorMessage] = useState<string>();
|
||||
// const [restartNeeded, setRestartNeeded] = useState<boolean>(false);
|
||||
// const [origData, setOrigData] = useState<D>();
|
||||
// const [dirtyFlags, setDirtyFlags] = useState<string[]>([]);
|
||||
// const blocker = useBlocker(dirtyFlags.length !== 0);
|
||||
// const {
|
||||
// data,
|
||||
// send: readData,
|
||||
// update: updateData
|
||||
// } = useRequest(read()).onComplete((event) => {
|
||||
// setOrigData(event.data as D);
|
||||
// });
|
||||
// const { loading: saving, send: writeData } = useRequest(
|
||||
// (newData: D) => update(newData),
|
||||
// { immediate: false }
|
||||
// ).onSuccess(() => {
|
||||
// toast.success(LL.UPDATED_OF(LL.SETTINGS(1)));
|
||||
// setDirtyFlags([]);
|
||||
// });
|
||||
// const updateDataValue = (new_data: D) => {
|
||||
// updateData({ data: new_data });
|
||||
// };
|
||||
// const loadData = async () => {
|
||||
// setDirtyFlags([]);
|
||||
// setErrorMessage(undefined);
|
||||
// await readData().catch((error: Error) => {
|
||||
// toast.error(error.message);
|
||||
// setErrorMessage(error.message);
|
||||
// });
|
||||
// };
|
||||
// const saveData = async () => {
|
||||
// if (!data) {
|
||||
// return;
|
||||
// }
|
||||
// setRestartNeeded(false);
|
||||
// setErrorMessage(undefined);
|
||||
// setDirtyFlags([]);
|
||||
// setOrigData(data as D);
|
||||
// await writeData(data as D).catch((error: Error) => {
|
||||
// if (error.message === 'Reboot required') {
|
||||
// setRestartNeeded(true);
|
||||
// } else {
|
||||
// toast.error(error.message);
|
||||
// setErrorMessage(error.message);
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
// return {
|
||||
// loadData,
|
||||
// saveData,
|
||||
// saving: saving as boolean,
|
||||
// updateDataValue,
|
||||
// data: data as D, // Explicitly define the type of 'data'
|
||||
// origData: origData as D, // Explicitly define the type of 'origData' to 'D'
|
||||
// dirtyFlags,
|
||||
// setDirtyFlags,
|
||||
// setOrigData,
|
||||
// blocker,
|
||||
// errorMessage,
|
||||
// restartNeeded
|
||||
// } as const;
|
||||
// };
|
||||
import { useState } from 'react';
|
||||
import { useBlocker } from 'react-router-dom';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import type { AlovaGenerics, Method } from 'alova';
|
||||
import { useRequest } from 'alova/client';
|
||||
import { type Method, useRequest } from 'alova';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
|
||||
export interface RestRequestOptions<D> {
|
||||
read: () => Method<AlovaGenerics>;
|
||||
update: (value: D) => Method<AlovaGenerics>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
read: () => Method<any, any, any, any, any, any, any>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
update: (value: D) => Method<any, any, any, any, any, any, any>;
|
||||
}
|
||||
|
||||
export const useRest = <D>({ read, update }: RestRequestOptions<D>) => {
|
||||
@@ -24,23 +100,29 @@ export const useRest = <D>({ read, update }: RestRequestOptions<D>) => {
|
||||
const {
|
||||
data,
|
||||
send: readData,
|
||||
update: updateData
|
||||
} = useRequest(read()).onComplete((event) => {
|
||||
setOrigData(event.data as D);
|
||||
});
|
||||
update: updateData,
|
||||
onComplete: onReadComplete
|
||||
} = useRequest(read());
|
||||
|
||||
const { loading: saving, send: writeData } = useRequest(
|
||||
(newData: D) => update(newData),
|
||||
{ immediate: false }
|
||||
).onSuccess(() => {
|
||||
toast.success(LL.UPDATED_OF(LL.SETTINGS(1)));
|
||||
setDirtyFlags([]);
|
||||
});
|
||||
const {
|
||||
loading: saving,
|
||||
send: writeData,
|
||||
onSuccess: onWriteSuccess
|
||||
} = useRequest((newData: D) => update(newData), { immediate: false });
|
||||
|
||||
const updateDataValue = (new_data: D) => {
|
||||
updateData({ data: new_data });
|
||||
};
|
||||
|
||||
onWriteSuccess(() => {
|
||||
toast.success(LL.UPDATED_OF(LL.SETTINGS(1)));
|
||||
setDirtyFlags([]);
|
||||
});
|
||||
|
||||
onReadComplete((event) => {
|
||||
setOrigData(event.data as D);
|
||||
});
|
||||
|
||||
const loadData = async () => {
|
||||
setDirtyFlags([]);
|
||||
setErrorMessage(undefined);
|
||||
|
||||
Reference in New Issue
Block a user