alova - update comments

This commit is contained in:
proddy
2023-06-15 16:08:25 +02:00
parent adc4760b5f
commit f58dbf6ec1
20 changed files with 117 additions and 137 deletions

View File

@@ -33,6 +33,7 @@ const AuthenticatedRouting: FC = () => {
); );
useEffect(() => { useEffect(() => {
// TODO how to replace AXIOS.interceptors.response.use ???
const axiosHandlerId = AXIOS.interceptors.response.use((response) => response, handleApiResponseError); const axiosHandlerId = AXIOS.interceptors.response.use((response) => response, handleApiResponseError);
return () => AXIOS.interceptors.response.eject(axiosHandlerId); return () => AXIOS.interceptors.response.eject(axiosHandlerId);
}, [handleApiResponseError]); }, [handleApiResponseError]);

View File

@@ -9,10 +9,10 @@ import type { Me, SignInRequest, SignInResponse } from 'types';
export const SIGN_IN_PATHNAME = 'loginPathname'; export const SIGN_IN_PATHNAME = 'loginPathname';
export const SIGN_IN_SEARCH = 'loginSearch'; export const SIGN_IN_SEARCH = 'loginSearch';
// TODO move to Alova
export function verifyAuthorization(): AxiosPromise<void> { export function verifyAuthorization(): AxiosPromise<void> {
return AXIOS.get('/verifyAuthorization'); return AXIOS.get('/verifyAuthorization');
} }
export function signIn(request: SignInRequest): AxiosPromise<SignInResponse> { export function signIn(request: SignInRequest): AxiosPromise<SignInResponse> {
return AXIOS.post('/signIn', request); return AXIOS.post('/signIn', request);
} }

View File

@@ -4,23 +4,20 @@ import ReactHook from 'alova/react';
import axios from 'axios'; import axios from 'axios';
import { unpack } from '../api/unpack'; import { unpack } from '../api/unpack';
// TODO axios can be removed
import type { AxiosPromise, CancelToken, AxiosProgressEvent } from 'axios'; import type { AxiosPromise, CancelToken, AxiosProgressEvent } from 'axios';
export const REST_BASE_URL = '/rest/'; export const REST_BASE_URL = '/rest/';
export const API_BASE_URL = '/api/'; export const API_BASE_URL = '/api/';
export const ACCESS_TOKEN = 'access_token'; export const ACCESS_TOKEN = 'access_token';
const location = window.location; const host = window.location.host;
const webProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; export const WEB_SOCKET_ROOT = 'ws://' + host + '/ws/';
export const WS_BASE_URL = '/ws/'; export const EVENT_SOURCE_ROOT = 'http://' + host + '/es/';
export const ES_BASE_URL = '/es/';
export const WEB_SOCKET_ROOT = webProtocol + '//' + location.host + WS_BASE_URL;
export const EVENT_SOURCE_ROOT = location.protocol + '//' + location.host + ES_BASE_URL;
export const alovaInstance = createAlova({ export const alovaInstance = createAlova({
statesHook: ReactHook, statesHook: ReactHook,
timeout: 5000, timeout: 3000,
requestAdapter: xhrRequestAdapter(), requestAdapter: xhrRequestAdapter(),
beforeRequest(method) { beforeRequest(method) {
if (localStorage.getItem(ACCESS_TOKEN)) { if (localStorage.getItem(ACCESS_TOKEN)) {

View File

@@ -3,6 +3,7 @@ import type { AxiosPromise } from 'axios';
import type { Features } from 'types'; import type { Features } from 'types';
// TODO move to Alova
export function readFeatures(): AxiosPromise<Features> { export function readFeatures(): AxiosPromise<Features> {
return AXIOS.get('/features'); return AXIOS.get('/features');
} }

View File

@@ -2,6 +2,7 @@ import { AXIOS } from './endpoints';
import type { AxiosPromise } from 'axios'; import type { AxiosPromise } from 'axios';
import type { MqttSettings, MqttStatus } from 'types'; import type { MqttSettings, MqttStatus } from 'types';
// TODO move to alova
export function readMqttStatus(): AxiosPromise<MqttStatus> { export function readMqttStatus(): AxiosPromise<MqttStatus> {
return AXIOS.get('/mqttStatus'); return AXIOS.get('/mqttStatus');
} }

View File

@@ -3,6 +3,7 @@ import type { AxiosPromise } from 'axios';
import type { WiFiNetworkList, NetworkSettings, NetworkStatus } from 'types'; import type { WiFiNetworkList, NetworkSettings, NetworkStatus } from 'types';
// TODO move to alova
export function readNetworkStatus(): AxiosPromise<NetworkStatus> { export function readNetworkStatus(): AxiosPromise<NetworkStatus> {
return AXIOS.get('/networkStatus'); return AXIOS.get('/networkStatus');
} }

View File

@@ -2,6 +2,7 @@ import { AXIOS } from './endpoints';
import type { AxiosPromise } from 'axios'; import type { AxiosPromise } from 'axios';
import type { NTPSettings, NTPStatus, Time } from 'types'; import type { NTPSettings, NTPStatus, Time } from 'types';
// TODO move to Alova
export function readNTPStatus(): AxiosPromise<NTPStatus> { export function readNTPStatus(): AxiosPromise<NTPStatus> {
return AXIOS.get('/ntpStatus'); return AXIOS.get('/ntpStatus');
} }

View File

@@ -3,6 +3,7 @@ import type { AxiosPromise } from 'axios';
import type { SecuritySettings, Token } from 'types'; import type { SecuritySettings, Token } from 'types';
// TODO move to Alova
export function readSecuritySettings(): AxiosPromise<SecuritySettings> { export function readSecuritySettings(): AxiosPromise<SecuritySettings> {
return AXIOS.get('/securitySettings'); return AXIOS.get('/securitySettings');
} }

View File

@@ -4,6 +4,7 @@ import type { AxiosPromise } from 'axios';
import type { OTASettings, SystemStatus, LogSettings, LogEntries } from 'types'; import type { OTASettings, SystemStatus, LogSettings, LogEntries } from 'types';
// TODO move to Alova
export function readSystemStatus(timeout?: number): AxiosPromise<SystemStatus> { export function readSystemStatus(timeout?: number): AxiosPromise<SystemStatus> {
return AXIOS.get('/systemStatus', { timeout }); return AXIOS.get('/systemStatus', { timeout });
} }

View File

@@ -38,7 +38,7 @@ export const mqttQueueHighlight = ({ mqtt_queued }: MqttStatus, theme: Theme) =>
}; };
const MqttStatusForm: FC = () => { const MqttStatusForm: FC = () => {
// TODO replace with const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus()); // TODO replace with const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus);
const { loadData, data, errorMessage } = useRest<MqttStatus>({ read: MqttApi.readMqttStatus }); const { loadData, data, errorMessage } = useRest<MqttStatus>({ read: MqttApi.readMqttStatus });
const { LL } = useI18nContext(); const { LL } = useI18nContext();

View File

@@ -59,7 +59,7 @@ const IPs = (status: NetworkStatus) => {
}; };
const NetworkStatusForm: FC = () => { const NetworkStatusForm: FC = () => {
// TODO replace with const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus()); // TODO replace with const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus);
const { loadData, data, errorMessage } = useRest<NetworkStatus>({ read: NetworkApi.readNetworkStatus }); const { loadData, data, errorMessage } = useRest<NetworkStatus>({ read: NetworkApi.readNetworkStatus });
const { LL } = useI18nContext(); const { LL } = useI18nContext();

View File

@@ -52,7 +52,7 @@ export const ntpStatusHighlight = ({ status }: NTPStatus, theme: Theme) => {
}; };
const NTPStatusForm: FC = () => { const NTPStatusForm: FC = () => {
// TODO replace with const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus()); // TODO replace with const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus);
const { loadData, data, errorMessage } = useRest<NTPStatus>({ read: NTPApi.readNTPStatus }); const { loadData, data, errorMessage } = useRest<NTPStatus>({ read: NTPApi.readNTPStatus });
const [localTime, setLocalTime] = useState<string>(''); const [localTime, setLocalTime] = useState<string>('');

View File

@@ -49,7 +49,7 @@ const levelLabel = (level: LogLevel) => {
const SystemLog: FC = () => { const SystemLog: FC = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
// TODO replace with const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus()); // TODO replace with const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus);
const { loadData, data, setData, origData, dirtyFlags, blocker, setDirtyFlags, setOrigData } = useRest<LogSettings>({ const { loadData, data, setData, origData, dirtyFlags, blocker, setDirtyFlags, setOrigData } = useRest<LogSettings>({
read: SystemApi.readLogSettings read: SystemApi.readLogSettings
}); });

View File

@@ -53,7 +53,7 @@ const SystemStatusForm: FC = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
const [restarting, setRestarting] = useState<boolean>(); const [restarting, setRestarting] = useState<boolean>();
// TODO replace with const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus()); // TODO replace with const { data: data, send: loadData, error } = useRequest(APApi.readAPStatus);
const { loadData, data, errorMessage } = useRest<SystemStatus>({ read: SystemApi.readSystemStatus }); const { loadData, data, errorMessage } = useRest<SystemStatus>({ read: SystemApi.readSystemStatus });
const { me } = useContext(AuthenticatedContext); const { me } = useContext(AuthenticatedContext);

View File

@@ -65,11 +65,7 @@ const SettingsCustomization: FC = () => {
const { send: writeCustomEntities } = useRequest((data) => EMSESP.writeCustomEntities(data), { immediate: false }); const { send: writeCustomEntities } = useRequest((data) => EMSESP.writeCustomEntities(data), { immediate: false });
const { const { send: readDeviceEntities, onSuccess: onSuccess } = useRequest((data) => EMSESP.readDeviceEntities(data), {
send: readDeviceEntities,
update: updateDeviceEntities,
onSuccess: onSuccess
} = useRequest((data) => EMSESP.readDeviceEntities(data), {
initialData: [], initialData: [],
immediate: false, immediate: false,
force: true force: true
@@ -236,8 +232,7 @@ const SettingsCustomization: FC = () => {
}; };
const maskDisabled = (set: boolean) => { const maskDisabled = (set: boolean) => {
// TODO fix update! setDeviceEntities(
updateDeviceEntities(
deviceEntities.map(function (de) { deviceEntities.map(function (de) {
if ((de.m & selectedFilters || !selectedFilters) && de.id.toLowerCase().includes(search.toLowerCase())) { if ((de.m & selectedFilters || !selectedFilters) && de.id.toLowerCase().includes(search.toLowerCase())) {
return { return {

View File

@@ -4,7 +4,8 @@ import WarningIcon from '@mui/icons-material/Warning';
import { Button, Typography, Box } from '@mui/material'; import { Button, Typography, Box } from '@mui/material';
import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table'; import { Table, Header, HeaderRow, HeaderCell, Body, Row, Cell } from '@table-library/react-table-library/table';
import { useTheme } from '@table-library/react-table-library/theme'; import { useTheme } from '@table-library/react-table-library/theme';
import { useState, useEffect, useCallback } from 'react'; import { updateState, useRequest } from 'alova';
import { useState, useCallback } from 'react';
import { unstable_useBlocker as useBlocker } from 'react-router-dom'; import { unstable_useBlocker as useBlocker } from 'react-router-dom';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
@@ -18,18 +19,25 @@ import type { FC } from 'react';
import { ButtonRow, FormLoader, SectionContent, BlockNavigation } from 'components'; import { ButtonRow, FormLoader, SectionContent, BlockNavigation } from 'components';
import { useI18nContext } from 'i18n/i18n-react'; import { useI18nContext } from 'i18n/i18n-react';
import { extractErrorMessage } from 'utils';
const SettingsEntities: FC = () => { const SettingsEntities: FC = () => {
const { LL } = useI18nContext(); const { LL } = useI18nContext();
const [numChanges, setNumChanges] = useState<number>(0); const [numChanges, setNumChanges] = useState<number>(0);
const blocker = useBlocker(numChanges !== 0); const blocker = useBlocker(numChanges !== 0);
const [entities, setEntities] = useState<EntityItem[]>();
const [selectedEntityItem, setSelectedEntityItem] = useState<EntityItem>(); const [selectedEntityItem, setSelectedEntityItem] = useState<EntityItem>();
const [errorMessage, setErrorMessage] = useState<string>();
const [creating, setCreating] = useState<boolean>(false); const [creating, setCreating] = useState<boolean>(false);
const [dialogOpen, setDialogOpen] = useState<boolean>(false); const [dialogOpen, setDialogOpen] = useState<boolean>(false);
const {
data: entities,
send: fetchEntities,
error
} = useRequest(EMSESP.readEntities, {
initialData: []
});
const { send: writeEntities } = useRequest((data) => EMSESP.writeEntities(data), { immediate: false });
function hasEntityChanged(ei: EntityItem) { function hasEntityChanged(ei: EntityItem) {
return ( return (
ei.id !== ei.o_id || ei.id !== ei.o_id ||
@@ -45,12 +53,6 @@ const SettingsEntities: FC = () => {
); );
} }
useEffect(() => {
if (entities) {
setNumChanges(entities ? entities.filter((ei) => hasEntityChanged(ei)).length : 0);
}
}, [entities]);
const entity_theme = useTheme({ const entity_theme = useTheme({
Table: ` Table: `
--data-table-library_grid-template-columns: repeat(1, minmax(60px, 1fr)) minmax(80px, auto) 80px 80px 80px; --data-table-library_grid-template-columns: repeat(1, minmax(60px, 1fr)) minmax(80px, auto) 80px 80px 80px;
@@ -105,38 +107,9 @@ const SettingsEntities: FC = () => {
` `
}); });
const fetchEntities = useCallback(async () => {
try {
const response = await EMSESP.readEntities();
setEntities(
response.data.entities.map((ei) => ({
...ei,
o_id: ei.id,
o_device_id: ei.device_id,
o_type_id: ei.type_id,
o_offset: ei.offset,
o_factor: ei.factor,
o_uom: ei.uom,
o_value_type: ei.value_type,
o_name: ei.name,
o_writeable: ei.writeable,
o_deleted: ei.deleted
}))
);
} catch (error) {
setErrorMessage(extractErrorMessage(error, LL.PROBLEM_LOADING()));
}
}, [LL]);
useEffect(() => {
void fetchEntities();
}, [fetchEntities]);
const saveEntities = async () => { const saveEntities = async () => {
if (entities) { await writeEntities(
try { entities
const response = await EMSESP.writeEntities({
entities: entities
.filter((ei) => !ei.deleted) .filter((ei) => !ei.deleted)
.map((condensed_ei) => ({ .map((condensed_ei) => ({
id: condensed_ei.id, id: condensed_ei.id,
@@ -149,18 +122,17 @@ const SettingsEntities: FC = () => {
writeable: condensed_ei.writeable, writeable: condensed_ei.writeable,
value_type: condensed_ei.value_type value_type: condensed_ei.value_type
})) }))
}); )
.then(() => {
if (response.status === 200) {
toast.success(LL.ENTITIES_UPDATED()); toast.success(LL.ENTITIES_UPDATED());
} else { })
toast.error(LL.PROBLEM_UPDATING()); .catch((err) => {
} toast.error(err.message);
})
.finally(async () => {
await fetchEntities(); await fetchEntities();
} catch (error) { setNumChanges(0);
toast.error(extractErrorMessage(error, LL.PROBLEM_UPDATING())); });
}
}
}; };
const editEntityItem = useCallback((ei: EntityItem) => { const editEntityItem = useCallback((ei: EntityItem) => {
@@ -175,11 +147,14 @@ const SettingsEntities: FC = () => {
const onDialogSave = (updatedItem: EntityItem) => { const onDialogSave = (updatedItem: EntityItem) => {
setDialogOpen(false); setDialogOpen(false);
if (entities && creating) {
setEntities([...entities.filter((ei) => creating || ei.o_id !== updatedItem.o_id), updatedItem]); updateState('entities', (data) => {
} else { const new_data = creating
setEntities(entities?.map((ei) => (ei.id === updatedItem.id ? { ...ei, ...updatedItem } : ei))); ? [...data.filter((ei) => creating || ei.o_id !== updatedItem.o_id), updatedItem]
} : data.map((ei) => (ei.id === updatedItem.id ? { ...ei, ...updatedItem } : ei));
setNumChanges(new_data.filter((ei) => hasEntityChanged(ei)).length);
return new_data;
});
}; };
const addEntityItem = () => { const addEntityItem = () => {
@@ -215,7 +190,7 @@ const SettingsEntities: FC = () => {
const renderEntity = () => { const renderEntity = () => {
if (!entities) { if (!entities) {
return <FormLoader errorMessage={errorMessage} />; return <FormLoader onRetry={fetchEntities} errorMessage={error?.message} />;
} }
return ( return (

View File

@@ -10,10 +10,10 @@ import type {
SensorData, SensorData,
Entities, Entities,
DeviceData, DeviceData,
ScheduleItem ScheduleItem,
EntityItem
} from './types'; } from './types';
import type { AxiosPromise } from 'axios'; import { alovaInstance } from 'api/endpoints';
import { AXIOS, alovaInstance } from 'api/endpoints';
// DashboardDevices // DashboardDevices
export const readCoreData = () => alovaInstance.Get<CoreData>(`/rest/coreData`); export const readCoreData = () => alovaInstance.Get<CoreData>(`/rest/coreData`);
@@ -33,19 +33,6 @@ export const getBoardProfile = (boardProfile: string) =>
}); });
export const restart = () => alovaInstance.Post('/rest/restart'); export const restart = () => alovaInstance.Post('/rest/restart');
// SettingsCustomization
export const readDeviceEntities = (id: number) =>
alovaInstance.Get<DeviceEntity[]>('/rest/deviceEntities', {
params: { id },
responseType: 'arraybuffer',
transformData(data: any) {
return data.map((de: DeviceEntity) => ({ ...de, o_m: de.m, o_cn: de.cn, o_mi: de.mi, o_ma: de.ma }));
}
});
export const readDevices = () => alovaInstance.Get<Devices>('/rest/devices');
export const resetCustomizations = () => alovaInstance.Post('/rest/resetCustomizations');
export const writeCustomEntities = (data: any) => alovaInstance.Post('/rest/customEntities', data);
// DashboardSensors // DashboardSensors
export const readSensorData = () => alovaInstance.Get<SensorData>('/rest/sensorData'); export const readSensorData = () => alovaInstance.Get<SensorData>('/rest/sensorData');
export const writeTemperatureSensor = (ts: WriteTemperatureSensor) => export const writeTemperatureSensor = (ts: WriteTemperatureSensor) =>
@@ -65,6 +52,19 @@ export const getCustomizations = () => alovaInstance.Get('/rest/getCustomization
export const getEntities = () => alovaInstance.Get<Entities>('/rest/getEntities'); export const getEntities = () => alovaInstance.Get<Entities>('/rest/getEntities');
export const getSchedule = () => alovaInstance.Get('/rest/getSchedule'); export const getSchedule = () => alovaInstance.Get('/rest/getSchedule');
// SettingsCustomization
export const readDeviceEntities = (id: number) =>
alovaInstance.Get<DeviceEntity[]>('/rest/deviceEntities', {
params: { id },
responseType: 'arraybuffer',
transformData(data: any) {
return data.map((de: DeviceEntity) => ({ ...de, o_m: de.m, o_cn: de.cn, o_mi: de.mi, o_ma: de.ma }));
}
});
export const readDevices = () => alovaInstance.Get<Devices>('/rest/devices');
export const resetCustomizations = () => alovaInstance.Post('/rest/resetCustomizations');
export const writeCustomEntities = (data: any) => alovaInstance.Post('/rest/customEntities', data);
// SettingsScheduler // SettingsScheduler
export const readSchedule = () => export const readSchedule = () =>
alovaInstance.Get<ScheduleItem[]>('/rest/schedule', { alovaInstance.Get<ScheduleItem[]>('/rest/schedule', {
@@ -86,10 +86,23 @@ export const readSchedule = () =>
export const writeSchedule = (data: any) => alovaInstance.Post('/rest/schedule', data); export const writeSchedule = (data: any) => alovaInstance.Post('/rest/schedule', data);
// SettingsCustomization // SettingsCustomization
// TODO move last Entities* to Alova export const readEntities = () =>
export function readEntities(): AxiosPromise<Entities> { alovaInstance.Get<EntityItem[]>('/rest/entities', {
return AXIOS.get('/entities'); name: 'entities',
} transformData(data: any) {
export function writeEntities(entities: Entities): AxiosPromise<void> { return data.map((ei: EntityItem) => ({
return AXIOS.post('/entities', entities); ...ei,
o_id: ei.id,
o_device_id: ei.device_id,
o_type_id: ei.type_id,
o_offset: ei.offset,
o_factor: ei.factor,
o_uom: ei.uom,
o_value_type: ei.value_type,
o_name: ei.name,
o_writeable: ei.writeable,
o_deleted: ei.deleted
}));
} }
});
export const writeEntities = (data: any) => alovaInstance.Post('/rest/entities', data);

View File

@@ -90,7 +90,7 @@ export const schedulerItemValidation = () =>
new Schema({ new Schema({
name: [ name: [
{ {
// TODO name must be unique - add check // TODO validator: add check for unique name
required: true, required: true,
type: 'string', type: 'string',
pattern: /^[a-zA-Z0-9_\\.]{0,15}$/, pattern: /^[a-zA-Z0-9_\\.]{0,15}$/,

View File

@@ -28,7 +28,6 @@ export const updateValueDirty =
const updated_value = extractEventValue(event); const updated_value = extractEventValue(event);
const name = event.target.name; const name = event.target.name;
// TODO not sure how this is even working!!
updateDataValue((prevState) => ({ updateDataValue((prevState) => ({
...prevState, ...prevState,
[name]: updated_value [name]: updated_value
@@ -36,11 +35,6 @@ export const updateValueDirty =
const arr: string[] = dirtyFlags; const arr: string[] = dirtyFlags;
// TODO remove comments
// console.log('updating ' + name + ' to ' + updated_value);
// console.log('dirtyFlags:', dirtyFlags);
// console.log('binding.ts origData:', origData);
if (origData[name] !== updated_value) { if (origData[name] !== updated_value) {
if (!arr.includes(name)) { if (!arr.includes(name)) {
arr.push(name); arr.push(name);

View File

@@ -1780,9 +1780,9 @@ const emsesp_devicedata_99 = {
}; };
// CUSTOM ENTITIES // CUSTOM ENTITIES
let emsesp_entities = { let emsesp_entities = [
// entities: [] // entities: []
entities: [ // entities: [
{ {
id: 0, id: 0,
device_id: 8, device_id: 8,
@@ -1794,8 +1794,7 @@ let emsesp_entities = {
value_type: 1, value_type: 1,
writeable: true writeable: true
} }
] ];
};
// SCHEDULE // SCHEDULE
let emsesp_schedule = let emsesp_schedule =
@@ -2333,7 +2332,7 @@ rest_server.post(EMSESP_WRITE_SCHEDULE_ENDPOINT, (req, res) => {
rest_server.post(EMSESP_WRITE_ENTITIES_ENDPOINT, (req, res) => { rest_server.post(EMSESP_WRITE_ENTITIES_ENDPOINT, (req, res) => {
console.log('write entities'); console.log('write entities');
console.log(req.body.entities); console.log(req.body);
emsesp_entities = req.body; emsesp_entities = req.body;
res.sendStatus(200); res.sendStatus(200);
}); });