|
| 1 | +import { useState } from "react"; |
| 2 | +import { BASE } from "../lib/api"; |
| 3 | + |
| 4 | +const SERVER_BASE = BASE.replace(/\/api$/, ""); |
| 5 | + |
| 6 | +export default function Jenkins() { |
| 7 | + const [question, setQuestion] = useState(""); |
| 8 | + const [answer, setAnswer] = useState(""); |
| 9 | + const [error, setError] = useState<string | null>(null); |
| 10 | + const [loading, setLoading] = useState(false); |
| 11 | + |
| 12 | + async function handleAsk() { |
| 13 | + if (!question.trim()) return; |
| 14 | + setLoading(true); |
| 15 | + setError(null); |
| 16 | + setAnswer(""); |
| 17 | + try { |
| 18 | + const res = await fetch(`${SERVER_BASE}/jenkins/ask`, { |
| 19 | + method: "POST", |
| 20 | + headers: { "Content-Type": "application/json" }, |
| 21 | + credentials: "include", |
| 22 | + body: JSON.stringify({ question: question.trim() }), |
| 23 | + }); |
| 24 | + const data = await res.json().catch(() => ({})); |
| 25 | + if (!res.ok) throw new Error((data as any)?.error || res.statusText); |
| 26 | + setAnswer(data?.answer ?? ""); |
| 27 | + } catch (err: any) { |
| 28 | + setError(err?.message ?? "Request failed"); |
| 29 | + } finally { |
| 30 | + setLoading(false); |
| 31 | + } |
| 32 | + } |
| 33 | + |
| 34 | + return ( |
| 35 | + <section style={{ display: "grid", gap: 12 }}> |
| 36 | + <h1>Jenkins</h1> |
| 37 | + <textarea |
| 38 | + rows={4} |
| 39 | + value={question} |
| 40 | + onChange={(e) => setQuestion(e.target.value)} |
| 41 | + placeholder="Ask Jenkins about jobs or status" |
| 42 | + style={{ width: "100%", padding: 8, fontSize: 14 }} |
| 43 | + /> |
| 44 | + <div style={{ display: "flex", gap: 8 }}> |
| 45 | + <button onClick={handleAsk} disabled={loading || !question.trim()}> |
| 46 | + {loading ? "Sending..." : "Ask"} |
| 47 | + </button> |
| 48 | + <button |
| 49 | + type="button" |
| 50 | + onClick={() => { |
| 51 | + setQuestion(""); |
| 52 | + setAnswer(""); |
| 53 | + setError(null); |
| 54 | + }} |
| 55 | + > |
| 56 | + Clear |
| 57 | + </button> |
| 58 | + </div> |
| 59 | + {error && <div style={{ color: "red", fontSize: 13 }}>{error}</div>} |
| 60 | + <textarea |
| 61 | + readOnly |
| 62 | + value={answer} |
| 63 | + placeholder="Jenkins response will appear here" |
| 64 | + rows={6} |
| 65 | + style={{ width: "100%", padding: 8, fontSize: 14, background: "#f6f6f6" }} |
| 66 | + /> |
| 67 | + </section> |
| 68 | + ); |
| 69 | +} |
0 commit comments