From a5bc7cf6d1cff5be2a4551d0a050f14e58f2ad38 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Tue, 24 Mar 2026 19:00:02 +0100 Subject: [PATCH] fix: use self-portaling DetailPanel from design system v0.1.5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DetailPanel now portals itself to #cameleer-detail-panel-root (a div AppShell places as a sibling of .main in the top-level flex row). Pages just render inline — no manual createPortal, no context, no prop drilling. Remove the old #detail-panel-portal div from LayoutShell and the createPortal wrappers from Dashboard and AgentHealth. Co-Authored-By: Claude Opus 4.6 (1M context) --- ui/package-lock.json | 61 ++++++++++++------------ ui/package.json | 2 +- ui/src/components/LayoutShell.tsx | 2 - ui/src/pages/AgentHealth/AgentHealth.tsx | 22 ++++----- ui/src/pages/Dashboard/Dashboard.tsx | 22 ++++----- 5 files changed, 50 insertions(+), 59 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 7c8a7993..fac4beee 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -8,7 +8,7 @@ "name": "ui", "version": "0.0.0", "dependencies": { - "@cameleer/design-system": "^0.1.4", + "@cameleer/design-system": "file:../../design-system", "@tanstack/react-query": "^5.90.21", "openapi-fetch": "^0.17.0", "react": "^19.2.4", @@ -35,6 +35,34 @@ "vite": "^8.0.0" } }, + "../../design-system": { + "name": "@cameleer/design-system", + "version": "0.1.5", + "dependencies": { + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-router-dom": "^7.0.0" + }, + "devDependencies": { + "@playwright/test": "^1.58.2", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^16.3.0", + "@testing-library/user-event": "^14.6.1", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "@vitejs/plugin-react": "^4.3.0", + "happy-dom": "^20.8.4", + "typescript": "^5.6.0", + "vite": "^6.0.0", + "vite-plugin-dts": "^4.5.4", + "vitest": "^3.0.0" + }, + "peerDependencies": { + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-router-dom": "^7.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", @@ -276,19 +304,8 @@ } }, "node_modules/@cameleer/design-system": { - "version": "0.1.4", - "resolved": "https://gitea.siegeln.net/api/packages/cameleer/npm/%40cameleer%2Fdesign-system/-/0.1.4/design-system-0.1.4.tgz", - "integrity": "sha512-DWyHv/1Nr8/h56T2ny1dsOZGy9YK64hfajTMOsl7gkWF3PwLPiB9Hpapa4O2Y5T/sspegxdlSZSddHF7muyFbw==", - "dependencies": { - "react": "^19.0.0", - "react-dom": "^19.0.0", - "react-router-dom": "^7.0.0" - }, - "peerDependencies": { - "react": "^19.0.0", - "react-dom": "^19.0.0", - "react-router-dom": "^7.0.0" - } + "resolved": "../../design-system", + "link": true }, "node_modules/@emnapi/core": { "version": "1.9.1", @@ -2955,22 +2972,6 @@ } } }, - "node_modules/react-router-dom": { - "version": "7.13.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.2.tgz", - "integrity": "sha512-aR7SUORwTqAW0JDeiWF07e9SBE9qGpByR9I8kJT5h/FrBKxPMS6TiC7rmVO+gC0q52Bx7JnjWe8Z1sR9faN4YA==", - "license": "MIT", - "dependencies": { - "react-router": "7.13.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - } - }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", diff --git a/ui/package.json b/ui/package.json index b7c2f6ae..9fe73ba7 100644 --- a/ui/package.json +++ b/ui/package.json @@ -14,7 +14,7 @@ "generate-api:live": "curl -s http://localhost:8081/api/v1/api-docs -o src/api/openapi.json && openapi-typescript src/api/openapi.json -o src/api/schema.d.ts" }, "dependencies": { - "@cameleer/design-system": "^0.1.4", + "@cameleer/design-system": "^0.1.5", "@tanstack/react-query": "^5.90.21", "openapi-fetch": "^0.17.0", "react": "^19.2.4", diff --git a/ui/src/components/LayoutShell.tsx b/ui/src/components/LayoutShell.tsx index 33fac29e..f3abaef2 100644 --- a/ui/src/components/LayoutShell.tsx +++ b/ui/src/components/LayoutShell.tsx @@ -137,8 +137,6 @@ function LayoutContent() {
- {/* Portal target for DetailPanel — pages use createPortal to render here */} -
); } diff --git a/ui/src/pages/AgentHealth/AgentHealth.tsx b/ui/src/pages/AgentHealth/AgentHealth.tsx index e17ef5ac..0f0d363d 100644 --- a/ui/src/pages/AgentHealth/AgentHealth.tsx +++ b/ui/src/pages/AgentHealth/AgentHealth.tsx @@ -1,5 +1,4 @@ import { useState, useMemo } from 'react'; -import { createPortal } from 'react-dom'; import { useParams, Link } from 'react-router'; import { StatCard, StatusDot, Badge, MonoText, ProgressBar, @@ -504,18 +503,15 @@ export default function AgentHealth() {
)} - {/* Detail panel — portaled to AppShell level for proper slide-in */} - {selectedInstance && document.getElementById('detail-panel-portal') && - createPortal( - { setPanelOpen(false); setSelectedInstance(null); }} - title={selectedInstance.name ?? selectedInstance.id} - tabs={detailTabs} - />, - document.getElementById('detail-panel-portal')!, - ) - } + {/* Detail panel — auto-portals to AppShell level via design system */} + {selectedInstance && ( + { setPanelOpen(false); setSelectedInstance(null); }} + title={selectedInstance.name ?? selectedInstance.id} + tabs={detailTabs} + /> + )} ); } diff --git a/ui/src/pages/Dashboard/Dashboard.tsx b/ui/src/pages/Dashboard/Dashboard.tsx index 9035a147..fde1c879 100644 --- a/ui/src/pages/Dashboard/Dashboard.tsx +++ b/ui/src/pages/Dashboard/Dashboard.tsx @@ -1,5 +1,4 @@ import { useState, useMemo, useCallback } from 'react' -import { createPortal } from 'react-dom' import { useParams, useNavigate } from 'react-router' import { DataTable, @@ -415,14 +414,13 @@ export default function Dashboard() { {/* Shortcuts bar */} - {/* Detail panel — portaled to AppShell level for proper slide-in */} - {selectedRow && detail && document.getElementById('detail-panel-portal') && - createPortal( - setPanelOpen(false)} - title={`${detail.routeId} \u2014 ${selectedRow.executionId.slice(0, 12)}`} - > + {/* Detail panel — auto-portals to AppShell level via design system */} + {selectedRow && detail && ( + setPanelOpen(false)} + title={`${detail.routeId} \u2014 ${selectedRow.executionId.slice(0, 12)}`} + >
)} -
, - document.getElementById('detail-panel-portal')!, - ) - } +
+ )} ) }