Sensors: read-only tokens, live stream, Prometheus, status sensors, widgets, embeds
- sensors:read tokens open the sensor endpoints (here and on managed machines through the hub) and nothing else; full tokens are never accepted from a URL - /api/sensors/stream: a shaped query that keeps answering, over SSE - /metrics: Prometheus text format - services, updates, ZFS and SMART as background status sensors - widget library over the sensor API; custom widgets on the dashboard - /embed/widget: one live widget in its own bundle, the only frameable path - Dashboard tab is now Monitors Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
468f45251d
commit
b05a053920
@@ -0,0 +1,31 @@
|
||||
// One widget, alone, for an iframe in someone else's dashboard (Glance, Home Assistant…):
|
||||
// /embed/widget?type=gauge&sensor=cpu.usage&token=<read-only token>
|
||||
// &machine=grid &title=… &theme=dark|light|cyberpunk|retro &every=<ms> &bare=1
|
||||
// It stays live over the sensor stream. The token must be a read-only sensor token; a
|
||||
// full-control token is refused in a URL by design.
|
||||
import { useSensorStream, Source } from './sensors'
|
||||
import { Widget, WidgetData, WidgetSpec, WidgetType, WIDGET_TYPES } from './widgets'
|
||||
import { applyTheme } from './themes'
|
||||
|
||||
const p = new URLSearchParams(location.search)
|
||||
if (p.get('theme')) applyTheme(p.get('theme')!)
|
||||
|
||||
export default function Embed() {
|
||||
const sensor = p.get('sensor') ?? ''
|
||||
const asked = p.get('type') as WidgetType | null
|
||||
const type: WidgetType = /[*?[]/.test(sensor) ? 'list' : asked && WIDGET_TYPES.some((t) => t.id === asked && !t.many) ? asked : 'stat'
|
||||
const spec: WidgetSpec = { id: 'w', type, sensor, title: p.get('title') ?? undefined }
|
||||
const src: Source = { machine: p.get('machine') || null, token: p.get('token') ?? undefined }
|
||||
const every = Number(p.get('every')) || undefined
|
||||
const live = useSensorStream<{ w: WidgetData }>(sensor ? { w: sensor } : null, src, every)
|
||||
return (
|
||||
<div className={'embed' + (p.get('bare') === '1' ? ' bare' : '')}>
|
||||
{!sensor ? <div className="error">embed needs ?sensor=</div> : (
|
||||
<div className={'tile w-' + type}>
|
||||
<Widget spec={spec} data={live.data ? live.data.w : undefined} src={src} />
|
||||
{live.error && !live.data && <div className="sub">{src.token ? 'waiting for the stream — check the token' : 'no token given'}</div>}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user