diff --git a/src/App.js b/src/App.js
index c3b54d5..9535920 100644
--- a/src/App.js
+++ b/src/App.js
@@ -808,7 +808,20 @@ class App extends React.Component {
try {
const data = await getUploadedData(index);
- if (!data || !data.retentionDate) return "Valid";
+ if (!data) {
+ log(`Dataset ${index + 1} not found in storage. It may have expired or been deleted.`, "error");
+ this.setState((prevState) => {
+ const newUploadedDatasets = [...prevState.uploadedDatasets];
+ newUploadedDatasets[index] = null;
+ return {
+ uploadedDatasets: newUploadedDatasets,
+ activeDatasetIndex: prevState.activeDatasetIndex === index ? null : prevState.activeDatasetIndex,
+ };
+ });
+ return "Expired";
+ }
+
+ if (!data.retentionDate) return "Valid";
const retentionDate = new Date(data.retentionDate);
const now = new Date();
diff --git a/src/DatasetLoading.js b/src/DatasetLoading.js
index 984f662..7878efb 100644
--- a/src/DatasetLoading.js
+++ b/src/DatasetLoading.js
@@ -3,8 +3,7 @@ import { useState, useEffect } from "react";
import { GoogleOAuthProvider } from "@react-oauth/google";
import ExtraDataSource from "./ExtraDataSource";
import { log } from "./Utils";
-import { toast, ToastContainer } from "react-toastify";
-import "react-toastify/dist/ReactToastify.css";
+import { toast } from "react-toastify";
import { isTokenValid, fetchLogsWithToken, useCloudLoggingLogin, buildQueryFilter } from "./CloudLogging";
import { HAS_EXTRA_DATA_SOURCE } from "./constants";
@@ -206,7 +205,6 @@ export default function DatasetLoading(props) {
return (
<>
-
{renderSourceSelection()}
{isExtra ? (
diff --git a/src/localStorage.js b/src/localStorage.js
index 6002c7e..2dae3c0 100644
--- a/src/localStorage.js
+++ b/src/localStorage.js
@@ -260,9 +260,10 @@ export function ensureCorrectFormat(data) {
if (!Array.isArray(data)) {
// If it's already in the correct format, return it as is, BUT RE-CALCULATE TTL for grace period.
if (data && data.rawLogs && Array.isArray(data.rawLogs)) {
+ const calculatedTTL = calculateRetentionDate(data.rawLogs);
return {
...data,
- retentionDate: calculateRetentionDate(data.rawLogs),
+ retentionDate: data.retentionDate > calculatedTTL ? data.retentionDate : calculatedTTL,
APIKEY: data.APIKEY || DEFAULT_API_KEY,
};
} else {
@@ -364,7 +365,7 @@ export function ensureCorrectFormat(data) {
if (!hasPoints) log("Bounds Calculation Failed: Could not find vehicle location data in any row.");
// Calculate retention date using the helper
- const retentionDateIdentifier = calculateRetentionDate(logsArray);
+ const calculatedTTL = calculateRetentionDate(logsArray);
return {
APIKEY: DEFAULT_API_KEY,
@@ -374,7 +375,7 @@ export function ensureCorrectFormat(data) {
solutionType: solutionType,
rawLogs: fullyNormalizedLogs,
bounds: hasPoints ? bounds : null,
- retentionDate: retentionDateIdentifier,
+ retentionDate: data.retentionDate > calculatedTTL ? data.retentionDate : calculatedTTL,
};
}
diff --git a/src/localStorage.test.js b/src/localStorage.test.js
index c6c3fe3..014ccb1 100644
--- a/src/localStorage.test.js
+++ b/src/localStorage.test.js
@@ -274,4 +274,19 @@ describe("ensureCorrectFormat TTL Logic", () => {
expect(result.retentionDate).not.toBe(staleDate);
expect(retention).toBeGreaterThanOrEqual(expectedMin - 1000);
});
+
+ it("should pick the 1h grace period if existing future TTL is less than 1h", () => {
+ const thirtyMinFuture = new Date(Date.now() + 30 * 60 * 1000).toISOString();
+ const mockExportedFile = {
+ rawLogs: [{ timestamp: new Date(Date.now() - 100 * ONE_DAY_MS).toISOString(), jsonPayload: { test: 1 } }],
+ retentionDate: thirtyMinFuture,
+ };
+
+ const result = ensureCorrectFormat(mockExportedFile);
+ const retention = new Date(result.retentionDate).getTime();
+ const expectedMin = Date.now() + ONE_HOUR_MS;
+
+ expect(result.retentionDate).not.toBe(thirtyMinFuture);
+ expect(retention).toBeGreaterThanOrEqual(expectedMin - 1000);
+ });
});