mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 00:09:51 +03:00
alova update #6
This commit is contained in:
@@ -1,11 +1,9 @@
|
||||
import { AXIOS } from './endpoints';
|
||||
import { AXIOS, alovaInstance } from './endpoints';
|
||||
import type { AxiosPromise } from 'axios';
|
||||
|
||||
import type { APSettings, APStatus } from 'types';
|
||||
|
||||
export function readAPStatus(): AxiosPromise<APStatus> {
|
||||
return AXIOS.get('/apStatus');
|
||||
}
|
||||
export const readAPStatus = () => alovaInstance.Get<APStatus>('/apStatus');
|
||||
|
||||
export function readAPSettings(): AxiosPromise<APSettings> {
|
||||
return AXIOS.get('/apSettings');
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { xhrRequestAdapter } from '@alova/adapter-xhr';
|
||||
import { createAlova } from 'alova';
|
||||
// import GlobalFetch from 'alova/GlobalFetch';
|
||||
import ReactHook from 'alova/react';
|
||||
import axios from 'axios';
|
||||
import { unpack } from '../api/unpack';
|
||||
@@ -23,21 +22,21 @@ export const EVENT_SOURCE_ROOT = location.protocol + '//' + location.host + ES_B
|
||||
export const alovaInstance = createAlova({
|
||||
baseURL: '/rest/',
|
||||
statesHook: ReactHook,
|
||||
timeout: 50000,
|
||||
requestAdapter: xhrRequestAdapter(),
|
||||
// requestAdapter: GlobalFetch(),
|
||||
beforeRequest(method) {
|
||||
// TODO check if bearer works
|
||||
if (localStorage.getItem(ACCESS_TOKEN)) {
|
||||
method.config.headers.token = 'Bearer ' + localStorage.getItem(ACCESS_TOKEN);
|
||||
method.config.headers.Authorization = 'Bearer ' + localStorage.getItem(ACCESS_TOKEN);
|
||||
}
|
||||
},
|
||||
|
||||
responded: {
|
||||
onSuccess: async (response) => {
|
||||
if (response.status === 400) {
|
||||
if (response.status == 202) {
|
||||
throw new Error('Reboot required');
|
||||
} else if (response.status === 400) {
|
||||
throw new Error('Invalid command');
|
||||
}
|
||||
if (response.status >= 400) {
|
||||
} else if (response.status >= 400) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
const data = await response.data;
|
||||
|
||||
@@ -3,6 +3,7 @@ import DeviceHubIcon from '@mui/icons-material/DeviceHub';
|
||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
|
||||
import { Avatar, Button, Divider, List, ListItem, ListItemAvatar, ListItemText, useTheme } from '@mui/material';
|
||||
import { useRequest } from 'alova';
|
||||
import type { Theme } from '@mui/material';
|
||||
import type { FC } from 'react';
|
||||
|
||||
@@ -12,7 +13,6 @@ import { ButtonRow, FormLoader, SectionContent } from 'components';
|
||||
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { APNetworkStatus } from 'types';
|
||||
import { useRest } from 'utils';
|
||||
|
||||
export const apStatusHighlight = ({ status }: APStatus, theme: Theme) => {
|
||||
switch (status) {
|
||||
@@ -28,7 +28,8 @@ export const apStatusHighlight = ({ status }: APStatus, theme: Theme) => {
|
||||
};
|
||||
|
||||
const APStatusForm: FC = () => {
|
||||
const { loadData, data, errorMessage } = useRest<APStatus>({ read: APApi.readAPStatus });
|
||||
// TODO missing update!
|
||||
const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus());
|
||||
|
||||
const { LL } = useI18nContext();
|
||||
|
||||
@@ -49,7 +50,7 @@ const APStatusForm: FC = () => {
|
||||
|
||||
const content = () => {
|
||||
if (!data) {
|
||||
return <FormLoader onRetry={loadData} errorMessage={errorMessage} />;
|
||||
return <FormLoader onRetry={loadData} errorMessage={error?.message} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -39,6 +39,8 @@ export const mqttQueueHighlight = ({ mqtt_queued }: MqttStatus, theme: Theme) =>
|
||||
};
|
||||
|
||||
const MqttStatusForm: FC = () => {
|
||||
// TODO missing update!
|
||||
|
||||
const { loadData, data, errorMessage } = useRest<MqttStatus>({ read: MqttApi.readMqttStatus });
|
||||
|
||||
const { LL } = useI18nContext();
|
||||
|
||||
@@ -59,6 +59,8 @@ const IPs = (status: NetworkStatus) => {
|
||||
};
|
||||
|
||||
const NetworkStatusForm: FC = () => {
|
||||
// TODO missing update!
|
||||
|
||||
const { loadData, data, errorMessage } = useRest<NetworkStatus>({ read: NetworkApi.readNetworkStatus });
|
||||
|
||||
const { LL } = useI18nContext();
|
||||
|
||||
@@ -52,6 +52,8 @@ export const ntpStatusHighlight = ({ status }: NTPStatus, theme: Theme) => {
|
||||
};
|
||||
|
||||
const NTPStatusForm: FC = () => {
|
||||
// TODO missing update!
|
||||
|
||||
const { loadData, data, errorMessage } = useRest<NTPStatus>({ read: NTPApi.readNTPStatus });
|
||||
const [localTime, setLocalTime] = useState<string>('');
|
||||
const [settingTime, setSettingTime] = useState<boolean>(false);
|
||||
|
||||
@@ -49,6 +49,8 @@ const levelLabel = (level: LogLevel) => {
|
||||
const SystemLog: FC = () => {
|
||||
const { LL } = useI18nContext();
|
||||
|
||||
// TODO missing update!
|
||||
|
||||
const { loadData, data, setData, origData, dirtyFlags, blocker, setDirtyFlags, setOrigData } = useRest<LogSettings>({
|
||||
read: SystemApi.readLogSettings
|
||||
});
|
||||
|
||||
@@ -53,6 +53,8 @@ const SystemStatusForm: FC = () => {
|
||||
const { LL } = useI18nContext();
|
||||
const [restarting, setRestarting] = useState<boolean>();
|
||||
|
||||
// TODO missing update!
|
||||
|
||||
const { loadData, data, errorMessage } = useRest<SystemStatus>({ read: SystemApi.readSystemStatus });
|
||||
|
||||
const { me } = useContext(AuthenticatedContext);
|
||||
|
||||
@@ -51,7 +51,6 @@ const de: Translation = {
|
||||
REMOVE: 'Entfernen',
|
||||
PROBLEM_UPDATING: 'Problem beim Aktualisieren',
|
||||
PROBLEM_LOADING: 'Problem beim Laden',
|
||||
HTTP_ERROR: 'Error {0}', // TODO translate
|
||||
ANALOG_SENSOR: 'Analogsensor',
|
||||
ANALOG_SENSORS: 'Analogsensoren',
|
||||
SETTINGS: 'Einstellungen',
|
||||
|
||||
@@ -51,7 +51,6 @@ const en: Translation = {
|
||||
REMOVE: 'Remove',
|
||||
PROBLEM_UPDATING: 'Problem updating',
|
||||
PROBLEM_LOADING: 'Problem loading',
|
||||
HTTP_ERROR: 'Error {0}',
|
||||
ANALOG_SENSOR: 'Analog Sensor',
|
||||
ANALOG_SENSORS: 'Analog Sensors',
|
||||
SETTINGS: 'Settings',
|
||||
|
||||
@@ -51,7 +51,6 @@ const fr: Translation = {
|
||||
REMOVE: 'Enlever',
|
||||
PROBLEM_UPDATING: 'Problème lors de la mise à jour',
|
||||
PROBLEM_LOADING: 'Problème lors du chargement',
|
||||
HTTP_ERROR: 'Error {0}', // TODO translate
|
||||
ANALOG_SENSOR: 'Capteur analogique',
|
||||
ANALOG_SENSORS: 'Capteurs analogiques',
|
||||
SETTINGS: 'Paramètres',
|
||||
|
||||
@@ -51,7 +51,6 @@ const nl: Translation = {
|
||||
REMOVE: 'Verwijderen',
|
||||
PROBLEM_UPDATING: 'Probleem met updaten',
|
||||
PROBLEM_LOADING: 'Probleem met laden',
|
||||
HTTP_ERROR: 'Error {0}', // TODO translate
|
||||
ANALOG_SENSOR: 'Analoge sensor',
|
||||
ANALOG_SENSORS: 'Analoge Sensoren',
|
||||
SETTINGS: 'Instellingen',
|
||||
|
||||
@@ -51,7 +51,6 @@ const no: Translation = {
|
||||
REMOVE: 'Fjern',
|
||||
PROBLEM_UPDATING: 'Problem med oppdatering',
|
||||
PROBLEM_LOADING: 'Problem med opplasting',
|
||||
HTTP_ERROR: 'Error {0}', // TODO translate
|
||||
ANALOG_SENSOR: 'Analog Sensor',
|
||||
ANALOG_SENSORS: 'Analoge Sensorer',
|
||||
SETTINGS: 'Innstillinger',
|
||||
|
||||
@@ -51,7 +51,6 @@ const pl: BaseTranslation = {
|
||||
REMOVE: 'Usuń',
|
||||
PROBLEM_UPDATING: 'Problem z uaktualnieniem!',
|
||||
PROBLEM_LOADING: 'Problem z załadowaniem!',
|
||||
HTTP_ERROR: 'Error {0}', // TODO translate
|
||||
ANALOG_SENSOR: '{{u|u||ustawienia u|ustawień u}}rządzeni{{a podłączonego do EMS-ESP|e||a podłączonego do EMS-ESP|a podłączonego do EMS-ESP}}',
|
||||
ANALOG_SENSORS: 'Urządzenia podłączone do EMS-ESP',
|
||||
SETTINGS: 'ustawienia',
|
||||
|
||||
@@ -51,7 +51,6 @@ const sv: Translation = {
|
||||
REMOVE: 'Ta bort',
|
||||
PROBLEM_UPDATING: 'Problem vid uppdatering',
|
||||
PROBLEM_LOADING: 'Problem vid hämtning',
|
||||
HTTP_ERROR: 'Error {0}', // TODO translate
|
||||
ANALOG_SENSOR: 'Analog Sensor',
|
||||
ANALOG_SENSORS: 'Analoga Sensorer',
|
||||
SETTINGS: 'Inställningar',
|
||||
|
||||
@@ -51,7 +51,6 @@ const tr: Translation = {
|
||||
REMOVE: 'Kaldır',
|
||||
PROBLEM_UPDATING: 'Güncelleme Sorunu',
|
||||
PROBLEM_LOADING: 'Yükleme Sorunu',
|
||||
HTTP_ERROR: 'Error {0}', // TODO translate
|
||||
ANALOG_SENSOR: 'Analog Sensör',
|
||||
ANALOG_SENSORS: 'Analog Sensörler',
|
||||
SETTINGS: 'Ayarlar',
|
||||
|
||||
@@ -69,7 +69,7 @@ const DashboardDevices: FC = () => {
|
||||
immediate: true
|
||||
});
|
||||
|
||||
const { data: deviceData, send: readDeviceData } = useRequest((id) => EMSESP.readDeviceData(id), {
|
||||
const { data: deviceData, send: readDeviceData } = useRequest((data) => EMSESP.readDeviceData(data), {
|
||||
initialData: {
|
||||
data: []
|
||||
},
|
||||
@@ -77,12 +77,9 @@ const DashboardDevices: FC = () => {
|
||||
immediate: false
|
||||
});
|
||||
|
||||
const { loading: submitting, send: writeDeviceValue } = useRequest(
|
||||
(id: number, deviceValue: DeviceValue) => EMSESP.writeDeviceValue(id, deviceValue),
|
||||
{
|
||||
immediate: false
|
||||
}
|
||||
);
|
||||
const { loading: submitting, send: writeDeviceValue } = useRequest((data) => EMSESP.writeDeviceValue(data), {
|
||||
immediate: false
|
||||
});
|
||||
|
||||
useLayoutEffect(() => {
|
||||
function updateSize() {
|
||||
@@ -350,7 +347,7 @@ const DashboardDevices: FC = () => {
|
||||
toast.success(LL.WRITE_CMD_SENT());
|
||||
})
|
||||
.catch((error) => {
|
||||
toast.error(LL.HTTP_ERROR(error));
|
||||
toast.error(error.message);
|
||||
})
|
||||
.finally(async () => {
|
||||
setDeviceValueDialogOpen(false);
|
||||
|
||||
@@ -64,6 +64,8 @@ const showQuality = (stat: Stat) => {
|
||||
};
|
||||
|
||||
const DashboardStatus: FC = () => {
|
||||
// TODO missing update!
|
||||
|
||||
const { loadData, data, errorMessage } = useRest<Status>({ read: EMSESP.readStatus });
|
||||
|
||||
const { LL } = useI18nContext();
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
|
||||
import RestartMonitor from 'framework/system/RestartMonitor';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { numberValue, extractErrorMessage, updateValueDirty, useRest } from 'utils';
|
||||
import { numberValue, extractErrorMessage, updateValueDirty, useRest2 } from 'utils';
|
||||
import { validate } from 'validators';
|
||||
|
||||
export function boardProfileSelectItems() {
|
||||
@@ -47,7 +47,7 @@ const SettingsApplication: FC = () => {
|
||||
blocker,
|
||||
errorMessage,
|
||||
restartNeeded
|
||||
} = useRest<Settings>({
|
||||
} = useRest2<Settings>({
|
||||
read: EMSESP.readSettings,
|
||||
update: EMSESP.writeSettings
|
||||
});
|
||||
@@ -60,6 +60,12 @@ const SettingsApplication: FC = () => {
|
||||
const [fieldErrors, setFieldErrors] = useState<ValidateFieldsError>();
|
||||
const [processingBoard, setProcessingBoard] = useState<boolean>(false);
|
||||
|
||||
// TODO remove - just for testing loaddata
|
||||
// useEffect(() => {
|
||||
// void loadData();
|
||||
// }, []);
|
||||
|
||||
// TODO replace with Alova!
|
||||
const updateBoardProfile = async (boardProfile: string) => {
|
||||
setProcessingBoard(true);
|
||||
try {
|
||||
|
||||
@@ -14,8 +14,7 @@ import type {
|
||||
WriteAnalogSensor,
|
||||
SensorData,
|
||||
Schedule,
|
||||
Entities,
|
||||
DeviceValue
|
||||
Entities
|
||||
} from './types';
|
||||
import type { AxiosPromise } from 'axios';
|
||||
import { AXIOS, AXIOS_API, AXIOS_BIN, alovaInstance } from 'api/endpoints';
|
||||
@@ -28,8 +27,11 @@ export const readDeviceData = (id: number) =>
|
||||
responseType: 'arraybuffer' // uses msgpack
|
||||
});
|
||||
|
||||
export const writeDeviceValue = (id: number, devicevalue: DeviceValue) =>
|
||||
alovaInstance.Post('/writeDeviceValue', { id, devicevalue });
|
||||
export const writeDeviceValue = (data: any) => alovaInstance.Post('/writeDeviceValue', data);
|
||||
|
||||
// SettingsApplication
|
||||
export const readSettings = () => alovaInstance.Get<Settings>('/settings');
|
||||
export const writeSettings = (data: any) => alovaInstance.Post('/settings', data);
|
||||
|
||||
//
|
||||
// TODO change below to use alova
|
||||
@@ -39,14 +41,6 @@ export function restart(): AxiosPromise<void> {
|
||||
return AXIOS.post('/restart');
|
||||
}
|
||||
|
||||
export function readSettings(): AxiosPromise<Settings> {
|
||||
return AXIOS.get('/settings');
|
||||
}
|
||||
|
||||
export function writeSettings(settings: Settings): AxiosPromise<Settings> {
|
||||
return AXIOS.post('/settings', settings); // call command
|
||||
}
|
||||
|
||||
// TODO change to GET
|
||||
export function getBoardProfile(boardProfile: BoardProfileName): AxiosPromise<BoardProfile> {
|
||||
return AXIOS.post('/boardProfile', boardProfile);
|
||||
|
||||
@@ -280,13 +280,6 @@ export interface APIcall {
|
||||
entity: string;
|
||||
id: any;
|
||||
}
|
||||
|
||||
// TODO can be removed?
|
||||
export interface WriteDeviceValue {
|
||||
id: number;
|
||||
devicevalue: DeviceValue;
|
||||
}
|
||||
|
||||
export interface WriteAnalogSensor {
|
||||
id: number;
|
||||
gpio: number;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
type UpdateEntity<S> = (state: (prevState: Readonly<S>) => S) => void;
|
||||
|
||||
export const numberValue = (value: number) => (isNaN(value) ? '' : value.toString());
|
||||
|
||||
export const extractEventValue = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@@ -13,6 +11,8 @@ export const extractEventValue = (event: React.ChangeEvent<HTMLInputElement>) =>
|
||||
}
|
||||
};
|
||||
|
||||
type UpdateEntity<S> = (state: (prevState: Readonly<S>) => S) => void;
|
||||
|
||||
export const updateValue =
|
||||
<S>(updateEntity: UpdateEntity<S>) =>
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@@ -23,10 +23,13 @@ export const updateValue =
|
||||
};
|
||||
|
||||
export const updateValueDirty =
|
||||
<S>(origData: any, dirtyFlags: any, setDirtyFlags: any, updateEntity: UpdateEntity<S>) =>
|
||||
<S>(origData: any, dirtyFlags: any, setDirtyFlags: any, updateEntity: any) =>
|
||||
// <S>(origData: any, dirtyFlags: any, setDirtyFlags: any, updateEntity: UpdateEntity<S>) =>
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const updated_value = extractEventValue(event);
|
||||
const name = event.target.name;
|
||||
|
||||
// TODO not sure how this is even working!!
|
||||
updateEntity((prevState) => ({
|
||||
...prevState,
|
||||
[name]: updated_value
|
||||
@@ -34,6 +37,11 @@ export const updateValueDirty =
|
||||
|
||||
const arr: string[] = dirtyFlags;
|
||||
|
||||
// TODO remove comments
|
||||
// console.log('updating ' + name + ' to ' + updated_value); // TODO remove
|
||||
// console.log('dirtyFlags:', dirtyFlags); // TODO remove
|
||||
// console.log('binding.ts origData:', origData); // TODO remove
|
||||
|
||||
if (origData[name] !== updated_value) {
|
||||
if (!arr.includes(name)) {
|
||||
arr.push(name);
|
||||
|
||||
@@ -4,4 +4,6 @@ export * from './route';
|
||||
export * from './submit';
|
||||
export * from './time';
|
||||
export * from './useRest';
|
||||
// TODO remove
|
||||
export * from './useRest2';
|
||||
export * from './props';
|
||||
|
||||
92
interface/src/utils/useRest2.ts
Normal file
92
interface/src/utils/useRest2.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { useRequest, type Method } from 'alova';
|
||||
import { useState } from 'react';
|
||||
import { unstable_useBlocker as useBlocker } from 'react-router-dom';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import type { AlovaXHRRequestConfig, AlovaXHRResponse, AlovaXHRResponseHeaders } from '@alova/adapter-xhr';
|
||||
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
|
||||
export interface RestRequestOptions<D> {
|
||||
read: () => Method<any, any, any, any, any, AlovaXHRResponse<any>, AlovaXHRResponseHeaders>;
|
||||
update: (
|
||||
value: D
|
||||
) => Method<any, unknown, unknown, unknown, AlovaXHRRequestConfig, AlovaXHRResponse<any>, AlovaXHRResponseHeaders>;
|
||||
}
|
||||
|
||||
export const useRest2 = <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: data, send: readData, update: updateData, onComplete: onReadComplete } = useRequest(read());
|
||||
|
||||
const {
|
||||
loading: saving,
|
||||
send: writeData,
|
||||
onSuccess: onWriteSuccess
|
||||
} = useRequest((newData: D) => update(newData), { immediate: false });
|
||||
|
||||
const setData = (new_data: D) => {
|
||||
console.log('SET DATA'); // TODO remove console
|
||||
console.log('new_data:', new_data); // TODO remove console
|
||||
updateData({
|
||||
data: new_data
|
||||
});
|
||||
};
|
||||
|
||||
onWriteSuccess(() => {
|
||||
toast.success(LL.UPDATED_OF(LL.SETTINGS()));
|
||||
setDirtyFlags([]);
|
||||
});
|
||||
|
||||
onReadComplete((event) => {
|
||||
setOrigData(event.data); // make a copy
|
||||
});
|
||||
|
||||
const loadData = async () => {
|
||||
setDirtyFlags([]);
|
||||
setErrorMessage(undefined);
|
||||
await readData().catch((error) => {
|
||||
toast.error(error.message);
|
||||
setErrorMessage(error.message);
|
||||
});
|
||||
};
|
||||
|
||||
const saveData = async () => {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
console.log('SAVE DATA'); // TODO remove console
|
||||
setRestartNeeded(false);
|
||||
setErrorMessage(undefined);
|
||||
await writeData(data).catch((error) => {
|
||||
if (error.message === 'Reboot required') {
|
||||
setRestartNeeded(true);
|
||||
} else {
|
||||
toast.error(error.message);
|
||||
setErrorMessage(error.message);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
loadData,
|
||||
saveData,
|
||||
saving,
|
||||
setData,
|
||||
data,
|
||||
origData,
|
||||
dirtyFlags,
|
||||
setDirtyFlags,
|
||||
setOrigData,
|
||||
blocker,
|
||||
errorMessage,
|
||||
restartNeeded
|
||||
} as const;
|
||||
};
|
||||
Reference in New Issue
Block a user