Add Utility Agent UI to dashboard
This commit is contained in:
parent
8c31ec3eb1
commit
da30585e5a
|
|
@ -0,0 +1,140 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
|
||||||
|
export default function UtilitiesPage() {
|
||||||
|
const [firstEnergyUser, setFirstEnergyUser] = useState("");
|
||||||
|
const [firstEnergyPass, setFirstEnergyPass] = useState("");
|
||||||
|
const [peoplesGasUser, setPeoplesGasUser] = useState("");
|
||||||
|
const [peoplesGasPass, setPeoplesGasPass] = useState("");
|
||||||
|
const [status, setStatus] = useState("");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch('/proxy/utility/api/credentials')
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
|
setFirstEnergyUser(data.firstEnergyUser || "");
|
||||||
|
setPeoplesGasUser(data.peoplesGasUser || "");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(console.error);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleSave = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setStatus("Saving...");
|
||||||
|
try {
|
||||||
|
const res = await fetch('/proxy/utility/api/credentials', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
firstEnergyUser,
|
||||||
|
firstEnergyPass,
|
||||||
|
peoplesGasUser,
|
||||||
|
peoplesGasPass
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
if (data.success) {
|
||||||
|
setStatus("✅ Credentials saved securely.");
|
||||||
|
setFirstEnergyPass("");
|
||||||
|
setPeoplesGasPass("");
|
||||||
|
} else {
|
||||||
|
setStatus("❌ Failed to save.");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setStatus("❌ Network error.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRun = async () => {
|
||||||
|
setStatus("Starting scraper...");
|
||||||
|
try {
|
||||||
|
await fetch('/proxy/utility/api/run', { method: 'POST' });
|
||||||
|
setStatus("✅ Scraper triggered in background!");
|
||||||
|
} catch (e) {
|
||||||
|
setStatus("❌ Failed to run scraper.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ height: "100vh", width: "100vw", background: "#05070a", overflow: "hidden", color: "white", padding: "40px", fontFamily: "'Inter', sans-serif" }}>
|
||||||
|
<h1 style={{ fontSize: "2rem", marginBottom: "10px", background: "-webkit-linear-gradient(#fff, #888)", WebkitBackgroundClip: "text", WebkitTextFillColor: "transparent" }}>
|
||||||
|
Utility Agent Configuration
|
||||||
|
</h1>
|
||||||
|
<p style={{ color: "#888", marginBottom: "40px", maxWidth: "600px", lineHeight: "1.6" }}>
|
||||||
|
The Utility Agent securely automates retrieving your daily energy and gas usage data. It uses these credentials locally in your private cluster and sends a summary to your WhatsApp gateway.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form onSubmit={handleSave} style={{ display: "flex", flexDirection: "column", gap: "24px", maxWidth: "500px", background: "rgba(255,255,255,0.03)", padding: "30px", borderRadius: "16px", border: "1px solid rgba(255,255,255,0.1)", backdropFilter: "blur(10px)" }}>
|
||||||
|
|
||||||
|
{/* FirstEnergy */}
|
||||||
|
<div>
|
||||||
|
<h2 style={{ fontSize: "1.2rem", marginBottom: "16px", display: "flex", alignItems: "center", gap: "8px" }}>
|
||||||
|
<span style={{ fontSize: "1.5rem" }}>⚡</span> FirstEnergy
|
||||||
|
</h2>
|
||||||
|
<div style={{ display: "flex", flexDirection: "column", gap: "12px" }}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Username"
|
||||||
|
value={firstEnergyUser}
|
||||||
|
onChange={e => setFirstEnergyUser(e.target.value)}
|
||||||
|
style={{ width: "100%", padding: "12px 16px", borderRadius: "8px", border: "1px solid rgba(255,255,255,0.1)", background: "rgba(0,0,0,0.5)", color: "white", outline: "none", fontSize: "0.95rem" }}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
placeholder="Password (leave blank to keep current)"
|
||||||
|
value={firstEnergyPass}
|
||||||
|
onChange={e => setFirstEnergyPass(e.target.value)}
|
||||||
|
style={{ width: "100%", padding: "12px 16px", borderRadius: "8px", border: "1px solid rgba(255,255,255,0.1)", background: "rgba(0,0,0,0.5)", color: "white", outline: "none", fontSize: "0.95rem" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ height: "1px", background: "rgba(255,255,255,0.1)", margin: "8px 0" }}></div>
|
||||||
|
|
||||||
|
{/* Peoples Gas */}
|
||||||
|
<div>
|
||||||
|
<h2 style={{ fontSize: "1.2rem", marginBottom: "16px", display: "flex", alignItems: "center", gap: "8px" }}>
|
||||||
|
<span style={{ fontSize: "1.5rem" }}>🔥</span> Peoples Gas
|
||||||
|
</h2>
|
||||||
|
<div style={{ display: "flex", flexDirection: "column", gap: "12px" }}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Username"
|
||||||
|
value={peoplesGasUser}
|
||||||
|
onChange={e => setPeoplesGasUser(e.target.value)}
|
||||||
|
style={{ width: "100%", padding: "12px 16px", borderRadius: "8px", border: "1px solid rgba(255,255,255,0.1)", background: "rgba(0,0,0,0.5)", color: "white", outline: "none", fontSize: "0.95rem" }}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
placeholder="Password (leave blank to keep current)"
|
||||||
|
value={peoplesGasPass}
|
||||||
|
onChange={e => setPeoplesGasPass(e.target.value)}
|
||||||
|
style={{ width: "100%", padding: "12px 16px", borderRadius: "8px", border: "1px solid rgba(255,255,255,0.1)", background: "rgba(0,0,0,0.5)", color: "white", outline: "none", fontSize: "0.95rem" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{status && <div style={{ fontSize: "0.9rem", color: "#4ade80", background: "rgba(74, 222, 128, 0.1)", padding: "10px", borderRadius: "6px" }}>{status}</div>}
|
||||||
|
|
||||||
|
<div style={{ display: "flex", gap: "12px", marginTop: "8px" }}>
|
||||||
|
<button type="submit" style={{ flex: 1, padding: "14px", background: "linear-gradient(135deg, #3b82f6, #2563eb)", color: "white", border: "none", borderRadius: "8px", fontSize: "1rem", fontWeight: "600", cursor: "pointer", transition: "transform 0.1s" }}
|
||||||
|
onMouseOver={e => e.currentTarget.style.transform = "scale(1.02)"}
|
||||||
|
onMouseOut={e => e.currentTarget.style.transform = "scale(1)"}
|
||||||
|
>
|
||||||
|
Save Credentials
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button type="button" onClick={handleRun} style={{ padding: "14px", background: "rgba(255,255,255,0.1)", color: "white", border: "none", borderRadius: "8px", fontSize: "1rem", fontWeight: "600", cursor: "pointer", transition: "transform 0.1s" }}
|
||||||
|
onMouseOver={e => e.currentTarget.style.background = "rgba(255,255,255,0.15)"}
|
||||||
|
onMouseOut={e => e.currentTarget.style.background = "rgba(255,255,255,0.1)"}
|
||||||
|
>
|
||||||
|
▶ Run Now
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,10 @@ const nextConfig = {
|
||||||
{
|
{
|
||||||
source: '/proxy/gmail/:path*',
|
source: '/proxy/gmail/:path*',
|
||||||
destination: 'http://gmail-agent.ai-agents.svc.cluster.local:5002/:path*'
|
destination: 'http://gmail-agent.ai-agents.svc.cluster.local:5002/:path*'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
source: '/proxy/utility/:path*',
|
||||||
|
destination: 'http://utility-agent.ai-agents.svc.cluster.local:5005/:path*'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue