@opengeni/react 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +109 -2
- package/dist/chunk-DEW2ZNF2.js +1238 -0
- package/dist/chunk-DEW2ZNF2.js.map +1 -0
- package/dist/index.d.ts +173 -50
- package/dist/index.js +1422 -982
- package/dist/index.js.map +1 -1
- package/dist/machines-BD6h9P_s.d.ts +329 -0
- package/dist/machines.d.ts +4 -0
- package/dist/machines.js +33 -0
- package/dist/machines.js.map +1 -0
- package/package.json +8 -2
- package/src/components/desktop-viewer.tsx +11 -1
- package/src/components/enrollment-consent.tsx +245 -0
- package/src/components/enrollment-device-flow.tsx +182 -0
- package/src/components/machine-card.tsx +131 -0
- package/src/components/machine-dock-bar.tsx +84 -0
- package/src/components/machine-metrics.tsx +184 -0
- package/src/components/machine-status-pill.tsx +157 -0
- package/src/components/machines-dashboard.tsx +151 -0
- package/src/components/message-timeline.tsx +106 -8
- package/src/components/workspace-dock.tsx +44 -10
- package/src/hooks/use-codex-accounts.ts +179 -0
- package/src/hooks/use-desktop-stream.ts +28 -2
- package/src/hooks/use-goal.ts +10 -2
- package/src/hooks/use-machines.ts +157 -0
- package/src/hooks/use-relay-frame-stream.ts +335 -0
- package/src/index.ts +15 -0
- package/src/lib/relay-wire.ts +116 -0
- package/src/machines.ts +50 -0
- package/src/timeline/activity-rail.tsx +13 -7
- package/src/timeline/index.ts +1 -0
- package/src/timeline/projection.ts +214 -16
- package/src/timeline/turn-summary.tsx +32 -10
- package/src/timeline/types.ts +29 -3
- package/src/types/machines.ts +67 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { OpenGeniClient, MachineState, MetricSample, MachineView, MachineKind, MachinesResponse } from '@opengeni/sdk';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The slice of `OpenGeniClient` the hooks depend on. Structural, so apps can
|
|
7
|
+
* pass the real SDK client, a proxy-backed client that routes through their
|
|
8
|
+
* own API, or a scripted client in tests/demos.
|
|
9
|
+
*/
|
|
10
|
+
type SessionClientLike = Pick<OpenGeniClient, "getClientConfig" | "getSession" | "updateSession" | "listSessions" | "sendMessage" | "steerMessage" | "interrupt" | "sendApprovalDecision" | "streamEvents" | "listTurns" | "updateQueuedTurn" | "reorderQueuedTurns" | "deleteQueuedTurn" | "getGoal" | "updateGoal" | "clearSessionContext" | "compactSessionContext" | "listScheduledTasks" | "uploadFile" | "getFile" | "createFileDownloadUrl" | "listEnvironments" | "createEnvironment" | "updateEnvironment" | "deleteEnvironment" | "setEnvironmentVariable" | "deleteEnvironmentVariable" | "listPacks" | "registerPack" | "enablePack" | "deletePack" | "listWorkspaces" | "createWorkspace" | "updateWorkspace" | "getBillingUsage" | "getClientConfig" | "getStreamCapabilities" | "acknowledgeStream" | "attachViewer" | "heartbeatViewer" | "detachViewer" | "fsList" | "fsRead" | "fsWrite" | "fsDelete" | "fsMove" | "fsMkdir" | "gitStatus" | "gitDiff" | "terminalExec" | "terminalPtyOpen" | "terminalPtyWrite" | "terminalPtyResize" | "terminalPtyClose">;
|
|
11
|
+
|
|
12
|
+
type OpenGeniContextValue = {
|
|
13
|
+
client: SessionClientLike;
|
|
14
|
+
workspaceId: string;
|
|
15
|
+
};
|
|
16
|
+
type OpenGeniProviderProps = {
|
|
17
|
+
client: SessionClientLike;
|
|
18
|
+
workspaceId: string;
|
|
19
|
+
children?: ReactNode;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Supplies the OpenGeni client + workspace to all hooks below it. Hooks also
|
|
23
|
+
* accept `{ client, workspaceId }` overrides per call for multi-workspace UIs.
|
|
24
|
+
*/
|
|
25
|
+
declare function OpenGeniProvider({ client, workspaceId, children }: OpenGeniProviderProps): react_jsx_runtime.JSX.Element;
|
|
26
|
+
type ClientOverride = {
|
|
27
|
+
client?: SessionClientLike | undefined;
|
|
28
|
+
workspaceId?: string | undefined;
|
|
29
|
+
};
|
|
30
|
+
/** Resolve client + workspace from explicit overrides or the provider. */
|
|
31
|
+
declare function useOpenGeni(override?: ClientOverride): OpenGeniContextValue;
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the client only — for hooks that are not workspace-scoped
|
|
34
|
+
* (`useWorkspaces`, `useBillingUsage`).
|
|
35
|
+
*/
|
|
36
|
+
declare function useOpenGeniClient(override?: Pick<ClientOverride, "client">): SessionClientLike;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The three connection-status pill values the UI surfaces across the dashboard,
|
|
40
|
+
* the dock, and the timeline. `consent_required` / `display_unavailable` /
|
|
41
|
+
* `enrolling` are NOT connection states — they map onto a connection state for
|
|
42
|
+
* the pill and carry their own badge separately.
|
|
43
|
+
*/
|
|
44
|
+
type ConnectionStatus = "online" | "reconnecting" | "offline";
|
|
45
|
+
/** Project a machine `state` onto its connection-status pill value. */
|
|
46
|
+
declare function connectionStatusForState(state: MachineState): ConnectionStatus;
|
|
47
|
+
|
|
48
|
+
type ConnectionStatusMeta = {
|
|
49
|
+
label: string;
|
|
50
|
+
dotClassName: string;
|
|
51
|
+
badgeClassName: string;
|
|
52
|
+
/** Live/transient states breathe; settled states hold still. */
|
|
53
|
+
pulse: boolean;
|
|
54
|
+
};
|
|
55
|
+
/** Token-backed meta for the three connection-status pill values. */
|
|
56
|
+
declare const CONNECTION_STATUS_META: Record<ConnectionStatus, ConnectionStatusMeta>;
|
|
57
|
+
type MachineStateBadgeMeta = {
|
|
58
|
+
label: string;
|
|
59
|
+
badgeClassName: string;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* The non-connection state badges that ride ALONGSIDE the connection pill —
|
|
63
|
+
* `consent_required` / `display_unavailable` / `enrolling` describe a capability
|
|
64
|
+
* limitation, not reachability, so they render as their own tinted chip.
|
|
65
|
+
*/
|
|
66
|
+
declare const MACHINE_STATE_BADGE_META: Partial<Record<MachineState, MachineStateBadgeMeta>>;
|
|
67
|
+
type ConnectionStatusPillProps = {
|
|
68
|
+
status: ConnectionStatus;
|
|
69
|
+
/** Override the label ("Online" -> "Connected", ...). */
|
|
70
|
+
label?: string | undefined;
|
|
71
|
+
size?: "sm" | "md" | undefined;
|
|
72
|
+
className?: string | undefined;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* The connection-status pill (online / reconnecting / offline) surfaced across
|
|
76
|
+
* the Machines dashboard, the dock header, and the session timeline. Reconnecting
|
|
77
|
+
* breathes (the resiliency-as-headline blip), online/offline hold still.
|
|
78
|
+
*/
|
|
79
|
+
declare function ConnectionStatusPill({ status, label, size, className }: ConnectionStatusPillProps): react_jsx_runtime.JSX.Element;
|
|
80
|
+
type ConnectionDotProps = {
|
|
81
|
+
status: ConnectionStatus;
|
|
82
|
+
className?: string | undefined;
|
|
83
|
+
};
|
|
84
|
+
/** Just the dot — for dense rows, the dock header, and timeline notices. */
|
|
85
|
+
declare function ConnectionDot({ status, className }: ConnectionDotProps): react_jsx_runtime.JSX.Element;
|
|
86
|
+
type MachineStatusPillProps = {
|
|
87
|
+
/** The machine's full state — drives the connection pill + any state badge. */
|
|
88
|
+
state: MachineState;
|
|
89
|
+
/** How many live sessions share this lease (renders a "Shared" chip when >1). */
|
|
90
|
+
sharedSessionCount?: number | undefined;
|
|
91
|
+
size?: "sm" | "md" | undefined;
|
|
92
|
+
className?: string | undefined;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* The composite machine status surface: the connection pill PLUS any
|
|
96
|
+
* consent/display/enrolling badge PLUS a shared-in-use chip. One component the
|
|
97
|
+
* dashboard row, the dock header, and the timeline all reuse so the status
|
|
98
|
+
* language is identical everywhere.
|
|
99
|
+
*/
|
|
100
|
+
declare function MachineStatusPill({ state, sharedSessionCount, size, className }: MachineStatusPillProps): react_jsx_runtime.JSX.Element;
|
|
101
|
+
|
|
102
|
+
type MachineMetricsProps = {
|
|
103
|
+
/** The latest metric sample, or null when the machine hasn't reported yet. */
|
|
104
|
+
metrics: MetricSample | null;
|
|
105
|
+
/** Compact (dashboard row) vs full (the dock detail). */
|
|
106
|
+
density?: "compact" | "full" | undefined;
|
|
107
|
+
className?: string | undefined;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Per-machine resource meters: CPU%, load average, memory, disk, and GPU when
|
|
111
|
+
* present. Renders the M2 `machine_metrics_latest` sample. When `metrics` is
|
|
112
|
+
* null the panel shows a quiet "no samples yet" placeholder (offline / just
|
|
113
|
+
* enrolled). GPU rows only render when `gpuUtilPct` is non-null.
|
|
114
|
+
*/
|
|
115
|
+
declare function MachineMetrics({ metrics, density, className }: MachineMetricsProps): react_jsx_runtime.JSX.Element;
|
|
116
|
+
|
|
117
|
+
type MachineCardProps = {
|
|
118
|
+
machine: MachineView;
|
|
119
|
+
/** Attach/swap the session's active sandbox to this machine. */
|
|
120
|
+
onAttach?: ((machine: MachineView) => void) | undefined;
|
|
121
|
+
/** Whether an attach/swap is currently in flight (disables the affordance). */
|
|
122
|
+
attaching?: boolean | undefined;
|
|
123
|
+
className?: string | undefined;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* One machine in the Machines dashboard: name + kind + OS/arch, the composite
|
|
127
|
+
* connection/state/shared status, latest resource meters, last-seen recency, and
|
|
128
|
+
* an attach/swap affordance. The session's currently-active sandbox carries an
|
|
129
|
+
* accent edge + an "Active" marker (never an attach button — it's already active).
|
|
130
|
+
*/
|
|
131
|
+
declare function MachineCard({ machine, onAttach, attaching, className }: MachineCardProps): react_jsx_runtime.JSX.Element;
|
|
132
|
+
|
|
133
|
+
type MachinesDashboardProps = {
|
|
134
|
+
machines: MachineView[];
|
|
135
|
+
/** The session's active sandbox id (drives the per-card "Active" marker). */
|
|
136
|
+
activeSandboxId?: string | null | undefined;
|
|
137
|
+
loading?: boolean | undefined;
|
|
138
|
+
error?: Error | null | undefined;
|
|
139
|
+
/** Attach/swap the session's active sandbox to a machine. */
|
|
140
|
+
onAttach?: ((machine: MachineView) => void) | undefined;
|
|
141
|
+
/** The sandbox id currently being attached/swapped to (disables that card). */
|
|
142
|
+
attachingSandboxId?: string | null | undefined;
|
|
143
|
+
/** Open the enrollment flow (the "Enroll a machine" CTA). */
|
|
144
|
+
onEnroll?: (() => void) | undefined;
|
|
145
|
+
onRefresh?: (() => void) | undefined;
|
|
146
|
+
className?: string | undefined;
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* The workspace Machines dashboard: the fleet of selfhosted enrollments + the
|
|
150
|
+
* session's Modal sandbox, each with its connection-status pill, state badges,
|
|
151
|
+
* latest metrics, and an attach/swap affordance. Renders the empty state (no
|
|
152
|
+
* machines → enroll CTA), a load error, and the populated grid. The component
|
|
153
|
+
* is purely presentational — feed it `MachinesResponse` data via `useMachines`.
|
|
154
|
+
*/
|
|
155
|
+
declare function MachinesDashboard({ machines, activeSandboxId, loading, error, onAttach, attachingSandboxId, onEnroll, onRefresh, className, }: MachinesDashboardProps): react_jsx_runtime.JSX.Element;
|
|
156
|
+
|
|
157
|
+
type MachineDockBarProps = {
|
|
158
|
+
/** The active machine's display name. */
|
|
159
|
+
name: string;
|
|
160
|
+
kind: MachineKind;
|
|
161
|
+
state: MachineState;
|
|
162
|
+
/** Live sessions sharing this whole-machine lease (>1 ⇒ shared disclosure). */
|
|
163
|
+
sharedSessionCount?: number | undefined;
|
|
164
|
+
className?: string | undefined;
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* A slim bar that surfaces WHICH machine the dock surfaces (Files/Terminal/
|
|
168
|
+
* Desktop) are bound to + its connection status. Mounted above the dock tabs so
|
|
169
|
+
* the user always knows whether they are looking at the Modal box or their own
|
|
170
|
+
* machine, and whether it is online / reconnecting / offline. The surfaces below
|
|
171
|
+
* render IDENTICALLY regardless of backend — this bar is the only backend-aware
|
|
172
|
+
* chrome (the dock-parity contract: selfhosted == Modal for the surfaces).
|
|
173
|
+
*/
|
|
174
|
+
declare function MachineDockBar({ name, kind, state, sharedSessionCount, className }: MachineDockBarProps): react_jsx_runtime.JSX.Element;
|
|
175
|
+
type SharedMachineDisclosureProps = {
|
|
176
|
+
sharedSessionCount: number;
|
|
177
|
+
/** Compact (inline strip) vs full (a notice block). */
|
|
178
|
+
density?: "compact" | "full" | undefined;
|
|
179
|
+
className?: string | undefined;
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* The "shared — another session is on this machine" disclosure. Surfaced in the
|
|
183
|
+
* dock (and reused on the desktop take-control gate) so the user knows others are
|
|
184
|
+
* driving the same whole-machine lease. Render when `sharedSessionCount > 1`.
|
|
185
|
+
*/
|
|
186
|
+
declare function SharedMachineDisclosure({ sharedSessionCount, density, className }: SharedMachineDisclosureProps): react_jsx_runtime.JSX.Element;
|
|
187
|
+
|
|
188
|
+
/** The poll state of an in-flight device-flow enrollment. */
|
|
189
|
+
type DeviceFlowPhase = "pending" | "authorized" | "denied" | "expired" | "disabled";
|
|
190
|
+
type EnrollmentDeviceFlowProps = {
|
|
191
|
+
/** The short user code the agent printed (shown big for the human to confirm). */
|
|
192
|
+
userCode: string;
|
|
193
|
+
/** Where the user approves — the same-origin device page. */
|
|
194
|
+
verificationUri: string;
|
|
195
|
+
/** The complete URI (code pre-filled) for a one-click / QR open. */
|
|
196
|
+
verificationUriComplete?: string | undefined;
|
|
197
|
+
/** The install one-liner the user ran (echoed for context). Optional. */
|
|
198
|
+
installCommand?: string | undefined;
|
|
199
|
+
phase?: DeviceFlowPhase | undefined;
|
|
200
|
+
/** Seconds remaining before the code expires (drives a quiet countdown). */
|
|
201
|
+
expiresInSeconds?: number | undefined;
|
|
202
|
+
onCopyCode?: (() => void) | undefined;
|
|
203
|
+
onCopyInstall?: (() => void) | undefined;
|
|
204
|
+
onOpenVerification?: (() => void) | undefined;
|
|
205
|
+
className?: string | undefined;
|
|
206
|
+
};
|
|
207
|
+
/**
|
|
208
|
+
* The IN-SESSION device-flow panel: the agent (after the install one-liner) prints
|
|
209
|
+
* a short `userCode` + a `verificationUri`; this surfaces them so the user can open
|
|
210
|
+
* the approve page and confirm the code. Polls in the caller; this renders the
|
|
211
|
+
* pending → authorized/denied/expired progression with a connection pill. This is
|
|
212
|
+
* the FIRST step of the IA flow (device-flow → Machines list → attach/swap).
|
|
213
|
+
*/
|
|
214
|
+
declare function EnrollmentDeviceFlow({ userCode, verificationUri, verificationUriComplete, installCommand, phase, expiresInSeconds, onCopyCode, onCopyInstall, onOpenVerification, className, }: EnrollmentDeviceFlowProps): react_jsx_runtime.JSX.Element;
|
|
215
|
+
|
|
216
|
+
/** The machine identity surfaced to the approver, from the device-flow start. */
|
|
217
|
+
type EnrollmentConsentMachine = {
|
|
218
|
+
/** Human-friendly name (hostname by default). */
|
|
219
|
+
machineName: string;
|
|
220
|
+
os: string;
|
|
221
|
+
arch: string;
|
|
222
|
+
/** The agent can offer a display (a real screen / Xvfb is available). */
|
|
223
|
+
canOfferDisplay: boolean;
|
|
224
|
+
/** The agent requests screen control (computer-use). */
|
|
225
|
+
requestsScreenControl: boolean;
|
|
226
|
+
};
|
|
227
|
+
/** The phase of the approve page (drives the rendered panel). */
|
|
228
|
+
type EnrollmentConsentPhase = "review" | "approving" | "approved" | "denied" | "error";
|
|
229
|
+
type EnrollmentConsentProps = {
|
|
230
|
+
/** The short code the user typed / scanned (echoed back for confirmation). */
|
|
231
|
+
userCode: string;
|
|
232
|
+
machine: EnrollmentConsentMachine;
|
|
233
|
+
phase?: EnrollmentConsentPhase | undefined;
|
|
234
|
+
/** Approve with the chosen screen-control consent. */
|
|
235
|
+
onApprove?: ((allowScreenControl: boolean) => void) | undefined;
|
|
236
|
+
onDeny?: (() => void) | undefined;
|
|
237
|
+
/** Error message when phase === "error". */
|
|
238
|
+
errorMessage?: string | undefined;
|
|
239
|
+
className?: string | undefined;
|
|
240
|
+
};
|
|
241
|
+
/**
|
|
242
|
+
* The user-facing APPROVE page for the device-flow enrollment: a LOUD,
|
|
243
|
+
* un-minimised whole-machine consent. Approving grants the agent FULL access to
|
|
244
|
+
* this machine — exec, files, terminal — and (when toggled) live screen control.
|
|
245
|
+
* The danger framing is deliberate (§18 hardening: whole-machine = loud consent),
|
|
246
|
+
* never buried. Renders review / approving / approved / denied / error phases.
|
|
247
|
+
*/
|
|
248
|
+
declare function EnrollmentConsent({ userCode, machine, phase, onApprove, onDeny, errorMessage, className, }: EnrollmentConsentProps): react_jsx_runtime.JSX.Element;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* The slice of the SDK client the Machines surface needs. The method NAMES +
|
|
252
|
+
* SIGNATURES match M10's `OpenGeniClient` (`listMachines`, `machineMetricsSeries`)
|
|
253
|
+
* so the real SDK client satisfies this surface DIRECTLY for the read paths — no
|
|
254
|
+
* adapter needed. It is declared structurally (not a hard `OpenGeniClient` Pick)
|
|
255
|
+
* so a test/demo/Geni-frontend client can stand in, keeping the hook dual-consumer
|
|
256
|
+
* safe (works in apps/web AND the separate Geni frontend).
|
|
257
|
+
*
|
|
258
|
+
* The active-sandbox SWAP is now a typed SDK call (`swapActiveSandbox`, the M7
|
|
259
|
+
* user-authenticated REST equivalent of the `sandbox_swap` MCP tool). The real
|
|
260
|
+
* SDK client satisfies it structurally, so the default attach path is wired
|
|
261
|
+
* WHENEVER a sessionId is in scope (the swap is session-scoped). `attachMachine`
|
|
262
|
+
* stays an OPTIONAL escape hatch for a host that wants to supply its own swap
|
|
263
|
+
* adapter; when neither it nor a sessionId is present, attach is a no-op and the
|
|
264
|
+
* card hides the button.
|
|
265
|
+
*/
|
|
266
|
+
type MachinesClientLike = {
|
|
267
|
+
/** GET /v1/workspaces/:ws/machines — the dashboard list + active pointer. */
|
|
268
|
+
listMachines: (workspaceId: string, options?: {
|
|
269
|
+
sessionId?: string;
|
|
270
|
+
}) => Promise<MachinesResponse>;
|
|
271
|
+
/** GET .../machines/:enrollmentId/metrics/series — the downsampled history. */
|
|
272
|
+
machineMetricsSeries?: (workspaceId: string, enrollmentId: string, options?: {
|
|
273
|
+
window?: "15m" | "1h" | "6h" | "24h";
|
|
274
|
+
}) => Promise<MetricSample[]>;
|
|
275
|
+
/**
|
|
276
|
+
* POST .../sessions/:sessionId/active-sandbox — swap the session's active
|
|
277
|
+
* sandbox to a machine. The default swap path; the real SDK client provides it.
|
|
278
|
+
*/
|
|
279
|
+
swapActiveSandbox?: (workspaceId: string, sessionId: string, request: {
|
|
280
|
+
target: string;
|
|
281
|
+
}) => Promise<unknown>;
|
|
282
|
+
/**
|
|
283
|
+
* Host-supplied swap adapter (an escape hatch). When present it wins over the
|
|
284
|
+
* default `swapActiveSandbox` path. Session-scoped, like the swap it backs.
|
|
285
|
+
*/
|
|
286
|
+
attachMachine?: (workspaceId: string, sessionId: string, sandboxId: string) => Promise<unknown>;
|
|
287
|
+
};
|
|
288
|
+
type UseMachinesOptions = ClientOverride & {
|
|
289
|
+
pollIntervalMs?: number | undefined;
|
|
290
|
+
enabled?: boolean | undefined;
|
|
291
|
+
/** Scope the list to a session (adds the synthetic Modal group box + pointer). */
|
|
292
|
+
sessionId?: string | undefined;
|
|
293
|
+
/**
|
|
294
|
+
* Override the client with one implementing `MachinesClientLike`. Defaults to
|
|
295
|
+
* the provider client cast to the surface (the real SDK client satisfies the
|
|
296
|
+
* read paths). An app supplies an adapter to wire `attachMachine` (the swap).
|
|
297
|
+
*/
|
|
298
|
+
machinesClient?: MachinesClientLike | undefined;
|
|
299
|
+
};
|
|
300
|
+
type UseMachinesResult = {
|
|
301
|
+
machines: MachineView[];
|
|
302
|
+
activeSandboxId: string | null;
|
|
303
|
+
activeEpoch: number;
|
|
304
|
+
loading: boolean;
|
|
305
|
+
error: Error | null;
|
|
306
|
+
refresh: () => Promise<void>;
|
|
307
|
+
/** Attach/swap the session's active sandbox to a machine (returns the new pointer). */
|
|
308
|
+
attach: (sandboxId: string) => Promise<boolean>;
|
|
309
|
+
/** Whether the host wired an attach/swap path (drives the card affordance). */
|
|
310
|
+
canAttach: boolean;
|
|
311
|
+
/** Fetch a downsampled metric series for one enrolled machine. */
|
|
312
|
+
fetchSeries: (enrollmentId: string, window?: "15m" | "1h" | "6h" | "24h") => Promise<MetricSample[]>;
|
|
313
|
+
attaching: boolean;
|
|
314
|
+
/** The sandbox id of the in-flight attach (for per-card spinner gating). */
|
|
315
|
+
attachingSandboxId: string | null;
|
|
316
|
+
mutationError: Error | null;
|
|
317
|
+
clearMutationError: () => void;
|
|
318
|
+
};
|
|
319
|
+
/**
|
|
320
|
+
* The workspace Machines fleet: the selfhosted enrollments + the session's Modal
|
|
321
|
+
* box, each with latest metrics + state, plus the active-sandbox pointer. Polls
|
|
322
|
+
* the M10 `GET /machines` endpoint and exposes attach/swap + a metric-series
|
|
323
|
+
* fetch. Renders via `<MachinesDashboard>`. Dual-consumer safe: it reads only the
|
|
324
|
+
* structural `MachinesClientLike` surface, so it works in apps/web AND the Geni
|
|
325
|
+
* frontend (each provides its own client/adapter).
|
|
326
|
+
*/
|
|
327
|
+
declare function useMachines(options?: UseMachinesOptions): UseMachinesResult;
|
|
328
|
+
|
|
329
|
+
export { SharedMachineDisclosure as A, type SharedMachineDisclosureProps as B, type ClientOverride as C, type DeviceFlowPhase as D, EnrollmentConsent as E, type UseMachinesResult as F, connectionStatusForState as G, useMachines as H, useOpenGeni as I, useOpenGeniClient as J, MACHINE_STATE_BADGE_META as M, type OpenGeniContextValue as O, type SessionClientLike as S, type UseMachinesOptions as U, CONNECTION_STATUS_META as a, ConnectionDot as b, type ConnectionDotProps as c, type ConnectionStatus as d, type ConnectionStatusMeta as e, ConnectionStatusPill as f, type ConnectionStatusPillProps as g, type EnrollmentConsentMachine as h, type EnrollmentConsentPhase as i, type EnrollmentConsentProps as j, EnrollmentDeviceFlow as k, type EnrollmentDeviceFlowProps as l, MachineCard as m, type MachineCardProps as n, MachineDockBar as o, type MachineDockBarProps as p, MachineMetrics as q, type MachineMetricsProps as r, type MachineStateBadgeMeta as s, MachineStatusPill as t, type MachineStatusPillProps as u, type MachinesClientLike as v, MachinesDashboard as w, type MachinesDashboardProps as x, OpenGeniProvider as y, type OpenGeniProviderProps as z };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { a as CONNECTION_STATUS_META, b as ConnectionDot, c as ConnectionDotProps, d as ConnectionStatus, e as ConnectionStatusMeta, f as ConnectionStatusPill, g as ConnectionStatusPillProps, D as DeviceFlowPhase, E as EnrollmentConsent, h as EnrollmentConsentMachine, i as EnrollmentConsentPhase, j as EnrollmentConsentProps, k as EnrollmentDeviceFlow, l as EnrollmentDeviceFlowProps, M as MACHINE_STATE_BADGE_META, m as MachineCard, n as MachineCardProps, o as MachineDockBar, p as MachineDockBarProps, q as MachineMetrics, r as MachineMetricsProps, s as MachineStateBadgeMeta, t as MachineStatusPill, u as MachineStatusPillProps, v as MachinesClientLike, w as MachinesDashboard, x as MachinesDashboardProps, A as SharedMachineDisclosure, B as SharedMachineDisclosureProps, U as UseMachinesOptions, F as UseMachinesResult, G as connectionStatusForState, H as useMachines } from './machines-BD6h9P_s.js';
|
|
2
|
+
export { MachineKind, MachineMetricsSeriesResponse, MachineState, MachineView, MachinesResponse, MetricSample } from '@opengeni/sdk';
|
|
3
|
+
import 'react/jsx-runtime';
|
|
4
|
+
import 'react';
|
package/dist/machines.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CONNECTION_STATUS_META,
|
|
3
|
+
ConnectionDot,
|
|
4
|
+
ConnectionStatusPill,
|
|
5
|
+
EnrollmentConsent,
|
|
6
|
+
EnrollmentDeviceFlow,
|
|
7
|
+
MACHINE_STATE_BADGE_META,
|
|
8
|
+
MachineCard,
|
|
9
|
+
MachineDockBar,
|
|
10
|
+
MachineMetrics,
|
|
11
|
+
MachineStatusPill,
|
|
12
|
+
MachinesDashboard,
|
|
13
|
+
SharedMachineDisclosure,
|
|
14
|
+
connectionStatusForState,
|
|
15
|
+
useMachines
|
|
16
|
+
} from "./chunk-DEW2ZNF2.js";
|
|
17
|
+
export {
|
|
18
|
+
CONNECTION_STATUS_META,
|
|
19
|
+
ConnectionDot,
|
|
20
|
+
ConnectionStatusPill,
|
|
21
|
+
EnrollmentConsent,
|
|
22
|
+
EnrollmentDeviceFlow,
|
|
23
|
+
MACHINE_STATE_BADGE_META,
|
|
24
|
+
MachineCard,
|
|
25
|
+
MachineDockBar,
|
|
26
|
+
MachineMetrics,
|
|
27
|
+
MachineStatusPill,
|
|
28
|
+
MachinesDashboard,
|
|
29
|
+
SharedMachineDisclosure,
|
|
30
|
+
connectionStatusForState,
|
|
31
|
+
useMachines
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=machines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "React hooks and styled components for OpenGeni: live session streaming, chat composer, message timeline, session status, and fleet views — token-themed (CSS variables), dark-first, built on Tailwind v4 + Radix + Motion.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
"types": "./dist/index.d.ts",
|
|
19
19
|
"import": "./dist/index.js"
|
|
20
20
|
},
|
|
21
|
+
"./machines": {
|
|
22
|
+
"types": "./dist/machines.d.ts",
|
|
23
|
+
"import": "./dist/machines.js"
|
|
24
|
+
},
|
|
21
25
|
"./styles.css": "./styles/index.css",
|
|
22
26
|
"./tokens.css": "./styles/tokens.css"
|
|
23
27
|
},
|
|
@@ -40,7 +44,8 @@
|
|
|
40
44
|
"demo:build": "vite build demo"
|
|
41
45
|
},
|
|
42
46
|
"dependencies": {
|
|
43
|
-
"@
|
|
47
|
+
"@bufbuild/protobuf": "^2.2.0",
|
|
48
|
+
"@opengeni/sdk": "^0.6.0",
|
|
44
49
|
"clsx": "^2.1.1",
|
|
45
50
|
"lucide-react": "^1.8.0",
|
|
46
51
|
"motion": "^12.0.0",
|
|
@@ -106,6 +111,7 @@
|
|
|
106
111
|
},
|
|
107
112
|
"devDependencies": {
|
|
108
113
|
"@codemirror/lang-css": "^6.3.1",
|
|
114
|
+
"@opengeni/agent-proto": "workspace:*",
|
|
109
115
|
"@codemirror/lang-html": "^6.4.11",
|
|
110
116
|
"@codemirror/lang-javascript": "^6.2.5",
|
|
111
117
|
"@codemirror/lang-json": "^6.0.2",
|
|
@@ -3,6 +3,7 @@ import { LoaderCircleIcon, MonitorIcon, MousePointerClickIcon, WifiOffIcon } fro
|
|
|
3
3
|
import { type ReactNode, useEffect, useRef, useState } from "react";
|
|
4
4
|
import { cn } from "../lib/cn";
|
|
5
5
|
import { useDesktopStream } from "../hooks/use-desktop-stream";
|
|
6
|
+
import type { DesktopWebSocketFactory } from "../hooks/use-relay-frame-stream";
|
|
6
7
|
|
|
7
8
|
export type DesktopViewerProps = {
|
|
8
9
|
/** The desktop cell of the negotiated capabilities (`capabilities.DesktopStream`). */
|
|
@@ -19,6 +20,9 @@ export type DesktopViewerProps = {
|
|
|
19
20
|
scaleViewport?: boolean | undefined;
|
|
20
21
|
/** Custom RFB factory (tests / a WebRTC swap). Defaults to lazy @novnc/novnc. */
|
|
21
22
|
rfbFactory?: DesktopRfbFactory | undefined;
|
|
23
|
+
/** Custom socket factory for the self-hosted `relay-frames` transport (tests).
|
|
24
|
+
* Defaults to `new WebSocket(url)`. Mirrors `rfbFactory`. */
|
|
25
|
+
webSocketFactory?: DesktopWebSocketFactory | undefined;
|
|
22
26
|
/**
|
|
23
27
|
* Consent gate for the un-redacted (and possibly shared) pixel plane. Rendered
|
|
24
28
|
* BEFORE connecting whenever the desktop requires acknowledgment that hasn't
|
|
@@ -121,6 +125,7 @@ export function DesktopViewer({
|
|
|
121
125
|
showControlToggle = true,
|
|
122
126
|
scaleViewport,
|
|
123
127
|
rfbFactory,
|
|
128
|
+
webSocketFactory,
|
|
124
129
|
renderConsentGate,
|
|
125
130
|
onAcknowledge,
|
|
126
131
|
watching,
|
|
@@ -213,6 +218,7 @@ export function DesktopViewer({
|
|
|
213
218
|
interactive: inControl,
|
|
214
219
|
...(scaleViewport !== undefined ? { scaleViewport } : {}),
|
|
215
220
|
...(rfbFactory ? { rfbFactory } : {}),
|
|
221
|
+
...(webSocketFactory ? { webSocketFactory } : {}),
|
|
216
222
|
});
|
|
217
223
|
|
|
218
224
|
const connected = stream.state === "connected";
|
|
@@ -429,7 +435,11 @@ export function DesktopViewer({
|
|
|
429
435
|
<TakeControlCallToAction
|
|
430
436
|
disabled={!serverAllowsControl}
|
|
431
437
|
disabledReason={
|
|
432
|
-
!serverAllowsControl
|
|
438
|
+
!serverAllowsControl
|
|
439
|
+
? capability?.client === "frames"
|
|
440
|
+
? "View-only — live control isn't available for this machine yet."
|
|
441
|
+
: "This deployment streams the desktop read-only"
|
|
442
|
+
: undefined
|
|
433
443
|
}
|
|
434
444
|
onTakeControl={() => setTakeControl(true)}
|
|
435
445
|
/>
|