improved Configurtaion page responsiveness in frontend
This commit is contained in:
parent
e16fa59771
commit
988b714d57
|
|
@ -182,11 +182,13 @@ function SodioHomeInstallation(props: singleInstallationProps) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchDataForOneTime = async () => {
|
const fetchDataForOneTime = async () => {
|
||||||
var timeperiodToSearch = 200;
|
var timeperiodToSearch = 300; // 5 minutes to cover ~4 upload cycles
|
||||||
let res;
|
let res;
|
||||||
let timestampToFetch;
|
let timestampToFetch;
|
||||||
|
|
||||||
for (var i = timeperiodToSearch; i > 0; i -= 2) {
|
// Search from NOW backward to find the most recent data
|
||||||
|
// Step by 10 seconds - balances between finding files quickly and reducing 404s
|
||||||
|
for (var i = 0; i < timeperiodToSearch; i += 10) {
|
||||||
timestampToFetch = UnixTime.now().earlier(TimeSpan.fromSeconds(i));
|
timestampToFetch = UnixTime.now().earlier(TimeSpan.fromSeconds(i));
|
||||||
try {
|
try {
|
||||||
res = await fetchDataJson(timestampToFetch, s3Credentials, false);
|
res = await fetchDataJson(timestampToFetch, s3Credentials, false);
|
||||||
|
|
@ -199,7 +201,7 @@ function SodioHomeInstallation(props: singleInstallationProps) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i <= 0) {
|
if (i >= timeperiodToSearch) {
|
||||||
setConnected(false);
|
setConnected(false);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -207,8 +209,10 @@ function SodioHomeInstallation(props: singleInstallationProps) {
|
||||||
setConnected(true);
|
setConnected(true);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
||||||
const timestamp = Object.keys(res)[Object.keys(res).length - 1];
|
// Sort timestamps numerically to ensure we get the most recent data point
|
||||||
setValues(res[timestamp]);
|
const timestamps = Object.keys(res).sort((a, b) => Number(b) - Number(a));
|
||||||
|
const latestTimestamp = timestamps[0];
|
||||||
|
setValues(res[latestTimestamp]);
|
||||||
// setValues(
|
// setValues(
|
||||||
// extractValues({
|
// extractValues({
|
||||||
// time: UnixTime.fromTicks(parseInt(timestamp, 10)),
|
// time: UnixTime.fromTicks(parseInt(timestamp, 10)),
|
||||||
|
|
@ -251,9 +255,19 @@ function SodioHomeInstallation(props: singleInstallationProps) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Fetch only one time in configuration tab
|
// Fetch periodically in configuration tab (every 30 seconds to detect S3 updates)
|
||||||
if (currentTab == 'configuration') {
|
if (currentTab == 'configuration') {
|
||||||
fetchDataForOneTime();
|
fetchDataForOneTime(); // Initial fetch
|
||||||
|
|
||||||
|
const configRefreshInterval = setInterval(() => {
|
||||||
|
console.log('Refreshing configuration data from S3...');
|
||||||
|
fetchDataForOneTime();
|
||||||
|
}, 15000); // Refresh every 15 seconds
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
continueFetching.current = false;
|
||||||
|
clearInterval(configRefreshInterval);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import {
|
||||||
useTheme
|
useTheme
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
import React, { useContext, useState } from 'react';
|
import React, { useContext, useState, useEffect } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
import { Close as CloseIcon } from '@mui/icons-material';
|
import { Close as CloseIcon } from '@mui/icons-material';
|
||||||
|
|
@ -105,6 +105,78 @@ function SodistoreHomeConfiguration(props: SodistoreHomeConfigurationProps) {
|
||||||
controlPermission: String(props.values.Config.ControlPermission).toLowerCase() === "true",
|
controlPermission: String(props.values.Config.ControlPermission).toLowerCase() === "true",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Storage key for pending config (optimistic update)
|
||||||
|
const pendingConfigKey = `pendingConfig_${props.id}`;
|
||||||
|
|
||||||
|
// Helper to get current S3 values
|
||||||
|
const getS3Values = () => ({
|
||||||
|
minimumSoC: props.values.Config.MinSoc,
|
||||||
|
maximumDischargingCurrent: props.values.Config.MaximumChargingCurrent,
|
||||||
|
maximumChargingCurrent: props.values.Config.MaximumDischargingCurrent,
|
||||||
|
operatingPriority: OperatingPriorityOptions.indexOf(
|
||||||
|
props.values.Config.OperatingPriority
|
||||||
|
),
|
||||||
|
batteriesCount: props.values.Config.BatteriesCount,
|
||||||
|
clusterNumber: props.values.Config.ClusterNumber ?? 1,
|
||||||
|
PvNumber: props.values.Config.PvNumber ?? 0,
|
||||||
|
timeChargeandDischargePower: props.values.Config?.TimeChargeandDischargePower ?? 0,
|
||||||
|
startTimeChargeandDischargeDayandTime:
|
||||||
|
props.values.Config?.StartTimeChargeandDischargeDayandTime
|
||||||
|
? dayjs(props.values.Config.StartTimeChargeandDischargeDayandTime).toDate()
|
||||||
|
: null,
|
||||||
|
stopTimeChargeandDischargeDayandTime:
|
||||||
|
props.values.Config?.StopTimeChargeandDischargeDayandTime
|
||||||
|
? dayjs(props.values.Config.StopTimeChargeandDischargeDayandTime).toDate()
|
||||||
|
: null,
|
||||||
|
controlPermission: String(props.values.Config.ControlPermission).toLowerCase() === "true",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sync form values when props.values changes
|
||||||
|
// Logic: Use localStorage only briefly after submit to prevent flicker, then trust S3
|
||||||
|
useEffect(() => {
|
||||||
|
const s3Values = getS3Values();
|
||||||
|
const pendingConfigStr = localStorage.getItem(pendingConfigKey);
|
||||||
|
|
||||||
|
if (pendingConfigStr) {
|
||||||
|
try {
|
||||||
|
const pendingConfig = JSON.parse(pendingConfigStr);
|
||||||
|
const submittedAt = pendingConfig.submittedAt || 0;
|
||||||
|
const timeSinceSubmit = Date.now() - submittedAt;
|
||||||
|
|
||||||
|
// Within 150 seconds of submit: use localStorage (waiting for S3 sync)
|
||||||
|
// This covers two full S3 upload cycles (75 sec × 2) to ensure new file is available
|
||||||
|
if (timeSinceSubmit < 150000) {
|
||||||
|
// Check if S3 now matches - if so, sync is complete
|
||||||
|
const s3MatchesPending =
|
||||||
|
s3Values.controlPermission === pendingConfig.values.controlPermission &&
|
||||||
|
s3Values.minimumSoC === pendingConfig.values.minimumSoC &&
|
||||||
|
s3Values.operatingPriority === pendingConfig.values.operatingPriority;
|
||||||
|
|
||||||
|
if (s3MatchesPending) {
|
||||||
|
// S3 synced! Clear localStorage and use S3 from now on
|
||||||
|
console.log('S3 synced with submitted config');
|
||||||
|
localStorage.removeItem(pendingConfigKey);
|
||||||
|
setFormValues(s3Values);
|
||||||
|
} else {
|
||||||
|
// Still waiting for sync, keep showing submitted values
|
||||||
|
console.log('Waiting for S3 sync, showing submitted values');
|
||||||
|
setFormValues(pendingConfig.values);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timeout expired: clear localStorage, trust S3 completely
|
||||||
|
console.log('Timeout expired, trusting S3 data');
|
||||||
|
localStorage.removeItem(pendingConfigKey);
|
||||||
|
} catch (e) {
|
||||||
|
localStorage.removeItem(pendingConfigKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No localStorage or expired: always use S3 (source of truth)
|
||||||
|
setFormValues(s3Values);
|
||||||
|
}, [props.values]);
|
||||||
|
|
||||||
const handleOperatingPriorityChange = (event) => {
|
const handleOperatingPriorityChange = (event) => {
|
||||||
setFormValues({
|
setFormValues({
|
||||||
...formValues,
|
...formValues,
|
||||||
|
|
@ -173,6 +245,13 @@ function SodistoreHomeConfiguration(props: SodistoreHomeConfigurationProps) {
|
||||||
if (res) {
|
if (res) {
|
||||||
setUpdated(true);
|
setUpdated(true);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
||||||
|
// Save submitted values to localStorage for optimistic UI update
|
||||||
|
// This ensures the form shows correct values even before S3 syncs (up to 75 sec delay)
|
||||||
|
localStorage.setItem(pendingConfigKey, JSON.stringify({
|
||||||
|
values: formValues,
|
||||||
|
submittedAt: Date.now()
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue