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
2 changes: 1 addition & 1 deletion .github/workflows/build-demos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ permissions:

jobs:
build-and-deploy:
if: github.repository == 'googlemaps/fleet-debugger'
if: github.repository == 'googlemaps/fleet-debugger' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest

steps:
Expand Down
1 change: 1 addition & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<script src="https://accounts.google.com/gsi/client" async defer></script>
<title>Fleet Debugger</title>
</head>
<body>
Expand Down
28 changes: 27 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
saveDatasetAsJson,
saveToIndexedDB,
} from "./localStorage";
import { exportToGoogleSheet, requestSheetsToken } from "./GoogleSheets";
import _ from "lodash";
import { getQueryStringValue, setQueryStringValue } from "./queryString";
import "./global.css";
Expand Down Expand Up @@ -527,6 +528,28 @@ class App extends React.Component {
}
};

const handleGoogleSheetExport = async (e) => {
e.stopPropagation();
log(`Google Sheet export initiated for dataset ${index}`);
this.setState({ activeMenuIndex: null });

try {
const token = await requestSheetsToken();
const sheetUrl = await exportToGoogleSheet(index, token);
toast.success(
<span>
Exported to{" "}
<a href={sheetUrl} target="_blank" rel="noopener noreferrer">
Google Sheet
</a>
</span>
);
} catch (error) {
log(`Error exporting to Google Sheet: ${error.message}`, error);
toast.error(`Google Sheet export failed: ${error.message}`);
}
};

const handlePruneClick = async (e) => {
e.stopPropagation();
log(`Prune initiated for dataset ${index}`);
Expand Down Expand Up @@ -681,7 +704,10 @@ class App extends React.Component {
{isMenuOpen && (
<div className="dataset-button-menu">
<div className="dataset-button-menu-item export" onClick={handleSaveClick}>
Export
Export File
</div>
<div className="dataset-button-menu-item export" onClick={handleGoogleSheetExport}>
Export GSheet
</div>
<div className="dataset-button-menu-item prune" onClick={handlePruneClick}>
Prune
Expand Down
94 changes: 89 additions & 5 deletions src/DatasetLoading.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ import ExtraDataSource from "./ExtraDataSource";
import { log } from "./Utils";
import { toast } from "react-toastify";
import { isTokenValid, fetchLogsWithToken, useCloudLoggingLogin, buildQueryFilter } from "./CloudLogging";
import { HAS_EXTRA_DATA_SOURCE } from "./constants";
import { useSheetsLogin, isSheetsTokenValid, getSheetsToken, importFromGoogleSheet } from "./GoogleSheets";
import { HAS_EXTRA_DATA_SOURCE, GOOGLE_CLIENT_ID } from "./constants";

const CloudLoggingFormComponent = ({ onLogsReceived, onFileUpload }) => {
const getStoredValue = (key, defaultValue = "") => localStorage.getItem(`datasetLoading_${key}`) || defaultValue;

const [fetching, setFetching] = useState(false);
const [sheetFormVisible, setSheetFormVisible] = useState(false);
const [sheetUrl, setSheetUrl] = useState(localStorage.getItem("datasetLoading_sheetUrl") || "");
const [sheetLoading, setSheetLoading] = useState(false);
const [queryParams, setQueryParams] = useState({
projectId: getStoredValue("projectId"),
vehicleId: getStoredValue("vehicleId"),
Expand Down Expand Up @@ -65,6 +69,52 @@ const CloudLoggingFormComponent = ({ onLogsReceived, onFileUpload }) => {
}
};

const handleSheetImport = (token) => {
setSheetLoading(true);
setLocalError(null);
localStorage.setItem("datasetLoading_sheetUrl", sheetUrl);

importFromGoogleSheet(sheetUrl, token)
.then((logs) => {
log(`Received ${logs.length} logs from Google Sheet`);
if (logs.length > 0) {
onLogsReceived(logs);
} else {
toast.warning("No logs found in the spreadsheet.");
}
})
.catch((err) => {
setLocalError(`Sheet import error: ${err.message}`);
toast.error(`Sheet import error: ${err.message}`);
})
.finally(() => setSheetLoading(false));
};

const sheetsLogin = useSheetsLogin(
(token) => {
log("Sheets login successful, importing...");
handleSheetImport(token);
},
(err) => {
log("Sheets login failed.", err);
setLocalError(`Auth Error: ${err.error || "Unknown"}`);
setSheetLoading(false);
}
);

const handleSheetLoadClick = () => {
if (!sheetUrl.trim()) {
setLocalError("Please enter a spreadsheet URL or ID.");
return;
}
setLocalError(null);
if (isSheetsTokenValid()) {
handleSheetImport(getSheetsToken());
} else {
sheetsLogin();
}
};

return (
<div className="cloud-logging-form">
<h3>Fleet Engine Logs Loading</h3>
Expand Down Expand Up @@ -162,14 +212,48 @@ const CloudLoggingFormComponent = ({ onLogsReceived, onFileUpload }) => {
</div>
)}
<div className="cloud-logging-buttons">
<button type="button" onClick={handleFetch} disabled={fetching} className="primary-button">
<button type="button" onClick={handleFetch} disabled={fetching} className="fetch-logs-button">
{fetching ? "Fetching..." : isTokenValid() ? "Fetch Logs" : "Sign in and Fetch Logs"}
</button>
<label htmlFor="fileUploadInput" className="secondary-button">
Load JSON or ZIP file instead
<button type="button" onClick={() => setSheetFormVisible(!sheetFormVisible)} className="sideload-logs-button">
Load Google Sheet
</button>
<label htmlFor="fileUploadInput" className="sideload-logs-button">
Load JSON or ZIP
</label>
<input type="file" id="fileUploadInput" accept=".json,.zip" onChange={onFileUpload} className="file-input" />
</div>
{sheetFormVisible && (
<div className="google-sheet-form">
<div className="form-field">
<label className="form-label">
Spreadsheet URL or ID:
<input
type="text"
value={sheetUrl}
onChange={(e) => setSheetUrl(e.target.value)}
placeholder="https://docs.google.com/spreadsheets/d/... or spreadsheet ID"
className="form-input"
/>
</label>
</div>
<button
type="button"
onClick={handleSheetLoadClick}
disabled={sheetLoading}
className="fetch-logs-button"
style={{ marginTop: "8px" }}
>
{sheetLoading ? "Loading..." : isSheetsTokenValid() ? "Load Sheet" : "Sign in and Load Sheet"}
</button>
{sheetLoading && (
<div className="progress-indicator">
<div>Loading from Google Sheet...</div>
<progress className="progress-bar" />
</div>
)}
</div>
)}
</div>
);
};
Expand Down Expand Up @@ -210,7 +294,7 @@ export default function DatasetLoading(props) {
{isExtra ? (
ExtraFormComponent
) : (
<GoogleOAuthProvider clientId="829183678942-eq2c9cd7pjdm39l2um5thgbrvgva07e7.apps.googleusercontent.com">
<GoogleOAuthProvider clientId={GOOGLE_CLIENT_ID}>
<CloudLoggingFormComponent {...props} />
</GoogleOAuthProvider>
)}
Expand Down
Loading
Loading