fix: use self-portaling DetailPanel from design system v0.1.5
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 <DetailPanel> 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) <noreply@anthropic.com>
This commit is contained in:
61
ui/package-lock.json
generated
61
ui/package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -137,8 +137,6 @@ function LayoutContent() {
|
||||
<main style={{ flex: 1, overflow: 'auto', padding: '1.5rem' }}>
|
||||
<Outlet />
|
||||
</main>
|
||||
{/* Portal target for DetailPanel — pages use createPortal to render here */}
|
||||
<div id="detail-panel-portal" />
|
||||
</AppShell>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Detail panel — portaled to AppShell level for proper slide-in */}
|
||||
{selectedInstance && document.getElementById('detail-panel-portal') &&
|
||||
createPortal(
|
||||
<DetailPanel
|
||||
open={panelOpen}
|
||||
onClose={() => { 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 && (
|
||||
<DetailPanel
|
||||
open={panelOpen}
|
||||
onClose={() => { setPanelOpen(false); setSelectedInstance(null); }}
|
||||
title={selectedInstance.name ?? selectedInstance.id}
|
||||
tabs={detailTabs}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 */}
|
||||
<ShortcutsBar shortcuts={SHORTCUTS} />
|
||||
|
||||
{/* Detail panel — portaled to AppShell level for proper slide-in */}
|
||||
{selectedRow && detail && document.getElementById('detail-panel-portal') &&
|
||||
createPortal(
|
||||
<DetailPanel
|
||||
open={panelOpen}
|
||||
onClose={() => setPanelOpen(false)}
|
||||
title={`${detail.routeId} \u2014 ${selectedRow.executionId.slice(0, 12)}`}
|
||||
>
|
||||
{/* Detail panel — auto-portals to AppShell level via design system */}
|
||||
{selectedRow && detail && (
|
||||
<DetailPanel
|
||||
open={panelOpen}
|
||||
onClose={() => setPanelOpen(false)}
|
||||
title={`${detail.routeId} \u2014 ${selectedRow.executionId.slice(0, 12)}`}
|
||||
>
|
||||
<div className={styles.panelSection}>
|
||||
<button
|
||||
className={styles.openDetailLink}
|
||||
@@ -498,10 +496,8 @@ export default function Dashboard() {
|
||||
<div style={{ color: 'var(--text-muted)', fontSize: 12 }}>No processor data</div>
|
||||
)}
|
||||
</div>
|
||||
</DetailPanel>,
|
||||
document.getElementById('detail-panel-portal')!,
|
||||
)
|
||||
}
|
||||
</DetailPanel>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user