diff --git a/core/http/react-ui/src/pages/Manage.jsx b/core/http/react-ui/src/pages/Manage.jsx
index 10d684a6e..feef047d4 100644
--- a/core/http/react-ui/src/pages/Manage.jsx
+++ b/core/http/react-ui/src/pages/Manage.jsx
@@ -3,6 +3,7 @@ import { useNavigate, useOutletContext, useSearchParams, useLocation } from 'rea
import { useTranslation } from 'react-i18next'
import { fromState } from '../utils/editorNav'
import ResourceMonitor from '../components/ResourceMonitor'
+import PageHeader from '../components/PageHeader'
import ConfirmDialog from '../components/ConfirmDialog'
import NodeDistributionChip from '../components/NodeDistributionChip'
import FilterBar from '../components/FilterBar'
@@ -448,10 +449,7 @@ export default function Manage() {
return (
-
-
{t('manage.title')}
-
{t('manage.subtitle')}
-
+
{/* Resource Monitor */}
diff --git a/core/http/react-ui/src/pages/Middleware.jsx b/core/http/react-ui/src/pages/Middleware.jsx
index 7be29725b..027967f69 100644
--- a/core/http/react-ui/src/pages/Middleware.jsx
+++ b/core/http/react-ui/src/pages/Middleware.jsx
@@ -5,6 +5,7 @@ import { fromState } from '../utils/editorNav'
import { settingsApi, modelsApi } from '../utils/api'
import LoadingSpinner from '../components/LoadingSpinner'
import Toggle from '../components/Toggle'
+import PageHeader from '../components/PageHeader'
// Middleware admin page. Three tabs:
// - Filtering: per-model resolved PII state + per-model detector list
@@ -129,12 +130,10 @@ export default function Middleware() {
return (
-
-
Middleware
-
- Inspect and configure routing-module middleware: PII filtering and intelligent routing.
-
-
+
{/* Tab bar */}
diff --git a/core/http/react-ui/src/pages/Models.jsx b/core/http/react-ui/src/pages/Models.jsx
index be4afaff1..c41dde2e5 100644
--- a/core/http/react-ui/src/pages/Models.jsx
+++ b/core/http/react-ui/src/pages/Models.jsx
@@ -8,6 +8,7 @@ import { useDebouncedCallback } from '../hooks/useDebounce'
import { useOperations } from '../hooks/useOperations'
import { useResources } from '../hooks/useResources'
import SearchableSelect from '../components/SearchableSelect'
+import PageHeader from '../components/PageHeader'
import ConfirmDialog from '../components/ConfirmDialog'
import GalleryLoader from '../components/GalleryLoader'
import Toggle from '../components/Toggle'
@@ -271,32 +272,32 @@ export default function Models() {
return (
-
-
-
{t('title')}
-
{t('subtitle')}
-
-
-
-
-
{stats.total}
-
{t('stats.available')}
-
-
-
-
-
-
+ }
+ />
{/* Search */}
diff --git a/core/http/react-ui/src/pages/NodeBackendLogs.jsx b/core/http/react-ui/src/pages/NodeBackendLogs.jsx
index 58e798233..e1dd76410 100644
--- a/core/http/react-ui/src/pages/NodeBackendLogs.jsx
+++ b/core/http/react-ui/src/pages/NodeBackendLogs.jsx
@@ -4,6 +4,7 @@ import { nodesApi } from '../utils/api'
import { formatTimestamp } from '../utils/format'
import { apiUrl } from '../utils/basePath'
import LoadingSpinner from '../components/LoadingSpinner'
+import PageHeader from '../components/PageHeader'
function wsUrl(path) {
const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
@@ -176,9 +177,9 @@ export default function NodeBackendLogs() {
return (
-
-
-
+
{baseModelName}
{!isMerged && (
@@ -217,13 +218,15 @@ export default function NodeBackendLogs() {
merged ยท {replicas.length} replicas
)}
-
-
+ >
+ }
+ supporting={
+ <>
Backend logs from node {nodeName || nodeId}
{' '}(back to nodes)
-
-
-
+ >
+ }
+ />
{showReplicaToggle && (
diff --git a/core/http/react-ui/src/pages/Nodes.jsx b/core/http/react-ui/src/pages/Nodes.jsx
index 06372f4b1..8fb258fcb 100644
--- a/core/http/react-ui/src/pages/Nodes.jsx
+++ b/core/http/react-ui/src/pages/Nodes.jsx
@@ -3,6 +3,7 @@ import { useOutletContext, useNavigate } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import { nodesApi } from '../utils/api'
import LoadingSpinner from '../components/LoadingSpinner'
+import PageHeader from '../components/PageHeader'
import ConfirmDialog from '../components/ConfirmDialog'
import ActionMenu from '../components/ActionMenu'
import SearchableModelSelect from '../components/SearchableModelSelect'
@@ -995,15 +996,15 @@ export default function Nodes() {
return (
-
-
-
- {t('nodes.title')}
-
-
- {t('nodes.subtitle')}
-
-
+
+
+ {t('nodes.title')}
+ >
+ }
+ supporting={t('nodes.subtitle')}
+ />
{/* Tabs */}
diff --git a/core/http/react-ui/src/pages/P2P.jsx b/core/http/react-ui/src/pages/P2P.jsx
index 7e52d1c77..b67d84110 100644
--- a/core/http/react-ui/src/pages/P2P.jsx
+++ b/core/http/react-ui/src/pages/P2P.jsx
@@ -3,6 +3,7 @@ import { useOutletContext } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import { p2pApi } from '../utils/api'
import LoadingSpinner from '../components/LoadingSpinner'
+import PageHeader from '../components/PageHeader'
import ImageSelector, { useImageSelector, dockerImage, dockerFlags } from '../components/ImageSelector'
function NodeCard({ node, label, iconColor, iconBg }) {
@@ -295,20 +296,24 @@ export default function P2P() {
return (
-
-
-
- {t('p2p.title')}
-
-
- {t('p2p.subtitle')}
- {' '}
-
-
-
-
-
+
+
+ {t('p2p.title')}
+ >
+ }
+ supporting={
+ <>
+ {t('p2p.subtitle')}
+ {' '}
+
+
+
+ >
+ }
+ />
{/* Network Token */}
navigate('/app/skills')}>
Back to skills
-
-
- {isNew ? 'New skill' : `Edit: ${name}`}
-
-
+
+ {isNew ? 'New skill' : `Edit: ${name}`}
+ >
+ }
+ />
diff --git a/core/http/react-ui/src/pages/Skills.jsx b/core/http/react-ui/src/pages/Skills.jsx
index 735bcc026..954912cfd 100644
--- a/core/http/react-ui/src/pages/Skills.jsx
+++ b/core/http/react-ui/src/pages/Skills.jsx
@@ -5,6 +5,7 @@ import { skillsApi } from '../utils/api'
import { useAuth } from '../context/AuthContext'
import { useUserMap } from '../hooks/useUserMap'
import UserGroupSection from '../components/UserGroupSection'
+import PageHeader from '../components/PageHeader'
import ConfirmDialog from '../components/ConfirmDialog'
export default function Skills() {
@@ -207,10 +208,7 @@ export default function Skills() {
if (unavailable) {
return (
-
-
{t('title')}
-
{t('unavailable.subtitle')}
-
+
+ }
+ />
{showGitRepos && (
diff --git a/core/http/react-ui/src/pages/Sound.jsx b/core/http/react-ui/src/pages/Sound.jsx
index 8ec783fc8..bb9555b1f 100644
--- a/core/http/react-ui/src/pages/Sound.jsx
+++ b/core/http/react-ui/src/pages/Sound.jsx
@@ -1,6 +1,7 @@
import { useState } from 'react'
import { useParams, useOutletContext } from 'react-router-dom'
import ModelSelector from '../components/ModelSelector'
+import PageHeader from '../components/PageHeader'
import { CAP_SOUND_GENERATION } from '../utils/capabilities'
import LoadingSpinner from '../components/LoadingSpinner'
import ErrorWithTraceLink from '../components/ErrorWithTraceLink'
@@ -77,9 +78,7 @@ export default function Sound() {
return (
-
-
Sound Generation
-
+
Sound Generation>} />