133 lines
3.8 KiB
JavaScript
133 lines
3.8 KiB
JavaScript
(function() {
|
|
const SDK = window.__HERMES_PLUGIN_SDK__;
|
|
const { useState, useEffect, useCallback } = React;
|
|
|
|
function SSHXPage() {
|
|
const [link, setLink] = useState(null);
|
|
const [status, setStatus] = useState("idle"); // idle | loading | running | error
|
|
const [error, setError] = useState(null);
|
|
|
|
const startSSHX = useCallback(async () => {
|
|
setStatus("loading");
|
|
setError(null);
|
|
try {
|
|
const res = await SDK.fetchJSON("/api/plugins/sshx-link/start");
|
|
if (res.link) {
|
|
setLink(res.link);
|
|
setStatus("running");
|
|
} else {
|
|
setError(res.message || "No link returned");
|
|
setStatus("error");
|
|
}
|
|
} catch (err) {
|
|
setError(err.message || "Failed to start sshx");
|
|
setStatus("error");
|
|
}
|
|
}, []);
|
|
|
|
const stopSSHX = useCallback(async () => {
|
|
try {
|
|
await fetch("/api/plugins/sshx-link/stop", { method: "POST" });
|
|
setLink(null);
|
|
setStatus("idle");
|
|
} catch (err) {
|
|
setError(err.message);
|
|
}
|
|
}, []);
|
|
|
|
const checkStatus = useCallback(async () => {
|
|
try {
|
|
const res = await SDK.fetchJSON("/api/plugins/sshx-link/status");
|
|
if (res.status === "running" && res.link) {
|
|
setLink(res.link);
|
|
setStatus("running");
|
|
}
|
|
} catch (_) {}
|
|
}, []);
|
|
|
|
useEffect(() => { checkStatus(); }, [checkStatus]);
|
|
|
|
return (
|
|
<div style={{ padding: "2rem", maxWidth: 600, margin: "0 auto" }}>
|
|
<h1 style={{ fontSize: "1.5rem", fontWeight: 600, marginBottom: "1rem" }}>
|
|
SSHX Shared Terminal
|
|
</h1>
|
|
<p style={{ color: "#888", marginBottom: "1.5rem" }}>
|
|
Start a shared terminal session. Others can join via the link.
|
|
</p>
|
|
|
|
{status === "running" && link ? (
|
|
<div style={{
|
|
background: "#1a1a2e",
|
|
border: "1px solid #0f3460",
|
|
borderRadius: 8,
|
|
padding: "1.5rem",
|
|
marginBottom: "1rem"
|
|
}}>
|
|
<p style={{ color: "#4ade80", fontWeight: 600, marginBottom: "0.5rem" }}>
|
|
Running
|
|
</p>
|
|
<a
|
|
href={link}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
style={{
|
|
color: "#60a5fa",
|
|
fontSize: "1.1rem",
|
|
wordBreak: "break-all",
|
|
textDecoration: "underline"
|
|
}}
|
|
>
|
|
{link}
|
|
</a>
|
|
<div style={{ marginTop: "1rem" }}>
|
|
<button
|
|
onClick={stopSSHX}
|
|
style={{
|
|
background: "#dc2626",
|
|
color: "#fff",
|
|
border: "none",
|
|
borderRadius: 6,
|
|
padding: "0.5rem 1rem",
|
|
cursor: "pointer",
|
|
fontWeight: 500
|
|
}}
|
|
>
|
|
Stop
|
|
</button>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<button
|
|
onClick={startSSHX}
|
|
disabled={status === "loading"}
|
|
style={{
|
|
background: status === "loading" ? "#555" : "#2563eb",
|
|
color: "#fff",
|
|
border: "none",
|
|
borderRadius: 6,
|
|
padding: "0.7rem 1.5rem",
|
|
cursor: status === "loading" ? "not-allowed" : "pointer",
|
|
fontWeight: 500,
|
|
fontSize: "1rem"
|
|
}}
|
|
>
|
|
{status === "loading" ? "Starting..." : "Start SSHX"}
|
|
</button>
|
|
)}
|
|
|
|
{error && (
|
|
<p style={{ color: "#f87171", marginTop: "1rem" }}>
|
|
Error: {error}
|
|
</p>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Register the tab component
|
|
if (window.__HERMES_PLUGINS__) {
|
|
window.__HERMES_PLUGINS__.register("sshx-link", SSHXPage);
|
|
}
|
|
})();
|