Prepared demo files and demo explanation file. Added debug only button to trigger demo file ingest on the server to queue and prepare the files. Added small expressjs server for talking between the web app and the rust engine containers.
This commit is contained in:
parent
381b7b8858
commit
a03969e497
28 changed files with 232 additions and 7 deletions
|
|
@ -6,4 +6,4 @@ RUN npm ci
|
|||
COPY . .
|
||||
RUN npm run format && npm run build
|
||||
EXPOSE 3000
|
||||
CMD ["npm", "run", "preview"]
|
||||
CMD ["node", "server.mjs"]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./"
|
||||
"baseUrl": "./",
|
||||
"lib": ["es2015", "dom"]
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
|
|
|||
44
web-app/server.mjs
Normal file
44
web-app/server.mjs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import express from 'express';
|
||||
import path from 'node:path';
|
||||
import helmet from 'helmet';
|
||||
import cors from 'cors';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 3000;
|
||||
const RUST_ENGINE_BASE = process.env.RUST_ENGINE_BASE || 'http://rust-engine:8000';
|
||||
|
||||
app.use(helmet());
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
// Proxy minimal API needed by the UI to the rust-engine container
|
||||
app.post('/api/files/import-demo', async (req, res) => {
|
||||
try {
|
||||
const qs = req.url.includes('?') ? req.url.substring(req.url.indexOf('?')) : '';
|
||||
const url = `${RUST_ENGINE_BASE}/api/files/import-demo${qs}`;
|
||||
const upstream = await fetch(url, { method: 'POST' });
|
||||
const text = await upstream.text();
|
||||
res.status(upstream.status).type(upstream.headers.get('content-type') || 'application/json').send(text);
|
||||
} catch (err) {
|
||||
console.error('import-demo proxy failed:', err);
|
||||
res.status(502).json({ error: 'proxy_failed' });
|
||||
}
|
||||
});
|
||||
|
||||
// Serve static frontend
|
||||
const distDir = path.resolve(__dirname, 'dist');
|
||||
app.use(express.static(distDir));
|
||||
|
||||
// SPA fallback
|
||||
app.get('*', (req, res) => {
|
||||
res.sendFile(path.join(distDir, 'index.html'));
|
||||
});
|
||||
|
||||
app.listen(PORT, '0.0.0.0', () => {
|
||||
console.log(`Web app server listening on http://0.0.0.0:${PORT}`);
|
||||
console.log(`Proxying to rust engine at ${RUST_ENGINE_BASE}`);
|
||||
});
|
||||
|
|
@ -1,14 +1,54 @@
|
|||
import React from "react";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { motion } from "motion/react";
|
||||
import { Rocket } from "lucide-react";
|
||||
|
||||
export default function ChatHeader({ title = "Title of Chat" }) {
|
||||
const isDebug = useMemo(() => {
|
||||
const p = new URLSearchParams(window.location.search);
|
||||
return p.get("debug") === "1";
|
||||
}, []);
|
||||
const [ingesting, setIngesting] = useState(false);
|
||||
const [toast, setToast] = useState("");
|
||||
|
||||
async function triggerDemoIngest() {
|
||||
try {
|
||||
setIngesting(true);
|
||||
const res = await fetch("/api/files/import-demo", { method: "POST" });
|
||||
const json = await res.json().catch(() => ({}));
|
||||
setToast(`Imported: ${json.imported ?? "?"}, Skipped: ${json.skipped ?? "?"}`);
|
||||
setTimeout(() => setToast(""), 4000);
|
||||
} catch (e) {
|
||||
setToast("Import failed");
|
||||
setTimeout(() => setToast(""), 4000);
|
||||
} finally {
|
||||
setIngesting(false);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div className="w-full flex justify-center">
|
||||
<header className="text-slate-100 fixed top-4 ">
|
||||
<div>
|
||||
<div className="flex items-center gap-3">
|
||||
<h1 className="text-lg font-semibold shadow-md shadow-indigo-600 bg-gray-900 px-6 py-2 rounded-4xl border-2 border-gray-800">
|
||||
{title}
|
||||
</h1>
|
||||
{isDebug && (
|
||||
<motion.button
|
||||
onClick={triggerDemoIngest}
|
||||
className="bg-gray-800 border-2 border-gray-700 rounded-xl px-3 py-2 flex items-center gap-2"
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
disabled={ingesting}
|
||||
>
|
||||
<Rocket size={16} />
|
||||
{ingesting ? "Seeding…" : "Seed Demo Data"}
|
||||
</motion.button>
|
||||
)}
|
||||
</div>
|
||||
{toast && (
|
||||
<div className="mt-2 text-xs text-slate-300 bg-gray-800/80 border border-gray-700 rounded px-2 py-1 inline-block">
|
||||
{toast}
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue