feat(ui): add useP2PMode hook and embedded prop to Nodes and P2P pages

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
Ettore Di Giacinto
2026-06-01 23:03:42 +00:00
parent ec2a0645dd
commit bc42374d8a
3 changed files with 64 additions and 29 deletions

View File

@@ -0,0 +1,31 @@
import { useState, useEffect, useCallback } from 'react'
import { p2pApi } from '../utils/api'
// useP2PMode reports whether p2p / swarm mode is available, mirroring
// useDistributedMode. Availability is "a network token exists" (the same signal
// the standalone P2P page used). One-shot probe on mount plus a manual refetch.
//
// Returns:
// enabled — true when a non-empty network token is present
// loading — true until the first probe completes
// refetch — manual trigger to re-run the probe
export function useP2PMode() {
const [enabled, setEnabled] = useState(false)
const [loading, setLoading] = useState(true)
const probe = useCallback(async () => {
setLoading(true)
try {
const token = await p2pApi.getToken()
setEnabled(!!(token && String(token).trim()))
} catch {
setEnabled(false)
} finally {
setLoading(false)
}
}, [])
useEffect(() => { probe() }, [probe])
return { enabled, loading, refetch: probe }
}

View File

@@ -689,7 +689,7 @@ function SchedulingForm({ onSave, onCancel }) {
)
}
export default function Nodes() {
export default function Nodes({ embedded = false }) {
const { addToast } = useOutletContext()
const navigate = useNavigate()
const { t } = useTranslation('admin')
@@ -983,16 +983,18 @@ export default function Nodes() {
const pending = filteredNodes.filter(n => n.status === 'pending').length
return (
<div className="page page--wide">
<div className="page-header">
<h1 className="page-title">
<i className="fas fa-network-wired" style={{ marginRight: 'var(--spacing-sm)' }} />
{t('nodes.title')}
</h1>
<p className="page-subtitle">
{t('nodes.subtitle')}
</p>
</div>
<div className={embedded ? '' : 'page page--wide'}>
{!embedded && (
<div className="page-header">
<h1 className="page-title">
<i className="fas fa-network-wired" style={{ marginRight: 'var(--spacing-sm)' }} />
{t('nodes.title')}
</h1>
<p className="page-subtitle">
{t('nodes.subtitle')}
</p>
</div>
)}
{/* Tabs */}
<div className="tabs" style={{ marginBottom: 'var(--spacing-lg)' }}>

View File

@@ -102,7 +102,7 @@ function StepNumber({ n, bg, color }) {
)
}
export default function P2P() {
export default function P2P({ embedded = false }) {
const { addToast } = useOutletContext()
const { t } = useTranslation('admin')
const [workers, setWorkers] = useState([])
@@ -172,7 +172,7 @@ export default function P2P() {
if (loading) {
return (
<div className="page page--narrow" style={{ display: 'flex', justifyContent: 'center', padding: 'var(--spacing-xl)' }}>
<div className={embedded ? '' : 'page page--narrow'} style={{ display: 'flex', justifyContent: 'center', padding: 'var(--spacing-xl)' }}>
<LoadingSpinner size="lg" />
</div>
)
@@ -181,7 +181,7 @@ export default function P2P() {
// ── P2P Disabled ──
if (!enabled) {
return (
<div className="page page--narrow">
<div className={embedded ? '' : 'page page--narrow'}>
<div style={{ textAlign: 'center', padding: 'var(--spacing-xl) 0' }}>
<i className="fas fa-network-wired" style={{ fontSize: '3rem', color: 'var(--color-primary)', marginBottom: 'var(--spacing-md)' }} />
<h1 style={{ fontSize: '1.5rem', fontWeight: 600, marginBottom: 'var(--spacing-sm)' }}>
@@ -294,21 +294,23 @@ export default function P2P() {
const mlxTotal = stats.mlx_workers?.total ?? 0
return (
<div className="page page--narrow">
<div className="page-header">
<h1 className="page-title">
<i className="fas fa-circle-nodes" style={{ marginRight: 'var(--spacing-sm)' }} />
{t('p2p.title')}
</h1>
<p className="page-subtitle">
{t('p2p.subtitle')}
{' '}
<a href="https://localai.io/features/distribute/" target="_blank" rel="noopener noreferrer"
style={{ color: 'var(--color-primary)' }}>
<i className="fas fa-circle-info" />
</a>
</p>
</div>
<div className={embedded ? '' : 'page page--narrow'}>
{!embedded && (
<div className="page-header">
<h1 className="page-title">
<i className="fas fa-circle-nodes" style={{ marginRight: 'var(--spacing-sm)' }} />
{t('p2p.title')}
</h1>
<p className="page-subtitle">
{t('p2p.subtitle')}
{' '}
<a href="https://localai.io/features/distribute/" target="_blank" rel="noopener noreferrer"
style={{ color: 'var(--color-primary)' }}>
<i className="fas fa-circle-info" />
</a>
</p>
</div>
)}
{/* Network Token */}
<div style={{