diff --git a/interface/hq-dashboard/app/api/trips/[id]/route.js b/interface/hq-dashboard/app/api/trips/[id]/route.js new file mode 100644 index 0000000..4a0411e --- /dev/null +++ b/interface/hq-dashboard/app/api/trips/[id]/route.js @@ -0,0 +1,30 @@ +import { NextResponse } from 'next/server'; + +const TRIP_SERVICE_URL = 'http://trip-service.ai-agents.svc.cluster.local:6002'; + +export async function PUT(req, { params }) { + try { + const body = await req.json(); + const res = await fetch(`${TRIP_SERVICE_URL}/trips/${params.id}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body) + }); + const data = await res.json(); + return NextResponse.json(data); + } catch (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } +} + +export async function DELETE(req, { params }) { + try { + const res = await fetch(`${TRIP_SERVICE_URL}/trips/${params.id}`, { + method: 'DELETE' + }); + const data = await res.json(); + return NextResponse.json(data); + } catch (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } +} diff --git a/interface/hq-dashboard/app/api/trips/[id]/test/route.js b/interface/hq-dashboard/app/api/trips/[id]/test/route.js new file mode 100644 index 0000000..5ce4813 --- /dev/null +++ b/interface/hq-dashboard/app/api/trips/[id]/test/route.js @@ -0,0 +1,15 @@ +import { NextResponse } from 'next/server'; + +const TRIP_SERVICE_URL = 'http://trip-service.ai-agents.svc.cluster.local:6002'; + +export async function POST(req, { params }) { + try { + const res = await fetch(`${TRIP_SERVICE_URL}/trips/${params.id}/test`, { + method: 'POST' + }); + const data = await res.json(); + return NextResponse.json(data); + } catch (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } +} diff --git a/interface/hq-dashboard/app/api/trips/route.js b/interface/hq-dashboard/app/api/trips/route.js new file mode 100644 index 0000000..5653de8 --- /dev/null +++ b/interface/hq-dashboard/app/api/trips/route.js @@ -0,0 +1,28 @@ +import { NextResponse } from 'next/server'; + +const TRIP_SERVICE_URL = 'http://trip-service.ai-agents.svc.cluster.local:6002'; + +export async function GET() { + try { + const res = await fetch(`${TRIP_SERVICE_URL}/trips`, { cache: 'no-store' }); + const data = await res.json(); + return NextResponse.json(data); + } catch (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } +} + +export async function POST(req) { + try { + const body = await req.json(); + const res = await fetch(`${TRIP_SERVICE_URL}/trips`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body) + }); + const data = await res.json(); + return NextResponse.json(data); + } catch (error) { + return NextResponse.json({ error: error.message }, { status: 500 }); + } +} diff --git a/interface/hq-dashboard/app/page.jsx b/interface/hq-dashboard/app/page.jsx index c5b1d73..2f48c8d 100644 --- a/interface/hq-dashboard/app/page.jsx +++ b/interface/hq-dashboard/app/page.jsx @@ -26,7 +26,8 @@ import { CloudSun, Wind, Droplets, - Thermometer + Thermometer, + Compass } from "lucide-react"; export default function Page() { @@ -90,6 +91,13 @@ export default function Page() { { id: "wf-ops-003", name: "OpsRemediateWorkflow", agent: "OpsAgent", target: "VMID 102", status: "running", result: "Awaiting approval signal" } ]); + // Trips State + const [tripsList, setTripsList] = useState([]); + const [selectedTripId, setSelectedTripId] = useState(null); + const [tripEditorJson, setTripEditorJson] = useState(""); + const [isSavingTrip, setIsSavingTrip] = useState(false); + const [isTestingTrip, setIsTestingTrip] = useState(false); + const messagesEndRef = useRef(null); const terminalEndRef = useRef(null); @@ -101,6 +109,14 @@ export default function Page() { terminalEndRef.current?.scrollIntoView({ behavior: "smooth" }); }, [clawTerminalLogs]); + useEffect(() => { + if (activeTab === "trips") { + fetch('/api/trips').then(res => res.json()).then(data => { + if(Array.isArray(data)) setTripsList(data); + }).catch(() => {}); + } + }, [activeTab]); + // Simulated Claw response logic const handleSendMessage = async (e) => { e.preventDefault(); @@ -523,6 +539,51 @@ export default function Page() { setIsProcessingClinical(false); }; + const handleSaveTrip = async () => { + try { + setIsSavingTrip(true); + let parsed = JSON.parse(tripEditorJson); + if (selectedTripId) { + await fetch(`/api/trips/${selectedTripId}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(parsed) + }); + } else { + await fetch('/api/trips', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(parsed) + }); + } + const data = await fetch('/api/trips').then(r => r.json()); + setTripsList(Array.isArray(data) ? data : []); + setSelectedTripId(null); + setTripEditorJson(""); + } catch (e) { + alert("Invalid JSON or save failed: " + e.message); + } finally { + setIsSavingTrip(false); + } + }; + + const handleTestTrip = async (id) => { + setIsTestingTrip(true); + try { + const res = await fetch(`/api/trips/${id}/test`, { method: 'POST' }); + const data = await res.json(); + if (data.success) { + alert("Test briefing fired to WhatsApp successfully!"); + } else { + alert("Test failed: " + JSON.stringify(data)); + } + } catch (e) { + alert("Error triggering test: " + e.message); + } finally { + setIsTestingTrip(false); + } + }; + return (