Skip to content

Commit b413d77

Browse files
feat: dataframe sidepanel (#296)
* fix: Don't show fractions of meters/feet * feat: dataframe sidepanel * fix: formatDistance tests 2ae547b
1 parent 1ffe2c0 commit b413d77

File tree

5 files changed

+150
-22
lines changed

5 files changed

+150
-22
lines changed

src/App.js

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ class App extends React.Component {
131131
featuredObject: { msg: "Click a table row to select object" },
132132
extraColumns: [],
133133
toggleOptions: Object.fromEntries(ALL_TOGGLES.map((t) => [t.id, false])),
134+
isDataframeCollapsed: false,
134135
filters: {
135136
logTypes: {
136137
createVehicle: true,
@@ -1082,6 +1083,12 @@ class App extends React.Component {
10821083
}));
10831084
};
10841085

1086+
toggleDataframe = () => {
1087+
this.setState((prevState) => ({
1088+
isDataframeCollapsed: !prevState.isDataframeCollapsed,
1089+
}));
1090+
};
1091+
10851092
render() {
10861093
const {
10871094
featuredObject,
@@ -1092,13 +1099,49 @@ class App extends React.Component {
10921099
dynamicMarkerLocations,
10931100
visibleToggles,
10941101
filters,
1102+
isDataframeCollapsed,
10951103
} = this.state;
10961104
const selectedEventTime = featuredObject?.timestamp ? new Date(featuredObject.timestamp).getTime() : null;
10971105
const availableFilters = currentLogData.solutionType === "ODRD" ? ODRD_FILTERS : [];
10981106

10991107
return (
1100-
<div className="app-container">
1108+
<div className={`app-container ${isDataframeCollapsed ? "dataframe-collapsed" : ""}`}>
11011109
<ToastContainer position="top-right" autoClose={5000} />
1110+
<button
1111+
className="dataframe-toggle-tab"
1112+
onClick={this.toggleDataframe}
1113+
title={isDataframeCollapsed ? "Show side panel" : "Hide side panel"}
1114+
>
1115+
{isDataframeCollapsed ? (
1116+
<svg
1117+
xmlns="http://www.w3.org/2000/svg"
1118+
width="16"
1119+
height="16"
1120+
viewBox="0 0 24 24"
1121+
fill="none"
1122+
stroke="currentColor"
1123+
strokeWidth="2"
1124+
strokeLinecap="round"
1125+
strokeLinejoin="round"
1126+
>
1127+
<polyline points="15 18 9 12 15 6"></polyline>
1128+
</svg>
1129+
) : (
1130+
<svg
1131+
xmlns="http://www.w3.org/2000/svg"
1132+
width="16"
1133+
height="16"
1134+
viewBox="0 0 24 24"
1135+
fill="none"
1136+
stroke="currentColor"
1137+
strokeWidth="2"
1138+
strokeLinecap="round"
1139+
strokeLinejoin="round"
1140+
>
1141+
<polyline points="9 18 15 12 9 6"></polyline>
1142+
</svg>
1143+
)}
1144+
</button>
11021145
<div className="main-content">
11031146
<div className="map-and-control-section">
11041147
<div className="map-container">

src/Dataframe.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,13 @@ function Dataframe({ featuredObject, extraColumns, onColumnToggle, onToggleMarke
199199
}, []);
200200

201201
return (
202-
<div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
202+
<div style={{ display: "flex", flexDirection: "column", height: "100%", position: "relative" }}>
203203
<div style={{ padding: "4px 8px", flexShrink: 0 }}>
204-
<button onClick={handleCopyRoot}>Copy Object</button>
204+
<button onClick={handleCopyRoot} className="copy-object-button">
205+
Copy Object
206+
</button>
205207
</div>
206-
<div style={{ overflow: "auto", flexGrow: 1 }}>
208+
<div className="dataframe-content">
207209
<JsonView
208210
src={featuredObject}
209211
collapsed={shouldCollapse}

src/PolylineUtils.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ describe("calculatePolylineDistanceMeters", () => {
9999
describe("formatDistance", () => {
100100
test("formats under 1000 meters correctly", () => {
101101
const { metric, imperial } = formatDistance(500);
102-
expect(metric).toBe("500.0 m");
103-
expect(imperial).toBe("1640.4 ft");
102+
expect(metric).toBe("500 m");
103+
expect(imperial).toBe("1640 ft");
104104
});
105105

106106
test("formats over 1000 meters into km and miles", () => {

src/Utils.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,9 @@ export function formatDistance(distanceMeters) {
152152
const distanceFeet = distanceMeters * 3.28084;
153153
const distanceMiles = distanceMeters * 0.000621371;
154154

155-
const metric = distanceMeters < 1000 ? distanceMeters.toFixed(1) + " m" : (distanceMeters / 1000).toFixed(2) + " km";
155+
const metric = distanceMeters < 1000 ? distanceMeters.toFixed(0) + " m" : (distanceMeters / 1000).toFixed(2) + " km";
156156

157-
const imperial = distanceFeet < 5280 ? distanceFeet.toFixed(1) + " ft" : distanceMiles.toFixed(2) + " mi";
157+
const imperial = distanceFeet < 5280 ? distanceFeet.toFixed(0) + " ft" : distanceMiles.toFixed(2) + " mi";
158158

159159
return { metric, imperial };
160160
}

src/global.css

Lines changed: 97 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
/* global.css */
2+
body,
3+
html {
4+
margin: 0;
5+
padding: 0;
6+
height: 100%;
7+
}
8+
29
/* Tooltip styles */
310
[class^="rc-slider-tooltip"] {
411
min-height: 30px;
@@ -101,8 +108,6 @@
101108
transform: translateX(-50%);
102109
}
103110

104-
105-
106111
/* Map and button styles */
107112
.map-button {
108113
height: 40px;
@@ -170,9 +175,11 @@
170175
}
171176

172177
.follow-vehicle-button.active .follow-vehicle-background {
173-
border: 2px solid #4285F4;
178+
border: 2px solid #4285f4;
174179
background-color: #d1dff7;
175-
box-shadow: 0 0 8px rgba(66, 133, 244, 0.6), inset 0 0 6px rgba(66, 133, 244, 0.6);
180+
box-shadow:
181+
0 0 8px rgba(66, 133, 244, 0.6),
182+
inset 0 0 6px rgba(66, 133, 244, 0.6);
176183
}
177184

178185
/* Cloud logging styles */
@@ -216,7 +223,7 @@
216223
}
217224

218225
.sideload-logs-button {
219-
background-color: #34A853;
226+
background-color: #34a853;
220227
color: white;
221228
padding: 12px 6px;
222229
border: none;
@@ -251,7 +258,7 @@
251258
}
252259

253260
.cloud-logging-file-button {
254-
background-color: #34A853;
261+
background-color: #34a853;
255262
flex: 1;
256263
}
257264

@@ -263,12 +270,15 @@
263270
.app-container {
264271
display: flex;
265272
height: 100vh;
273+
position: relative;
274+
overflow: hidden;
266275
}
267276

268277
.main-content {
269278
width: 70%;
270279
display: flex;
271280
flex-direction: column;
281+
transition: width 0.3s ease;
272282
}
273283

274284
.map-and-control-section {
@@ -281,9 +291,78 @@
281291
width: 30%;
282292
height: 100%;
283293
overflow: auto;
294+
transition: width 0.3s ease;
295+
}
296+
297+
.app-container.dataframe-collapsed .main-content {
298+
width: 100%;
299+
}
300+
301+
.app-container.dataframe-collapsed .dataframe-section {
302+
width: 0;
303+
overflow: hidden;
284304
}
285305

286-
/* Navigation controls */
306+
.dataframe-header-inner {
307+
display: flex;
308+
align-items: center;
309+
justify-content: flex-end;
310+
padding: 8px;
311+
gap: 8px;
312+
flex-shrink: 0;
313+
}
314+
315+
.dataframe-toggle-tab {
316+
position: absolute;
317+
right: 30%;
318+
/* Will be the edge of the dataframe section when expanded */
319+
bottom: 24px;
320+
width: 32px;
321+
height: 48px;
322+
background-color: #f1f3f4;
323+
border: 1px solid #dadce0;
324+
border-right: none;
325+
border-radius: 24px 0 0 24px;
326+
display: flex;
327+
align-items: center;
328+
justify-content: center;
329+
cursor: pointer;
330+
z-index: 1000;
331+
transition: right 0.3s ease, background-color 0.2s ease;
332+
color: #5f6368;
333+
box-shadow: -2px 0 4px rgba(0, 0, 0, 0.05);
334+
}
335+
336+
.dataframe-toggle-tab:hover {
337+
background-color: #e8eaed;
338+
}
339+
340+
.app-container.dataframe-collapsed .dataframe-toggle-tab {
341+
right: 0;
342+
}
343+
344+
.copy-object-button {
345+
padding: 6px 12px;
346+
background-color: transparent;
347+
border: 1px solid #ccc;
348+
border-radius: 4px;
349+
cursor: pointer;
350+
font-size: 13px;
351+
color: #555;
352+
transition: all 0.2s ease;
353+
}
354+
355+
.copy-object-button:hover {
356+
background-color: #f5f5f5;
357+
}
358+
359+
.dataframe-content {
360+
overflow: auto;
361+
flex-grow: 1;
362+
padding: 8, 8, 8, 0;
363+
}
364+
365+
/* App layout styles */
287366
.nav-controls {
288367
display: flex;
289368
flex-direction: column;
@@ -328,12 +407,12 @@
328407
}
329408

330409
.dataset-button-active {
331-
background-color: #4CAF50;
410+
background-color: #4caf50;
332411
padding: 10px 25px 10px 10px;
333412
}
334413

335414
.dataset-button-uploaded {
336-
background-color: #008CBA;
415+
background-color: #008cba;
337416
padding: 10px 25px 10px 10px;
338417
}
339418

@@ -591,18 +670,21 @@
591670
}
592671

593672
.map-toggle-button.active {
594-
color: #4285F4;
673+
color: #4285f4;
595674
background-color: rgba(209, 223, 247, 0.5);
596-
border: 2px solid #4285F4;
675+
border: 2px solid #4285f4;
597676
border-radius: 20px;
598-
box-shadow: 0 0 8px rgba(66, 133, 244, 0.4), inset 0 0 4px rgba(66, 133, 244, 0.2);
677+
box-shadow:
678+
0 0 8px rgba(66, 133, 244, 0.4),
679+
inset 0 0 4px rgba(66, 133, 244, 0.2);
599680
}
600681

601682
.map-toggle-separator {
602683
width: 1px;
603684
height: 100%;
604685
background-color: rgba(0, 0, 0, 0.15);
605686
}
687+
606688
/* Resizer styles for react-table */
607689
.resizer {
608690
display: inline-block;
@@ -618,6 +700,7 @@
618700
cursor: col-resize;
619701
}
620702

621-
.resizer:hover, .resizer.isResizing {
703+
.resizer:hover,
704+
.resizer.isResizing {
622705
background: rgba(0, 0, 0, 0.5);
623-
}
706+
}

0 commit comments

Comments
 (0)