sandbox-wave8-pod-spawn
1 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2c6595a378
|
feat(openova-flow): npm workspaces + FlowPage canvas real-adapter rewire (Agent #5) (#1399)
Lands the OpenovaFlow Foundation end-to-end so the catalyst-ui FlowPage
consumes the new openova-flow-server's merged multi-region SSE stream
(`GET /api/v1/flows/{deploymentId}/stream`) and renders the per-region
adapter-flux emissions directly via @openova/flow-canvas. Closes the
revert from PR #1394 and unblocks the prov #34 multi-region 2-bubble
demo (fsn1 + hel1 each install bp-gateway-api → two bubbles).
# What ships
## A. npm workspaces at repo root
• New `package.json` declares `openova-monorepo` private root with
three workspaces: products/openova-flow/{core,canvas} +
products/catalyst/bootstrap/ui.
• Root `package-lock.json` resolves @openova/flow-* as workspace
symlinks into the hoisted node_modules tree.
• react / react-dom / d3-* are now hoisted into the monorepo's root
node_modules, so flow-canvas's bare `import 'react'` resolves via
standard upward-walking node_modules — no per-package sibling
node_modules required (the root cause of PR #1389's build break).
## B. Catalyst-ui consumes @openova/flow-* via file: deps
• catalyst-ui's `package.json` adds `@openova/flow-core` and
`@openova/flow-canvas` as `file:../../../openova-flow/{core,canvas}`
deps so `npm ci` from within catalyst-ui (today's CI path) keeps
working without needing root-level `npm ci -ws`.
• Vite `resolve.alias` + tsconfig `paths` bind `@openova/flow-core`
and `@openova/flow-canvas` to the source-only `./src/index.ts`
entry points. `dedupe: ['react', 'react-dom']` guards against
double-instancing.
• `tsconfig.app.json` `include` adds the two flow-package src trees
so tsc covers them with catalyst-ui's strict settings (instead of
each package's standalone `tsc -p tsconfig.json`, which lacks the
React/d3 node_modules siblings).
## C. New SSE consumer + bridge
• `src/lib/openflow-adapter-sse.ts` — `useFlowStream` React hook +
pure `reduceFlowMessage` reducer. Consumes the contract verbatim
(snapshot / upsert-flow / upsert-nodes / upsert-rels / delete-nodes
/ delete-rels). Owns the EventSource lifecycle, GET /snapshot
pre-paint, capped exponential reconnect.
• `src/lib/flow-bridge.ts` — catalyst-specific glue:
`CATALYST_STATUS_PALETTE` (mirrors `--bubble-*` CSS tokens onto
`StatusTone`), `flowStateToArrays` (Map→Array materialiser),
`regionDescriptorsFromFlow` (derives FlowCanvas regions from live
region tags + optional wizard-store augmentation), and
`rollupFlowStatus` (provisioning-status rollup on the new
contract).
• NOT a Job-shape bridge — the legacy Job adapter from PR #1389
is gone. catalyst-ui never goes through Catalyst's legacy Job model
again; the SSE stream IS the source of truth.
## D. FlowPage.tsx rewired
• Drives `FlowCanvas` from `@openova/flow-canvas` directly off the
new hook.
• Multi-region support comes for free: per-region adapter-flux tags
every emitted FlowNode with `region: '<location-code>'`; the
canvas's swimlane layout buckets by `region`. Single-region
provisions render identically to before via a synthetic
fallback descriptor.
• Embedded mode preserved for JobDetail.
## E. Containerfile preserves CI build
• COPY products/openova-flow/{core,canvas}/{package.json,src/}
BEFORE `npm ci` so `file:` deps validate. Subsequent
`COPY products/` layers the rest (CONTRACT.md etc.) in.
# Tests
• 23 new tests, 0 regressions on adjacent areas:
- `openflow-adapter-sse.test.ts` (6) — reducer covers all 6
FlowMessage variants including delete-nodes' rel-prune cascade
AND a multi-region merge case (fsn1 + hel1 both install
bp-gateway-api).
- `flow-bridge.test.ts` (10) — palette completeness, Map→Array
ordering, region descriptor derivation/fallback, status rollup
including group-exclusion and terminal-failure detection.
- `FlowPage.test.tsx` (7) — empty-state mount, StatusStrip, no
legacy mode toggle, embedded variant.
• flow-core: 20/20 passing; flow-canvas: 9/9 passing.
• Vitest full suite: 1130 pass / 87 fail (87 fails are pre-existing
on main and unrelated — PinInput6, ProvisionPage, etc.). Baseline
on main is 1052 pass / 88 fail / 27 failed files; this PR brings
78 new passing tests and lowers failing files from 27 → 18.
# Constraints honoured (Rule 7)
• NO `vite build` / `next build` / `npm run build` / `npx playwright
test` / `npx playwright install`. Only `tsc --noEmit` + `vitest
run` + `npm install --package-lock-only`.
• NO `kubectl apply` / chart manifests touched (Rule 11).
• NO hardcoded URLs / regions / k3s flags. Endpoint composed from
`API_BASE`; regions derived from live FlowNode tags; deploymentId
from `useParams` (Rule 18).
• Two-repo discipline: openova-io/openova only (Rule 21).
• Conventional commit + Claude co-author footer (Rule 20).
• isolation:"worktree" — work landed in a dedicated worktree.
# Canonical-seam citations (ARCHITECT-FIRST)
1. PR #1389's `flow-bridge.ts` — reference for the shape of a
catalyst-ui→@openova/flow contract layer. NOT conflated: that
bridge translated legacy Catalyst Jobs into FlowNodes; this one
consumes the new SSE FlowMessage stream directly with no Job
intermediary.
2. `useDeploymentEvents.ts` (line 526+, `openStream` + `onerror`
reconnect + capped retry) — canonical SSE consumer pattern in
this codebase. `useFlowStream` mirrors it (capped exponential
backoff, idempotent reducer over replayed buffered events).
# Definition of Done — post-merge verification plan
1. CI green (catalyst-build builds the new Containerfile path).
2. `curl -k -b /tmp/cz-cookie-prov27.txt
'https://console.openova.io/sovereign/api/v1/flows/5a175e0a88c99cec/snapshot' | jq`
→ nodes[] contains BOTH `fsn1/bp-gateway-api` AND `hel1/bp-gateway-api`.
3. Browser test: navigate to
`https://console.openova.io/sovereign/provision/5a175e0a88c99cec/jobs/install-gateway-api`
→ expect TWO bubbles (one per region).
4. If snapshot is empty, inspect emitter DaemonSets:
`kubectl --context=omantel get pods -n openova-flow`.
Co-authored-by: hatiyildiz <269457768+hatiyildiz@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|