Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class App extends React.Component {
id: "showSpeed",
name: "Speed",
docLink: "https://github.com/googlemaps/fleet-debugger/blob/main/docs/Speed.md",
columns: ["lastlocation.speed"],
columns: [],
solutionTypes: ["ODRD", "LMFS"],
},
{
Expand Down Expand Up @@ -131,7 +131,7 @@ class App extends React.Component {
id: "showHighVelocityJumps",
name: "Jumps (unrealistic velocity)",
docLink: "https://github.com/googlemaps/fleet-debugger/blob/main/docs/VelocityJumps.md",
columns: ["lastlocation.speed"],
columns: [],
solutionTypes: ["ODRD", "LMFS"],
},
{
Expand All @@ -145,7 +145,7 @@ class App extends React.Component {
id: "showClientServerTimeDeltas",
name: "Client/Server Time Deltas",
docLink: "https://github.com/googlemaps/fleet-debugger/blob/main/README.md",
columns: ["response.laslLocation.rawlocationlime", "response.laslLocation.serverlime"],
columns: [],
solutionTypes: ["ODRD", "LMFS"],
},
{
Expand Down
2 changes: 1 addition & 1 deletion src/LogTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ function LogTable(props) {
{
Header: "DayTime",
accessor: "formattedDate",
Cell: ({ cell: { value } }) => value.substring(8, 10) + "T" + value.substring(11, 23),
Cell: ({ cell: { value } }) => value.substring(5, 10) + " " + value.substring(11, 19),
width: columnRegularWidth,
className: "logtable-cell",
solutionTypes: ["ODRD", "LMFS"],
Expand Down
4 changes: 4 additions & 0 deletions src/TrafficPolyline.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ import { log } from "./Utils";

export const TRAFFIC_COLORS = {
STYLE_NO_DATA: "#808080", // Gray
NO_DATA: "#808080",
STYLE_NORMAL: "#4285F4", // Google Maps Blue
NORMAL: "#4285F4",
STYLE_SLOWER_TRAFFIC: "#FFA500", // Orange
SLOWER_TRAFFIC: "#FFA500",
STYLE_TRAFFIC_JAM: "#FF0000", // Red
TRAFFIC_JAM: "#FF0000",
};

export class TrafficPolyline {
Expand Down
35 changes: 33 additions & 2 deletions src/localStorage.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,45 @@ export function parseJsonContent(content) {
}, {});
};

const processJsonObject = (obj) => {
if (obj === null || typeof obj !== "object") return obj;
if (Array.isArray(obj)) return obj.map(processJsonObject);

return Object.keys(obj).reduce((result, key) => {
const newKey = key.replace(/_/g, "");
let value = obj[key];

// Check if this is a value object with only a 'value' property and flatten
if (
value !== null &&
typeof value === "object" &&
!Array.isArray(value) &&
Object.keys(value).length === 1 &&
"value" in value
) {
value = value.value;
} else if (typeof value === "object" && value !== null) {
// Recursively process nested objects
value = processJsonObject(value);
}

result[newKey] = value;
return result;
}, {});
};

try {
const parsed = JSON.parse(content);
return sortObjectKeys(parsed);
const processedData = processJsonObject(parsed);
log("Processed JSON data: removed underscores and flattened value objects");
return sortObjectKeys(processedData);
} catch (error) {
log("Initial JSON parsing failed, attempting to wrap in array");
try {
const parsed = JSON.parse(`[${content}]`);
return sortObjectKeys(parsed);
const processedData = processJsonObject(parsed);
log("Processed JSON data in array format");
return sortObjectKeys(processedData);
} catch (innerError) {
console.error("JSON parsing error:", innerError);
throw new Error(`Invalid JSON content: ${innerError.message}`);
Expand Down
89 changes: 89 additions & 0 deletions src/localStorage.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,95 @@ test("parseJsonContent throws error for invalid JSON", () => {
expect(() => parseJsonContent(invalidJson)).toThrow("Invalid JSON content");
});

test("parseJsonContent removes underscores from keys", () => {
const snakeCaseJson = JSON.stringify({
snake_case_key: "value",
normal_key: "value2",
});

const result = parseJsonContent(snakeCaseJson);

expect(result).toHaveProperty("snakecasekey", "value");
expect(result).toHaveProperty("normalkey", "value2");
expect(result).not.toHaveProperty("snake_case_key");
expect(result).not.toHaveProperty("normal_key");
});

test("parseJsonContent removes underscores from deeply nested object keys", () => {
const nestedJson = JSON.stringify({
top_level: {
nested_key: {
deeply_nested_key: "value",
},
},
});

const result = parseJsonContent(nestedJson);

expect(result).toHaveProperty("toplevel.nestedkey.deeplynestedkey", "value");
expect(result).not.toHaveProperty("top_level");
});

// New tests for value object flattening
test("parseJsonContent flattens objects with a single 'value' property", () => {
const valueObjectJson = JSON.stringify({
normalKey: "normal",
valueObject: { value: "flattened" },
});

const result = parseJsonContent(valueObjectJson);

expect(result.normalKey).toBe("normal");
expect(result.valueObject).toBe("flattened");
expect(typeof result.valueObject).toBe("string");
});

test("parseJsonContent flattens nested objects with a single 'value' property", () => {
const nestedValueObjectJson = JSON.stringify({
level1: {
level2: {
normalObj: { key: "value" },
valueObj: { value: "flattened" },
},
},
});

const result = parseJsonContent(nestedValueObjectJson);

expect(result.level1.level2.normalObj.key).toBe("value");
expect(result.level1.level2.valueObj).toBe("flattened");
expect(typeof result.level1.level2.valueObj).toBe("string");
});

test("parseJsonContent handles both underscore removal and value flattening together", () => {
const complexJson = JSON.stringify({
snake_case: {
nested_value_obj: { value: 123 },
other_key: { some_nested: { value: "test" } },
},
});

const result = parseJsonContent(complexJson);

expect(result.snakecase.nestedvalueobj).toBe(123);
expect(result.snakecase.otherkey.somenested).toBe("test");
});

test("parseJsonContent properly handles arrays containing value objects", () => {
const arrayWithValueObjects = JSON.stringify({
items: [
{ name: "item1", property: { value: 100 } },
{ name: "item2", property: { value: 200 } },
],
});

const result = parseJsonContent(arrayWithValueObjects);

expect(result.items[0].name).toBe("item1");
expect(result.items[0].property).toBe(100);
expect(result.items[1].property).toBe(200);
});

test("removeEmptyObjects removes empty nested objects", () => {
const input = {
a: {},
Expand Down
Loading