From b7df3e731fa8331432f4b116018c0aa28e9e2c22 Mon Sep 17 00:00:00 2001 From: Slawomir Koszewski Date: Sat, 31 Jan 2026 09:05:07 +0100 Subject: [PATCH] Fix: the expression input box was getting reset while switching pages. Formatted the code text. --- src/App.js | 129 +++++++++++++++++++++--------------- src/components/MainPage.js | 131 ++++++++++++++++++------------------- 2 files changed, 140 insertions(+), 120 deletions(-) diff --git a/src/App.js b/src/App.js index cb37c12..1130899 100644 --- a/src/App.js +++ b/src/App.js @@ -1,16 +1,16 @@ -import React, { useState, useEffect } from 'react'; -import Header from './components/Header'; -import Footer from './components/Footer'; -import MainPage from './components/MainPage'; -import ApiKeyPage from './components/ApiKeyPage'; -import './App.css'; +import React, { useState, useEffect } from "react"; +import Header from "./components/Header"; +import Footer from "./components/Footer"; +import MainPage from "./components/MainPage"; +import ApiKeyPage from "./components/ApiKeyPage"; +import "./App.css"; // Utility function to generate a cryptographically secure API key function generateApiKey() { const array = new Uint8Array(16); - + // Use crypto.getRandomValues if available (browser), fallback for tests - if (typeof crypto !== 'undefined' && crypto.getRandomValues) { + if (typeof crypto !== "undefined" && crypto.getRandomValues) { crypto.getRandomValues(array); } else { // Fallback for test environments - not cryptographically secure @@ -18,62 +18,86 @@ function generateApiKey() { array[i] = Math.floor(Math.random() * 256); } } - - return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join(''); + + return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join( + "", + ); } // JMESPath Testing Tool - Main Application Component function App() { - const [currentPage, setCurrentPage] = useState('main'); // 'main' or 'apikey' + const [currentPage, setCurrentPage] = useState("main"); // 'main' or 'apikey' const [theme, setTheme] = useState(() => { // Load theme from localStorage or default to 'auto' - return localStorage.getItem('theme') || 'auto'; + return localStorage.getItem("theme") || "auto"; }); const [showReloadButton, setShowReloadButton] = useState(false); const [currentStateGuid, setCurrentStateGuid] = useState(null); - const [sampleData, setSampleData] = useState(null); + const [jmespathExpression, setJmespathExpression] = + useState("people[0].name"); + const [jsonData, setJsonData] = useState(`{ + "people": [ + { + "name": "John Doe", + "age": 30, + "city": "New York" + }, + { + "name": "Jane Smith", + "age": 25, + "city": "Los Angeles" + } + ], + "total": 2 +}`); const [apiKey, setApiKey] = useState(() => { // Load API key from localStorage or generate new one - const stored = localStorage.getItem('jmespath-api-key'); + const stored = localStorage.getItem("jmespath-api-key"); if (stored && /^[0-9a-f]{32}$/i.test(stored)) { return stored; } const newKey = generateApiKey(); - localStorage.setItem('jmespath-api-key', newKey); + localStorage.setItem("jmespath-api-key", newKey); return newKey; }); // Theme management useEffect(() => { const applyTheme = (selectedTheme) => { - const effectiveTheme = selectedTheme === 'auto' - ? (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') - : selectedTheme; - - document.documentElement.setAttribute('data-bs-theme', effectiveTheme); + const effectiveTheme = + selectedTheme === "auto" + ? window.matchMedia && + window.matchMedia("(prefers-color-scheme: dark)").matches + ? "dark" + : "light" + : selectedTheme; + + document.documentElement.setAttribute("data-bs-theme", effectiveTheme); }; applyTheme(theme); - + // Save theme preference - localStorage.setItem('theme', theme); + localStorage.setItem("theme", theme); }, [theme]); // Get headers for API requests const getApiHeaders = () => { const headers = { - 'Accept': 'application/json' + Accept: "application/json", }; - + // Only send API key for non-localhost requests // For localhost, let server use its default LOCALHOST_API_KEY - if (window.location.hostname !== 'localhost' && - window.location.hostname !== '127.0.0.1' && - !window.location.hostname.startsWith('127.') && - window.location.hostname !== '::1') { - headers['X-API-Key'] = apiKey; + if ( + window.location.hostname !== "localhost" && + window.location.hostname !== "127.0.0.1" && + !window.location.hostname.startsWith("127.") && + window.location.hostname !== "::1" + ) { + headers["X-API-Key"] = apiKey; } - + return headers; }; @@ -90,10 +114,10 @@ function App() { // Check if state has changed (new data uploaded) const checkStateChange = async () => { try { - const response = await fetch('/api/v1/state', { - headers: getApiHeaders() + const response = await fetch("/api/v1/state", { + headers: getApiHeaders(), }); - + if (response.ok) { const stateData = await response.json(); if (stateData.state && stateData.state !== currentStateGuid) { @@ -109,19 +133,19 @@ function App() { const loadSampleData = async () => { try { setShowReloadButton(false); - const response = await fetch('/api/v1/sample', { - headers: getApiHeaders() + const response = await fetch("/api/v1/sample", { + headers: getApiHeaders(), }); - + if (response.ok) { const data = await response.json(); if (data) { - setSampleData(data); + setJsonData(JSON.stringify(data, null, 2)); } // Update current state GUID - const stateResponse = await fetch('/api/v1/state', { - headers: getApiHeaders() + const stateResponse = await fetch("/api/v1/state", { + headers: getApiHeaders(), }); if (stateResponse.ok) { const stateData = await stateResponse.json(); @@ -129,7 +153,7 @@ function App() { } } } catch (error) { - console.error('Failed to load sample data:', error); + console.error("Failed to load sample data:", error); } }; @@ -137,7 +161,7 @@ function App() { const regenerateApiKey = () => { const newKey = generateApiKey(); setApiKey(newKey); - localStorage.setItem('jmespath-api-key', newKey); + localStorage.setItem("jmespath-api-key", newKey); setShowReloadButton(false); setCurrentStateGuid(null); }; @@ -152,7 +176,7 @@ function App() { return (
-
{/* Main Content Section - flex-grow to fill space */} -
- {currentPage === 'main' ? ( - + {currentPage === "main" ? ( + ) : ( - + )}
@@ -181,4 +208,4 @@ function App() { ); } -export default App; \ No newline at end of file +export default App; diff --git a/src/components/MainPage.js b/src/components/MainPage.js index 2e79bb8..e1220f7 100644 --- a/src/components/MainPage.js +++ b/src/components/MainPage.js @@ -1,41 +1,23 @@ -import React, { useState, useEffect } from 'react'; -import jmespath from 'jmespath'; - -function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleData }) { - const [jmespathExpression, setJmespathExpression] = useState('people[0].name'); - const [jsonData, setJsonData] = useState(`{ - "people": [ - { - "name": "John Doe", - "age": 30, - "city": "New York" - }, - { - "name": "Jane Smith", - "age": 25, - "city": "Los Angeles" - } - ], - "total": 2 -}`); - const [result, setResult] = useState(''); - const [error, setError] = useState(''); - const [jsonError, setJsonError] = useState(''); - - // Use initial sample data when provided - useEffect(() => { - if (initialSampleData) { - setJsonData(JSON.stringify(initialSampleData, null, 2)); - } - }, [initialSampleData]); - +import React, { useState, useEffect } from "react"; +import jmespath from "jmespath"; +function MainPage({ + showReloadButton, + onReloadSampleData, + jmespathExpression, + setJmespathExpression, + jsonData, + setJsonData, +}) { + const [result, setResult] = useState(""); + const [error, setError] = useState(""); + const [jsonError, setJsonError] = useState(""); const evaluateExpression = () => { try { // Clear previous errors - setError(''); - setJsonError(''); + setError(""); + setJsonError(""); // Validate and parse JSON let parsedData; @@ -43,7 +25,7 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD parsedData = JSON.parse(jsonData); } catch (jsonErr) { setJsonError(`Invalid JSON: ${jsonErr.message}`); - setResult(''); + setResult(""); return; } @@ -52,13 +34,13 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD // Format the result if (queryResult === null || queryResult === undefined) { - setResult('null'); + setResult("null"); } else { setResult(JSON.stringify(queryResult, null, 2)); } } catch (jmesErr) { setError(`JMESPath Error: ${jmesErr.message}`); - setResult(''); + setResult(""); } }; @@ -88,30 +70,30 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD }; const clearAll = () => { - setJmespathExpression(''); - setJsonData(''); - setResult(''); - setError(''); - setJsonError(''); + setJmespathExpression(""); + setJsonData(""); + setResult(""); + setError(""); + setJsonError(""); }; const loadSample = () => { const sampleData = { - "users": [ - {"name": "Alice", "age": 30, "city": "New York"}, - {"name": "Bob", "age": 25, "city": "San Francisco"}, - {"name": "Charlie", "age": 35, "city": "Chicago"} + users: [ + { name: "Alice", age: 30, city: "New York" }, + { name: "Bob", age: 25, city: "San Francisco" }, + { name: "Charlie", age: 35, city: "Chicago" }, ], - "total": 3 + total: 3, }; setJsonData(JSON.stringify(sampleData, null, 2)); - setJmespathExpression('users[?age > `30`].name'); + setJmespathExpression("users[?age > `30`].name"); }; const loadFromDisk = () => { - const input = document.createElement('input'); - input.type = 'file'; - input.accept = '.json'; + const input = document.createElement("input"); + input.type = "file"; + input.accept = ".json"; input.onchange = (e) => { const file = e.target.files[0]; if (file) { @@ -122,7 +104,7 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD const parsed = JSON.parse(content); setJsonData(JSON.stringify(parsed, null, 2)); } catch (error) { - alert('Invalid JSON file'); + alert("Invalid JSON file"); } }; reader.readAsText(file); @@ -132,9 +114,9 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD }; const loadLogFile = () => { - const input = document.createElement('input'); - input.type = 'file'; - input.accept = '.log,.jsonl,.ndjson'; + const input = document.createElement("input"); + input.type = "file"; + input.accept = ".log,.jsonl,.ndjson"; input.onchange = (e) => { const file = e.target.files[0]; if (file) { @@ -142,12 +124,12 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD reader.onload = (e) => { try { const content = e.target.result; - const lines = content.trim().split('\n'); - const logs = lines.map(line => JSON.parse(line)); + const lines = content.trim().split("\n"); + const logs = lines.map((line) => JSON.parse(line)); setJsonData(JSON.stringify(logs, null, 2)); - setJmespathExpression('[*].message'); + setJmespathExpression("[*].message"); } catch (error) { - alert('Invalid JSON Lines file'); + alert("Invalid JSON Lines file"); } }; reader.readAsText(file); @@ -162,8 +144,9 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD

- Validate and test JMESPath expressions against JSON data in real-time. - Enter your JMESPath query and JSON data below to see the results instantly. + Validate and test JMESPath expressions against JSON data in + real-time. Enter your JMESPath query and JSON data below to see the + results instantly.

@@ -218,13 +201,17 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD
-
- {error || 'Expression is correct'} +
+ + {error || "Expression is correct"} + {showReloadButton && (
-
+