Fix: the expression input box was getting reset while switching pages. Formatted the code text.
This commit is contained in:
129
src/App.js
129
src/App.js
@@ -1,16 +1,16 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from "react";
|
||||||
import Header from './components/Header';
|
import Header from "./components/Header";
|
||||||
import Footer from './components/Footer';
|
import Footer from "./components/Footer";
|
||||||
import MainPage from './components/MainPage';
|
import MainPage from "./components/MainPage";
|
||||||
import ApiKeyPage from './components/ApiKeyPage';
|
import ApiKeyPage from "./components/ApiKeyPage";
|
||||||
import './App.css';
|
import "./App.css";
|
||||||
|
|
||||||
// Utility function to generate a cryptographically secure API key
|
// Utility function to generate a cryptographically secure API key
|
||||||
function generateApiKey() {
|
function generateApiKey() {
|
||||||
const array = new Uint8Array(16);
|
const array = new Uint8Array(16);
|
||||||
|
|
||||||
// Use crypto.getRandomValues if available (browser), fallback for tests
|
// Use crypto.getRandomValues if available (browser), fallback for tests
|
||||||
if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
|
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
||||||
crypto.getRandomValues(array);
|
crypto.getRandomValues(array);
|
||||||
} else {
|
} else {
|
||||||
// Fallback for test environments - not cryptographically secure
|
// Fallback for test environments - not cryptographically secure
|
||||||
@@ -18,62 +18,86 @@ function generateApiKey() {
|
|||||||
array[i] = Math.floor(Math.random() * 256);
|
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
|
// JMESPath Testing Tool - Main Application Component
|
||||||
function App() {
|
function App() {
|
||||||
const [currentPage, setCurrentPage] = useState('main'); // 'main' or 'apikey'
|
const [currentPage, setCurrentPage] = useState("main"); // 'main' or 'apikey'
|
||||||
const [theme, setTheme] = useState(() => {
|
const [theme, setTheme] = useState(() => {
|
||||||
// Load theme from localStorage or default to 'auto'
|
// Load theme from localStorage or default to 'auto'
|
||||||
return localStorage.getItem('theme') || 'auto';
|
return localStorage.getItem("theme") || "auto";
|
||||||
});
|
});
|
||||||
const [showReloadButton, setShowReloadButton] = useState(false);
|
const [showReloadButton, setShowReloadButton] = useState(false);
|
||||||
const [currentStateGuid, setCurrentStateGuid] = useState(null);
|
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(() => {
|
const [apiKey, setApiKey] = useState(() => {
|
||||||
// Load API key from localStorage or generate new one
|
// 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)) {
|
if (stored && /^[0-9a-f]{32}$/i.test(stored)) {
|
||||||
return stored;
|
return stored;
|
||||||
}
|
}
|
||||||
const newKey = generateApiKey();
|
const newKey = generateApiKey();
|
||||||
localStorage.setItem('jmespath-api-key', newKey);
|
localStorage.setItem("jmespath-api-key", newKey);
|
||||||
return newKey;
|
return newKey;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Theme management
|
// Theme management
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const applyTheme = (selectedTheme) => {
|
const applyTheme = (selectedTheme) => {
|
||||||
const effectiveTheme = selectedTheme === 'auto'
|
const effectiveTheme =
|
||||||
? (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
|
selectedTheme === "auto"
|
||||||
: selectedTheme;
|
? window.matchMedia &&
|
||||||
|
window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||||
document.documentElement.setAttribute('data-bs-theme', effectiveTheme);
|
? "dark"
|
||||||
|
: "light"
|
||||||
|
: selectedTheme;
|
||||||
|
|
||||||
|
document.documentElement.setAttribute("data-bs-theme", effectiveTheme);
|
||||||
};
|
};
|
||||||
|
|
||||||
applyTheme(theme);
|
applyTheme(theme);
|
||||||
|
|
||||||
// Save theme preference
|
// Save theme preference
|
||||||
localStorage.setItem('theme', theme);
|
localStorage.setItem("theme", theme);
|
||||||
}, [theme]);
|
}, [theme]);
|
||||||
|
|
||||||
// Get headers for API requests
|
// Get headers for API requests
|
||||||
const getApiHeaders = () => {
|
const getApiHeaders = () => {
|
||||||
const headers = {
|
const headers = {
|
||||||
'Accept': 'application/json'
|
Accept: "application/json",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only send API key for non-localhost requests
|
// Only send API key for non-localhost requests
|
||||||
// For localhost, let server use its default LOCALHOST_API_KEY
|
// For localhost, let server use its default LOCALHOST_API_KEY
|
||||||
if (window.location.hostname !== 'localhost' &&
|
if (
|
||||||
window.location.hostname !== '127.0.0.1' &&
|
window.location.hostname !== "localhost" &&
|
||||||
!window.location.hostname.startsWith('127.') &&
|
window.location.hostname !== "127.0.0.1" &&
|
||||||
window.location.hostname !== '::1') {
|
!window.location.hostname.startsWith("127.") &&
|
||||||
headers['X-API-Key'] = apiKey;
|
window.location.hostname !== "::1"
|
||||||
|
) {
|
||||||
|
headers["X-API-Key"] = apiKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
return headers;
|
return headers;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -90,10 +114,10 @@ function App() {
|
|||||||
// Check if state has changed (new data uploaded)
|
// Check if state has changed (new data uploaded)
|
||||||
const checkStateChange = async () => {
|
const checkStateChange = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/v1/state', {
|
const response = await fetch("/api/v1/state", {
|
||||||
headers: getApiHeaders()
|
headers: getApiHeaders(),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const stateData = await response.json();
|
const stateData = await response.json();
|
||||||
if (stateData.state && stateData.state !== currentStateGuid) {
|
if (stateData.state && stateData.state !== currentStateGuid) {
|
||||||
@@ -109,19 +133,19 @@ function App() {
|
|||||||
const loadSampleData = async () => {
|
const loadSampleData = async () => {
|
||||||
try {
|
try {
|
||||||
setShowReloadButton(false);
|
setShowReloadButton(false);
|
||||||
const response = await fetch('/api/v1/sample', {
|
const response = await fetch("/api/v1/sample", {
|
||||||
headers: getApiHeaders()
|
headers: getApiHeaders(),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (data) {
|
if (data) {
|
||||||
setSampleData(data);
|
setJsonData(JSON.stringify(data, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update current state GUID
|
// Update current state GUID
|
||||||
const stateResponse = await fetch('/api/v1/state', {
|
const stateResponse = await fetch("/api/v1/state", {
|
||||||
headers: getApiHeaders()
|
headers: getApiHeaders(),
|
||||||
});
|
});
|
||||||
if (stateResponse.ok) {
|
if (stateResponse.ok) {
|
||||||
const stateData = await stateResponse.json();
|
const stateData = await stateResponse.json();
|
||||||
@@ -129,7 +153,7 @@ function App() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} 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 regenerateApiKey = () => {
|
||||||
const newKey = generateApiKey();
|
const newKey = generateApiKey();
|
||||||
setApiKey(newKey);
|
setApiKey(newKey);
|
||||||
localStorage.setItem('jmespath-api-key', newKey);
|
localStorage.setItem("jmespath-api-key", newKey);
|
||||||
setShowReloadButton(false);
|
setShowReloadButton(false);
|
||||||
setCurrentStateGuid(null);
|
setCurrentStateGuid(null);
|
||||||
};
|
};
|
||||||
@@ -152,7 +176,7 @@ function App() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container-fluid vh-100 d-flex flex-column">
|
<div className="container-fluid vh-100 d-flex flex-column">
|
||||||
<Header
|
<Header
|
||||||
theme={theme}
|
theme={theme}
|
||||||
onThemeChange={handleThemeChange}
|
onThemeChange={handleThemeChange}
|
||||||
currentPage={currentPage}
|
currentPage={currentPage}
|
||||||
@@ -160,19 +184,22 @@ function App() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Main Content Section - flex-grow to fill space */}
|
{/* Main Content Section - flex-grow to fill space */}
|
||||||
<div className="container-fluid flex-grow-1 d-flex flex-column" style={{ minHeight: 0 }}>
|
<div
|
||||||
{currentPage === 'main' ? (
|
className="container-fluid flex-grow-1 d-flex flex-column"
|
||||||
<MainPage
|
style={{ minHeight: 0 }}
|
||||||
|
>
|
||||||
|
{currentPage === "main" ? (
|
||||||
|
<MainPage
|
||||||
apiKey={apiKey}
|
apiKey={apiKey}
|
||||||
showReloadButton={showReloadButton}
|
showReloadButton={showReloadButton}
|
||||||
onReloadSampleData={loadSampleData}
|
onReloadSampleData={loadSampleData}
|
||||||
initialSampleData={sampleData}
|
jmespathExpression={jmespathExpression}
|
||||||
|
setJmespathExpression={setJmespathExpression}
|
||||||
|
jsonData={jsonData}
|
||||||
|
setJsonData={setJsonData}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ApiKeyPage
|
<ApiKeyPage apiKey={apiKey} onRegenerateApiKey={regenerateApiKey} />
|
||||||
apiKey={apiKey}
|
|
||||||
onRegenerateApiKey={regenerateApiKey}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -181,4 +208,4 @@ function App() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
@@ -1,41 +1,23 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from "react";
|
||||||
import jmespath from 'jmespath';
|
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]);
|
|
||||||
|
|
||||||
|
|
||||||
|
function MainPage({
|
||||||
|
showReloadButton,
|
||||||
|
onReloadSampleData,
|
||||||
|
jmespathExpression,
|
||||||
|
setJmespathExpression,
|
||||||
|
jsonData,
|
||||||
|
setJsonData,
|
||||||
|
}) {
|
||||||
|
const [result, setResult] = useState("");
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
const [jsonError, setJsonError] = useState("");
|
||||||
|
|
||||||
const evaluateExpression = () => {
|
const evaluateExpression = () => {
|
||||||
try {
|
try {
|
||||||
// Clear previous errors
|
// Clear previous errors
|
||||||
setError('');
|
setError("");
|
||||||
setJsonError('');
|
setJsonError("");
|
||||||
|
|
||||||
// Validate and parse JSON
|
// Validate and parse JSON
|
||||||
let parsedData;
|
let parsedData;
|
||||||
@@ -43,7 +25,7 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD
|
|||||||
parsedData = JSON.parse(jsonData);
|
parsedData = JSON.parse(jsonData);
|
||||||
} catch (jsonErr) {
|
} catch (jsonErr) {
|
||||||
setJsonError(`Invalid JSON: ${jsonErr.message}`);
|
setJsonError(`Invalid JSON: ${jsonErr.message}`);
|
||||||
setResult('');
|
setResult("");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,13 +34,13 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD
|
|||||||
|
|
||||||
// Format the result
|
// Format the result
|
||||||
if (queryResult === null || queryResult === undefined) {
|
if (queryResult === null || queryResult === undefined) {
|
||||||
setResult('null');
|
setResult("null");
|
||||||
} else {
|
} else {
|
||||||
setResult(JSON.stringify(queryResult, null, 2));
|
setResult(JSON.stringify(queryResult, null, 2));
|
||||||
}
|
}
|
||||||
} catch (jmesErr) {
|
} catch (jmesErr) {
|
||||||
setError(`JMESPath Error: ${jmesErr.message}`);
|
setError(`JMESPath Error: ${jmesErr.message}`);
|
||||||
setResult('');
|
setResult("");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -88,30 +70,30 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD
|
|||||||
};
|
};
|
||||||
|
|
||||||
const clearAll = () => {
|
const clearAll = () => {
|
||||||
setJmespathExpression('');
|
setJmespathExpression("");
|
||||||
setJsonData('');
|
setJsonData("");
|
||||||
setResult('');
|
setResult("");
|
||||||
setError('');
|
setError("");
|
||||||
setJsonError('');
|
setJsonError("");
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadSample = () => {
|
const loadSample = () => {
|
||||||
const sampleData = {
|
const sampleData = {
|
||||||
"users": [
|
users: [
|
||||||
{"name": "Alice", "age": 30, "city": "New York"},
|
{ name: "Alice", age: 30, city: "New York" },
|
||||||
{"name": "Bob", "age": 25, "city": "San Francisco"},
|
{ name: "Bob", age: 25, city: "San Francisco" },
|
||||||
{"name": "Charlie", "age": 35, "city": "Chicago"}
|
{ name: "Charlie", age: 35, city: "Chicago" },
|
||||||
],
|
],
|
||||||
"total": 3
|
total: 3,
|
||||||
};
|
};
|
||||||
setJsonData(JSON.stringify(sampleData, null, 2));
|
setJsonData(JSON.stringify(sampleData, null, 2));
|
||||||
setJmespathExpression('users[?age > `30`].name');
|
setJmespathExpression("users[?age > `30`].name");
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadFromDisk = () => {
|
const loadFromDisk = () => {
|
||||||
const input = document.createElement('input');
|
const input = document.createElement("input");
|
||||||
input.type = 'file';
|
input.type = "file";
|
||||||
input.accept = '.json';
|
input.accept = ".json";
|
||||||
input.onchange = (e) => {
|
input.onchange = (e) => {
|
||||||
const file = e.target.files[0];
|
const file = e.target.files[0];
|
||||||
if (file) {
|
if (file) {
|
||||||
@@ -122,7 +104,7 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD
|
|||||||
const parsed = JSON.parse(content);
|
const parsed = JSON.parse(content);
|
||||||
setJsonData(JSON.stringify(parsed, null, 2));
|
setJsonData(JSON.stringify(parsed, null, 2));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert('Invalid JSON file');
|
alert("Invalid JSON file");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
@@ -132,9 +114,9 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD
|
|||||||
};
|
};
|
||||||
|
|
||||||
const loadLogFile = () => {
|
const loadLogFile = () => {
|
||||||
const input = document.createElement('input');
|
const input = document.createElement("input");
|
||||||
input.type = 'file';
|
input.type = "file";
|
||||||
input.accept = '.log,.jsonl,.ndjson';
|
input.accept = ".log,.jsonl,.ndjson";
|
||||||
input.onchange = (e) => {
|
input.onchange = (e) => {
|
||||||
const file = e.target.files[0];
|
const file = e.target.files[0];
|
||||||
if (file) {
|
if (file) {
|
||||||
@@ -142,12 +124,12 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD
|
|||||||
reader.onload = (e) => {
|
reader.onload = (e) => {
|
||||||
try {
|
try {
|
||||||
const content = e.target.result;
|
const content = e.target.result;
|
||||||
const lines = content.trim().split('\n');
|
const lines = content.trim().split("\n");
|
||||||
const logs = lines.map(line => JSON.parse(line));
|
const logs = lines.map((line) => JSON.parse(line));
|
||||||
setJsonData(JSON.stringify(logs, null, 2));
|
setJsonData(JSON.stringify(logs, null, 2));
|
||||||
setJmespathExpression('[*].message');
|
setJmespathExpression("[*].message");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert('Invalid JSON Lines file');
|
alert("Invalid JSON Lines file");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
@@ -162,8 +144,9 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD
|
|||||||
<div className="row mb-2">
|
<div className="row mb-2">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<p className="text-muted text-center mb-2 small">
|
<p className="text-muted text-center mb-2 small">
|
||||||
Validate and test JMESPath expressions against JSON data in real-time.
|
Validate and test JMESPath expressions against JSON data in
|
||||||
Enter your JMESPath query and JSON data below to see the results instantly.
|
real-time. Enter your JMESPath query and JSON data below to see the
|
||||||
|
results instantly.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -218,13 +201,17 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD
|
|||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className={`form-control jmespath-input ${error ? 'error' : 'success'}`}
|
className={`form-control jmespath-input ${error ? "error" : "success"}`}
|
||||||
value={jmespathExpression}
|
value={jmespathExpression}
|
||||||
onChange={handleJmespathChange}
|
onChange={handleJmespathChange}
|
||||||
placeholder="Enter JMESPath expression (e.g., people[*].name)"
|
placeholder="Enter JMESPath expression (e.g., people[*].name)"
|
||||||
/>
|
/>
|
||||||
<div className={`alert mt-2 mb-0 d-flex justify-content-between align-items-center ${error ? 'alert-danger' : 'alert-success'}`}>
|
<div
|
||||||
<small className="mb-0">{error || 'Expression is correct'}</small>
|
className={`alert mt-2 mb-0 d-flex justify-content-between align-items-center ${error ? "alert-danger" : "alert-success"}`}
|
||||||
|
>
|
||||||
|
<small className="mb-0">
|
||||||
|
{error || "Expression is correct"}
|
||||||
|
</small>
|
||||||
{showReloadButton && (
|
{showReloadButton && (
|
||||||
<button
|
<button
|
||||||
className="btn btn-light btn-sm ms-2 border"
|
className="btn btn-light btn-sm ms-2 border"
|
||||||
@@ -254,13 +241,16 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD
|
|||||||
JSON Data
|
JSON Data
|
||||||
</h6>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
<div className="card-body flex-grow-1 d-flex flex-column" style={{ minHeight: 0 }}>
|
<div
|
||||||
|
className="card-body flex-grow-1 d-flex flex-column"
|
||||||
|
style={{ minHeight: 0 }}
|
||||||
|
>
|
||||||
<textarea
|
<textarea
|
||||||
className={`form-control json-input flex-grow-1 ${jsonError ? 'error' : 'success'}`}
|
className={`form-control json-input flex-grow-1 ${jsonError ? "error" : "success"}`}
|
||||||
value={jsonData}
|
value={jsonData}
|
||||||
onChange={handleJsonChange}
|
onChange={handleJsonChange}
|
||||||
placeholder="Enter JSON data here..."
|
placeholder="Enter JSON data here..."
|
||||||
style={{ minHeight: 0, resize: 'none' }}
|
style={{ minHeight: 0, resize: "none" }}
|
||||||
/>
|
/>
|
||||||
{jsonError && (
|
{jsonError && (
|
||||||
<div className="alert alert-danger mt-2 mb-0">
|
<div className="alert alert-danger mt-2 mb-0">
|
||||||
@@ -280,13 +270,16 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD
|
|||||||
Results
|
Results
|
||||||
</h6>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
<div className="card-body flex-grow-1 d-flex flex-column" style={{ minHeight: 0 }}>
|
<div
|
||||||
|
className="card-body flex-grow-1 d-flex flex-column"
|
||||||
|
style={{ minHeight: 0 }}
|
||||||
|
>
|
||||||
<textarea
|
<textarea
|
||||||
className="form-control result-output flex-grow-1"
|
className="form-control result-output flex-grow-1"
|
||||||
value={result}
|
value={result}
|
||||||
readOnly
|
readOnly
|
||||||
placeholder="Results will appear here..."
|
placeholder="Results will appear here..."
|
||||||
style={{ minHeight: 0, resize: 'none' }}
|
style={{ minHeight: 0, resize: "none" }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -296,4 +289,4 @@ function MainPage({ apiKey, showReloadButton, onReloadSampleData, initialSampleD
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MainPage;
|
export default MainPage;
|
||||||
|
|||||||
Reference in New Issue
Block a user