Files
Krow-workspace/internal/api-harness/src/pages/EntityTester.jsx
bwnyasse d43a14ee0c clean
2026-01-10 21:22:35 -05:00

191 lines
6.1 KiB
JavaScript

import { useState, useMemo } from "react";
import { krowSDK } from "@/api/krowSDK";
import { Button } from "@/components/ui/button";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import ApiResponse from "@/components/ApiResponse";
import { Textarea } from "@/components/ui/textarea";
import { Label } from "@/components/ui/label";
const entityNames = Object.keys(krowSDK.entities).sort();
const getPrettifiedJSON = (entity, method) => {
// Basic placeholder payloads. A more advanced SDK could provide detailed examples.
const payloads = {
get: { id: "some-id" },
create: { data: { property: "value" } },
update: { id: "some-id", data: { property: "new-value" } },
delete: { id: "some-id" },
filter: { where: { property: { _eq: "value" } } },
list: {}
};
return JSON.stringify(payloads[method] || {}, null, 2);
};
const EntityTester = () => {
const [selectedEntity, setSelectedEntity] = useState(null);
const [selectedMethod, setSelectedMethod] = useState(null);
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const [jsonInput, setJsonInput] = useState("");
const [jsonError, setJsonError] = useState(null);
const availableMethods = useMemo(() => {
if (!selectedEntity) return [];
return Object.keys(krowSDK.entities[selectedEntity]);
}, [selectedEntity]);
const handleEntityChange = (entity) => {
setSelectedEntity(entity);
setSelectedMethod(null);
setJsonInput("");
setJsonError(null);
setResponse(null);
setError(null);
};
const handleMethodSelect = (method) => {
setSelectedMethod(method);
setJsonInput(getPrettifiedJSON(selectedEntity, method));
setJsonError(null);
setResponse(null);
setError(null);
};
const handleJsonInputChange = (e) => {
setJsonInput(e.target.value);
try {
JSON.parse(e.target.value);
setJsonError(null);
} catch (err) {
setJsonError("Invalid JSON format");
}
};
const executeApi = async () => {
if (!selectedEntity || !selectedMethod || jsonError) return;
setLoading(true);
setResponse(null);
setError(null);
try {
const params = JSON.parse(jsonInput);
const sdkMethod = krowSDK.entities[selectedEntity][selectedMethod];
const res = await sdkMethod(params);
setResponse(res);
} catch (err) {
setError(err.response?.data || err.message);
} finally {
setLoading(false);
}
};
const renderMethodForm = () => {
if (!selectedMethod) {
return (
<div className="mt-4 p-4 text-center text-slate-500 bg-slate-50 rounded-lg">
<p>Select a method to begin.</p>
</div>
);
}
return (
<div className="space-y-4 mt-6">
<h3 className="text-lg font-semibold text-slate-800">
Parameters for <code className="bg-slate-100 p-1 rounded text-sm">/{selectedEntity}/{selectedMethod}</code>
</h3>
{/*
This is a textarea for JSON input. A more advanced implementation could
dynamically generate a form based on the expected parameters of each
SDK method, but that requires metadata about each method's signature
which is not currently available in the mock client.
*/}
<div className="space-y-2">
<Label htmlFor="params">JSON Payload</Label>
<Textarea
id="params"
name="params"
value={jsonInput}
onChange={handleJsonInputChange}
rows={8}
className={`font-mono text-sm ${jsonError ? 'border-red-500 focus-visible:ring-red-500' : ''}`}
/>
{jsonError && <p className="text-xs text-red-600">{jsonError}</p>}
</div>
<Button onClick={executeApi} disabled={loading || !!jsonError}>
{loading ? "Executing..." : "Execute"}
</Button>
</div>
);
};
return (
<div>
<header className="mb-8">
<h1 className="text-3xl font-bold text-slate-900">Entity API Tester</h1>
<p className="text-slate-600 mt-1">
Select an entity and method, provide the required parameters in JSON format, and execute the API call.
</p>
</header>
<Card className="shadow-sm">
<CardHeader>
<CardTitle>API Configuration</CardTitle>
<CardDescription>Choose a Base44 entity and method to interact with.</CardDescription>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 items-start">
<div className="col-span-1">
<Label>Entity</Label>
<Select onValueChange={handleEntityChange} value={selectedEntity || ""}>
<SelectTrigger>
<SelectValue placeholder="Select an entity" />
</SelectTrigger>
<SelectContent>
{entityNames.map(entity => (
<SelectItem key={entity} value={entity}>{entity}</SelectItem>
))}
</SelectContent>
</Select>
</div>
{selectedEntity && (
<div className="col-span-2">
<Label>Method</Label>
<div className="flex flex-wrap items-center gap-2 pt-2">
{availableMethods.map(method => (
<Button
key={method}
variant={selectedMethod === method ? "default" : "outline"}
size="sm"
onClick={() => handleMethodSelect(method)}
>
{method}
</Button>
))}
</div>
</div>
)}
</div>
{renderMethodForm()}
</CardContent>
</Card>
<ApiResponse response={response} error={error} loading={loading} />
</div>
);
};
export default EntityTester;