Demonstrates the compose-as-source-of-truth path (ADR-026): import an existing docker-compose.yml into typed Scores, then build/publish/deploy with the fleet pattern (no ApplicationScore, no ArgoCD). - compose.rs: docker-compose-types → typed ComposeApp; loud on bind mounts / unparseable ports, warns on depends_on/command/restart. - chart.rs: per-service Deployment+Service (unique filenames), RWX PVC per mounted named volume, RollingUpdate/Recreate strategy. Deploy-only knobs live here, never in compose or Harmony.toml. - score.rs: ComposeAppScore = helm upgrade --install + public Ingress. - publish.rs: docker build/push each built service + helm package/push. - app/: minimal real Java(SQLite)+React(nginx) compose stack. - 16 unit tests over import + chart generation.
49 lines
1.1 KiB
JavaScript
49 lines
1.1 KiB
JavaScript
import { useEffect, useState } from "react";
|
|
|
|
export default function App() {
|
|
const [entries, setEntries] = useState([]);
|
|
const [note, setNote] = useState("");
|
|
|
|
const load = () =>
|
|
fetch("/api/entries")
|
|
.then((r) => r.json())
|
|
.then(setEntries);
|
|
|
|
useEffect(() => {
|
|
load();
|
|
}, []);
|
|
|
|
const submit = async (e) => {
|
|
e.preventDefault();
|
|
if (!note.trim()) return;
|
|
await fetch("/api/entries", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ note }),
|
|
});
|
|
setNote("");
|
|
load();
|
|
};
|
|
|
|
return (
|
|
<main style={{ fontFamily: "sans-serif", maxWidth: 600, margin: "2rem auto" }}>
|
|
<h1>Timesheet</h1>
|
|
<form onSubmit={submit}>
|
|
<input
|
|
value={note}
|
|
onChange={(e) => setNote(e.target.value)}
|
|
placeholder="What did you work on?"
|
|
/>
|
|
<button type="submit">Add</button>
|
|
</form>
|
|
<ul>
|
|
{entries.map((e) => (
|
|
<li key={e.id}>
|
|
{e.note} <small>({e.created_at})</small>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</main>
|
|
);
|
|
}
|