mirror of
https://github.com/mudler/LocalAI.git
synced 2026-06-04 23:06:22 -04:00
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:
31
core/http/react-ui/src/hooks/useP2PMode.js
vendored
Normal file
31
core/http/react-ui/src/hooks/useP2PMode.js
vendored
Normal 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 }
|
||||
}
|
||||
@@ -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)' }}>
|
||||
|
||||
@@ -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={{
|
||||
|
||||
Reference in New Issue
Block a user