@opengeni/react 7.6.1 → 7.7.0-canary.37090756480001
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 +19 -2
- package/dist/{browser-viewer-5X47I6T2.js → browser-viewer-63TXMINB.js} +6 -5
- package/dist/{chunk-UINDK6C3.js → chunk-2QUSQVF2.js} +3 -3
- package/dist/{chunk-CHPKSLPN.js → chunk-6ZSWSH4I.js} +3 -1
- package/dist/chunk-6ZSWSH4I.js.map +1 -0
- package/dist/{chunk-KGENSZKS.js → chunk-AAG4R3QN.js} +4 -3
- package/dist/chunk-AAG4R3QN.js.map +1 -0
- package/dist/{chunk-Z3DISEQN.js → chunk-CWWKTNKK.js} +35 -18
- package/dist/chunk-CWWKTNKK.js.map +1 -0
- package/dist/{chunk-5EXGU7UF.js → chunk-DOJWJQ3F.js} +3 -3
- package/dist/{chunk-WZ55DVGK.js → chunk-ELCE5SXV.js} +8 -4
- package/dist/chunk-ELCE5SXV.js.map +1 -0
- package/dist/{chunk-YSMMDOOE.js → chunk-GISEVGS6.js} +10 -2
- package/dist/chunk-GISEVGS6.js.map +1 -0
- package/dist/{chunk-YRYF2GLG.js → chunk-HNFCAQ5R.js} +39 -31
- package/dist/chunk-HNFCAQ5R.js.map +1 -0
- package/dist/{chunk-BI57CQUV.js → chunk-I7IWRQLN.js} +2 -2
- package/dist/{chunk-XA6R7DJQ.js → chunk-IQUCRAT7.js} +3 -3
- package/dist/{chunk-DV2DBNPQ.js → chunk-Q5QBEZIQ.js} +48 -29
- package/dist/chunk-Q5QBEZIQ.js.map +1 -0
- package/dist/{chunk-FGBCYQOT.js → chunk-RDKBXMWX.js} +120 -74
- package/dist/chunk-RDKBXMWX.js.map +1 -0
- package/dist/{chunk-45GE35O7.js → chunk-TKB4SB44.js} +10 -2
- package/dist/chunk-TKB4SB44.js.map +1 -0
- package/dist/{chunk-YCGBREUV.js → chunk-TOAH2BKA.js} +6 -2
- package/dist/{chunk-YCGBREUV.js.map → chunk-TOAH2BKA.js.map} +1 -1
- package/dist/chunk-UGLEYEMP.js +33 -0
- package/dist/chunk-UGLEYEMP.js.map +1 -0
- package/dist/{chunk-UJRYEWZI.js → chunk-UTRTG6LH.js} +48 -8
- package/dist/chunk-UTRTG6LH.js.map +1 -0
- package/dist/{chunk-VGIKFIO2.js → chunk-XOAMRDDK.js} +6 -3
- package/dist/chunk-XOAMRDDK.js.map +1 -0
- package/dist/{chunk-6NEZPF53.js → chunk-YN7I3STW.js} +153 -32
- package/dist/chunk-YN7I3STW.js.map +1 -0
- package/dist/{chunk-KZ73RL76.js → chunk-YQEAA6LT.js} +7 -3
- package/dist/chunk-YQEAA6LT.js.map +1 -0
- package/dist/{chunk-LZ3KHA55.js → chunk-ZYALTAEQ.js} +329 -339
- package/dist/chunk-ZYALTAEQ.js.map +1 -0
- package/dist/client.d.ts +4 -1
- package/dist/commands/types.d.ts +2 -0
- package/dist/components/approval-surface.d.ts +15 -0
- package/dist/composer.js +8 -7
- package/dist/{computer-viewer-7GF35SNY.js → computer-viewer-X2MBRZY4.js} +5 -4
- package/dist/connect.js +3 -3
- package/dist/hooks/use-browser-session.d.ts +4 -0
- package/dist/hooks/use-composer.d.ts +2 -0
- package/dist/hooks/use-computer-session.d.ts +2 -0
- package/dist/hooks/use-file-attachments.d.ts +2 -0
- package/dist/hooks/use-session-events.d.ts +1 -1
- package/dist/hooks/use-workspace-sessions.d.ts +15 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +28 -21
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +1 -1
- package/dist/interaction.js +6 -5
- package/dist/interaction.js.map +1 -1
- package/dist/{latest-question-3BJGKQQ6.js → latest-question-CNEZ5KAN.js} +3 -3
- package/dist/lib/error-message.d.ts +7 -0
- package/dist/lib/format.d.ts +27 -3
- package/dist/lib/interaction-errors.d.ts +3 -0
- package/dist/machines.js +5 -4
- package/dist/{model-policy-picker-menu-PUTA5JOB.js → model-policy-picker-menu-JSA64TNN.js} +4 -4
- package/dist/model-policy.js +1 -1
- package/dist/provider.d.ts +5 -1
- package/dist/{queue-surface-implementation-2CAQAIHM.js → queue-surface-implementation-HENWYFWA.js} +3 -2
- package/dist/{queue-surface-implementation-2CAQAIHM.js.map → queue-surface-implementation-HENWYFWA.js.map} +1 -1
- package/dist/realtime.js +2 -2
- package/dist/{sandbox-files-AEJTWGT4.js → sandbox-files-BBC47SLD.js} +4 -3
- package/dist/session-ui.d.ts +1 -1
- package/dist/session-ui.js +13 -12
- package/dist/session-ui.js.map +1 -1
- package/dist/session.js +7 -6
- package/dist/usage.js +2 -1
- package/dist/usage.js.map +1 -1
- package/package.json +3 -3
- package/src/client.ts +5 -1
- package/src/commands/registry.ts +18 -15
- package/src/commands/types.ts +2 -0
- package/src/components/approval-surface.tsx +166 -42
- package/src/components/browser-viewer.tsx +38 -9
- package/src/components/composer.tsx +9 -2
- package/src/components/computer-viewer.tsx +160 -30
- package/src/components/generated-video-player.tsx +4 -2
- package/src/components/human-input-form.tsx +18 -5
- package/src/components/message-timeline.tsx +120 -168
- package/src/components/open-geni-chat.tsx +11 -4
- package/src/components/queue-surface-state.tsx +3 -1
- package/src/components/session-chrome.tsx +5 -2
- package/src/components/session-commands-panel.tsx +3 -1
- package/src/components/session-conversation.tsx +4 -2
- package/src/components/session-list.tsx +7 -5
- package/src/components/session-mcp-capability-card.tsx +11 -1
- package/src/hooks/internal.ts +3 -2
- package/src/hooks/use-browser-session.ts +115 -79
- package/src/hooks/use-composer.ts +70 -31
- package/src/hooks/use-computer-session.ts +57 -6
- package/src/hooks/use-file-attachments.ts +16 -3
- package/src/hooks/use-goal.ts +2 -1
- package/src/hooks/use-session-capabilities.ts +3 -2
- package/src/hooks/use-session-events.ts +15 -8
- package/src/hooks/use-slash-commands.ts +6 -11
- package/src/hooks/use-turn-queue.ts +2 -1
- package/src/hooks/use-workspace-sessions.ts +40 -7
- package/src/index.ts +7 -2
- package/src/interaction.ts +1 -0
- package/src/lib/error-message.ts +37 -0
- package/src/lib/format.ts +73 -9
- package/src/lib/interaction-errors.ts +15 -0
- package/src/model-policy.ts +5 -0
- package/src/provider.tsx +12 -4
- package/src/session-ui.ts +1 -1
- package/src/timeline/projection.ts +12 -1
- package/styles/compiled.css +14 -30
- package/dist/chunk-45GE35O7.js.map +0 -1
- package/dist/chunk-6NEZPF53.js.map +0 -1
- package/dist/chunk-CHPKSLPN.js.map +0 -1
- package/dist/chunk-DV2DBNPQ.js.map +0 -1
- package/dist/chunk-FGBCYQOT.js.map +0 -1
- package/dist/chunk-KGENSZKS.js.map +0 -1
- package/dist/chunk-KZ73RL76.js.map +0 -1
- package/dist/chunk-LZ3KHA55.js.map +0 -1
- package/dist/chunk-UJRYEWZI.js.map +0 -1
- package/dist/chunk-VGIKFIO2.js.map +0 -1
- package/dist/chunk-WZ55DVGK.js.map +0 -1
- package/dist/chunk-YRYF2GLG.js.map +0 -1
- package/dist/chunk-YSMMDOOE.js.map +0 -1
- package/dist/chunk-Z3DISEQN.js.map +0 -1
- package/dist/components/timeline-pill-geometry.d.ts +0 -8
- package/dist/components/timeline-pill-placement.d.ts +0 -24
- package/dist/timeline-pill-geometry-Z23V243M.js +0 -110
- package/dist/timeline-pill-geometry-Z23V243M.js.map +0 -1
- package/src/components/timeline-pill-geometry.ts +0 -169
- package/src/components/timeline-pill-placement.ts +0 -99
- /package/dist/{browser-viewer-5X47I6T2.js.map → browser-viewer-63TXMINB.js.map} +0 -0
- /package/dist/{chunk-UINDK6C3.js.map → chunk-2QUSQVF2.js.map} +0 -0
- /package/dist/{chunk-5EXGU7UF.js.map → chunk-DOJWJQ3F.js.map} +0 -0
- /package/dist/{chunk-BI57CQUV.js.map → chunk-I7IWRQLN.js.map} +0 -0
- /package/dist/{chunk-XA6R7DJQ.js.map → chunk-IQUCRAT7.js.map} +0 -0
- /package/dist/{computer-viewer-7GF35SNY.js.map → computer-viewer-X2MBRZY4.js.map} +0 -0
- /package/dist/{latest-question-3BJGKQQ6.js.map → latest-question-CNEZ5KAN.js.map} +0 -0
- /package/dist/{model-policy-picker-menu-PUTA5JOB.js.map → model-policy-picker-menu-JSA64TNN.js.map} +0 -0
- /package/dist/{sandbox-files-AEJTWGT4.js.map → sandbox-files-BBC47SLD.js.map} +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
InteractionInterventionBanner,
|
|
3
|
+
isInteractionControlUnavailable,
|
|
3
4
|
isNonRetryableInteractionError,
|
|
4
5
|
isSourcePlacementChangedError,
|
|
5
6
|
useInteractionInterventions,
|
|
6
7
|
useInteractionInvalidation
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-GISEVGS6.js";
|
|
8
9
|
import {
|
|
9
10
|
copyTextToClipboard
|
|
10
11
|
} from "./chunk-JVYQRRC4.js";
|
|
@@ -22,7 +23,7 @@ import {
|
|
|
22
23
|
} from "./chunk-5J4FOW6Q.js";
|
|
23
24
|
import {
|
|
24
25
|
usePageLiveActivity
|
|
25
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-YQEAA6LT.js";
|
|
26
27
|
import {
|
|
27
28
|
useEmbeddedComputerInteraction
|
|
28
29
|
} from "./chunk-NEXLLTP4.js";
|
|
@@ -452,6 +453,7 @@ function useComputerSession(options) {
|
|
|
452
453
|
requestRef.current.controller?.abort();
|
|
453
454
|
const controller = new AbortController();
|
|
454
455
|
requestRef.current = { id, controller };
|
|
456
|
+
let discoveryCompleted = false;
|
|
455
457
|
try {
|
|
456
458
|
const [session, targetResponse] = await Promise.all([
|
|
457
459
|
client.getComputerSession(workspaceId, computerSessionId, {
|
|
@@ -461,6 +463,7 @@ function useComputerSession(options) {
|
|
|
461
463
|
signal: controller.signal
|
|
462
464
|
})
|
|
463
465
|
]);
|
|
466
|
+
discoveryCompleted = true;
|
|
464
467
|
if (!mountedRef.current || requestRef.current.id !== id) return;
|
|
465
468
|
const targets = sortComputerTargets(targetResponse.targets);
|
|
466
469
|
const selected = chooseTarget(targets, selectedTargetIdRef.current, session.platform);
|
|
@@ -477,7 +480,8 @@ function useComputerSession(options) {
|
|
|
477
480
|
selectedTargetId: selected?.id ?? null,
|
|
478
481
|
observation: retainedObservation,
|
|
479
482
|
loading: false,
|
|
480
|
-
error: null
|
|
483
|
+
error: null,
|
|
484
|
+
controlError: null
|
|
481
485
|
} : current
|
|
482
486
|
);
|
|
483
487
|
const observation = selected ? await client.observeComputerTarget(workspaceId, computerSessionId, selected.id, {
|
|
@@ -500,11 +504,16 @@ function useComputerSession(options) {
|
|
|
500
504
|
);
|
|
501
505
|
} catch (cause) {
|
|
502
506
|
if (controller.signal.aborted || !mountedRef.current || requestRef.current.id !== id) return;
|
|
507
|
+
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
503
508
|
setState(
|
|
504
509
|
(current) => current.computerSessionId === computerSessionId ? {
|
|
505
510
|
...current,
|
|
506
511
|
loading: false,
|
|
507
|
-
error
|
|
512
|
+
error,
|
|
513
|
+
controlError: isInteractionControlUnavailable(
|
|
514
|
+
error,
|
|
515
|
+
discoveryCompleted ? "observation" : "control"
|
|
516
|
+
) ? error : current.controlError
|
|
508
517
|
} : current
|
|
509
518
|
);
|
|
510
519
|
} finally {
|
|
@@ -561,11 +570,19 @@ function useComputerSession(options) {
|
|
|
561
570
|
(current) => current.computerSessionId === scopeComputerSessionId ? { ...current, mutating: true, error: null } : current
|
|
562
571
|
);
|
|
563
572
|
try {
|
|
564
|
-
|
|
573
|
+
const result = await operation();
|
|
574
|
+
setState(
|
|
575
|
+
(current) => current.computerSessionId === scopeComputerSessionId ? { ...current, controlError: null } : current
|
|
576
|
+
);
|
|
577
|
+
return result;
|
|
565
578
|
} catch (cause) {
|
|
566
579
|
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
567
580
|
setState(
|
|
568
|
-
(current) => current.computerSessionId === scopeComputerSessionId ? {
|
|
581
|
+
(current) => current.computerSessionId === scopeComputerSessionId ? {
|
|
582
|
+
...current,
|
|
583
|
+
error,
|
|
584
|
+
controlError: isInteractionControlUnavailable(error) ? error : current.controlError
|
|
585
|
+
} : current
|
|
569
586
|
);
|
|
570
587
|
throw error;
|
|
571
588
|
} finally {
|
|
@@ -612,7 +629,12 @@ function useComputerSession(options) {
|
|
|
612
629
|
} catch (cause) {
|
|
613
630
|
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
614
631
|
setState(
|
|
615
|
-
(current) => current.computerSessionId === computerSessionId && current.selectedTargetId === target.id ? {
|
|
632
|
+
(current) => current.computerSessionId === computerSessionId && current.selectedTargetId === target.id ? {
|
|
633
|
+
...current,
|
|
634
|
+
loading: false,
|
|
635
|
+
error,
|
|
636
|
+
controlError: isInteractionControlUnavailable(error, "observation") ? error : current.controlError
|
|
637
|
+
} : current
|
|
616
638
|
);
|
|
617
639
|
throw error;
|
|
618
640
|
}
|
|
@@ -684,7 +706,19 @@ function useComputerSession(options) {
|
|
|
684
706
|
);
|
|
685
707
|
const readClipboard = useCallback2(async () => {
|
|
686
708
|
if (!computerSessionId) throw new Error("No desktop is selected.");
|
|
687
|
-
|
|
709
|
+
try {
|
|
710
|
+
return await client.readComputerClipboard(workspaceId, computerSessionId);
|
|
711
|
+
} catch (cause) {
|
|
712
|
+
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
713
|
+
setState(
|
|
714
|
+
(current) => current.computerSessionId === computerSessionId ? {
|
|
715
|
+
...current,
|
|
716
|
+
error,
|
|
717
|
+
controlError: isInteractionControlUnavailable(error) ? error : current.controlError
|
|
718
|
+
} : current
|
|
719
|
+
);
|
|
720
|
+
throw error;
|
|
721
|
+
}
|
|
688
722
|
}, [client, computerSessionId, workspaceId]);
|
|
689
723
|
return {
|
|
690
724
|
session: visible.session,
|
|
@@ -694,6 +728,7 @@ function useComputerSession(options) {
|
|
|
694
728
|
loading: visible.loading,
|
|
695
729
|
mutating: visible.mutating,
|
|
696
730
|
error: visible.error,
|
|
731
|
+
controlError: visible.controlError,
|
|
697
732
|
refresh,
|
|
698
733
|
readClipboard,
|
|
699
734
|
selectTarget,
|
|
@@ -710,7 +745,8 @@ function emptyState(computerSessionId, loading) {
|
|
|
710
745
|
observation: null,
|
|
711
746
|
loading,
|
|
712
747
|
mutating: false,
|
|
713
|
-
error: null
|
|
748
|
+
error: null,
|
|
749
|
+
controlError: null
|
|
714
750
|
};
|
|
715
751
|
}
|
|
716
752
|
function chooseTarget(targets, preferredId, platform) {
|
|
@@ -1084,7 +1120,9 @@ function ComputerViewer({
|
|
|
1084
1120
|
const displayedFrame = frames.frame && frames.frame.computerSessionId === selection?.sessionId && frames.frame.targetId === computer.selectedTarget?.id && frames.frame.targetGeneration === computer.selectedTarget?.targetGeneration ? frames.frame : null;
|
|
1085
1121
|
const rfbStream = frames.attachment?.stream.kind === "direct_rfb" ? frames.attachment.stream : null;
|
|
1086
1122
|
const machineLocked = selectedRegistrySession?.failureCode === "machine_locked";
|
|
1087
|
-
const
|
|
1123
|
+
const controlUnavailable = computer.controlError !== null;
|
|
1124
|
+
const connectionState = controlUnavailable ? "error" : frames.state;
|
|
1125
|
+
const rfbInputEnabled = !machineLocked && !controlUnavailable && computer.session?.capabilities?.pointerInput === true && computer.session?.capabilities?.keyboardInput === true;
|
|
1088
1126
|
const rfbCapability = useMemo2(() => {
|
|
1089
1127
|
if (!rfbStream || !frames.attachment) return null;
|
|
1090
1128
|
const bounds = computer.selectedTarget?.bounds;
|
|
@@ -1192,6 +1230,7 @@ function ComputerViewer({
|
|
|
1192
1230
|
]);
|
|
1193
1231
|
const perform = useCallback4(
|
|
1194
1232
|
async (action, frame) => {
|
|
1233
|
+
if (computer.controlError) throw computer.controlError;
|
|
1195
1234
|
let receipt;
|
|
1196
1235
|
if (action.type === "pointer") {
|
|
1197
1236
|
if (!frame) throw new Error("Desktop view is not ready for pointer input.");
|
|
@@ -1203,8 +1242,12 @@ function ComputerViewer({
|
|
|
1203
1242
|
throw new Error(receipt.error?.message ?? "Desktop input did not complete.");
|
|
1204
1243
|
}
|
|
1205
1244
|
},
|
|
1206
|
-
[act, actFromFrame]
|
|
1245
|
+
[act, actFromFrame, computer.controlError]
|
|
1207
1246
|
);
|
|
1247
|
+
const reconnect = () => {
|
|
1248
|
+
void refreshComputer();
|
|
1249
|
+
frames.reconnect();
|
|
1250
|
+
};
|
|
1208
1251
|
const copyFromRfb = useCallback4(
|
|
1209
1252
|
(event) => {
|
|
1210
1253
|
if (!rfbInputEnabled || !rfbStream || computer.session?.capabilities?.clipboard !== true)
|
|
@@ -1298,7 +1341,7 @@ function ComputerViewer({
|
|
|
1298
1341
|
},
|
|
1299
1342
|
onCreate: hideGenericCreate ? void 0 : createComputer,
|
|
1300
1343
|
onRefresh: () => {
|
|
1301
|
-
if (
|
|
1344
|
+
if (connectionState === "error" && !generationLossSelected && !generationLossFrames) {
|
|
1302
1345
|
frames.reconnect();
|
|
1303
1346
|
}
|
|
1304
1347
|
void Promise.all([refreshRegistry(), refreshComputer()]);
|
|
@@ -1356,7 +1399,19 @@ function ComputerViewer({
|
|
|
1356
1399
|
className: "h-full"
|
|
1357
1400
|
}
|
|
1358
1401
|
),
|
|
1359
|
-
!rfbInputEnabled ? /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute bottom-3 left-1/2 -translate-x-1/2 rounded-full border border-white/10 bg-black/70 px-3 py-1 text-[11px] text-white/80 backdrop-blur", children:
|
|
1402
|
+
!rfbInputEnabled ? /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute bottom-3 left-1/2 -translate-x-1/2 rounded-full border border-white/10 bg-black/70 px-3 py-1 text-[11px] text-white/80 backdrop-blur", children: controlUnavailable ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1403
|
+
"Desktop controls unavailable",
|
|
1404
|
+
" ",
|
|
1405
|
+
/* @__PURE__ */ jsx(
|
|
1406
|
+
"button",
|
|
1407
|
+
{
|
|
1408
|
+
type: "button",
|
|
1409
|
+
onClick: reconnect,
|
|
1410
|
+
className: "pointer-events-auto ml-2 font-medium underline",
|
|
1411
|
+
children: "Reconnect"
|
|
1412
|
+
}
|
|
1413
|
+
)
|
|
1414
|
+
] }) : "View only \xB7 direct input unavailable" }) : null
|
|
1360
1415
|
] }) : /* @__PURE__ */ jsx(
|
|
1361
1416
|
ComputerViewport,
|
|
1362
1417
|
{
|
|
@@ -1364,16 +1419,18 @@ function ComputerViewer({
|
|
|
1364
1419
|
observation: computer.observation,
|
|
1365
1420
|
target: computer.selectedTarget,
|
|
1366
1421
|
machineLocked,
|
|
1367
|
-
|
|
1368
|
-
|
|
1422
|
+
controlUnavailable,
|
|
1423
|
+
connectionState,
|
|
1424
|
+
connectionError: computer.controlError ?? frames.error ?? computer.error,
|
|
1369
1425
|
mutating: computer.mutating,
|
|
1370
1426
|
backgroundActions: computer.session?.capabilities?.backgroundActions === true,
|
|
1427
|
+
backgroundInput: computer.session?.capabilities?.backgroundInput === true,
|
|
1371
1428
|
clipboardEnabled: computer.session?.capabilities?.clipboard === true,
|
|
1372
1429
|
pointerInput: computer.session?.capabilities?.pointerInput === true,
|
|
1373
1430
|
keyboardInput: computer.session?.capabilities?.keyboardInput === true,
|
|
1374
1431
|
onAction: perform,
|
|
1375
1432
|
onReadClipboard: computer.readClipboard,
|
|
1376
|
-
onReconnect: generationLossSelected || generationLossFrames ? () => void 0 :
|
|
1433
|
+
onReconnect: generationLossSelected || generationLossFrames ? () => void 0 : reconnect,
|
|
1377
1434
|
onError: (cause) => notifyError(cause, "Desktop input failed.")
|
|
1378
1435
|
},
|
|
1379
1436
|
JSON.stringify([
|
|
@@ -1387,7 +1444,8 @@ function ComputerViewer({
|
|
|
1387
1444
|
ComputerSemanticPanel,
|
|
1388
1445
|
{
|
|
1389
1446
|
observation: computer.observation,
|
|
1390
|
-
mutating: computer.mutating,
|
|
1447
|
+
mutating: computer.mutating || controlUnavailable,
|
|
1448
|
+
controlUnavailable,
|
|
1391
1449
|
onAction: (action) => void perform(action, null).catch(
|
|
1392
1450
|
(cause) => notifyError(cause, "Desktop action failed.")
|
|
1393
1451
|
)
|
|
@@ -1399,10 +1457,11 @@ function ComputerViewer({
|
|
|
1399
1457
|
{
|
|
1400
1458
|
session: computer.session,
|
|
1401
1459
|
target: computer.selectedTarget,
|
|
1402
|
-
connectionState
|
|
1460
|
+
connectionState,
|
|
1461
|
+
controlUnavailable,
|
|
1403
1462
|
refreshing: registry.refreshing,
|
|
1404
1463
|
showControls,
|
|
1405
|
-
controlCount:
|
|
1464
|
+
controlCount: semanticControls(computer.observation).length,
|
|
1406
1465
|
onToggleControls: () => setShowControls((current) => !current)
|
|
1407
1466
|
}
|
|
1408
1467
|
)
|
|
@@ -1627,6 +1686,7 @@ function ComputerLifecyclePanel(props) {
|
|
|
1627
1686
|
function ComputerViewport(props) {
|
|
1628
1687
|
const canvasRef = useRef4(null);
|
|
1629
1688
|
const inputRef = useRef4(null);
|
|
1689
|
+
const composingRef = useRef4(false);
|
|
1630
1690
|
const pointerStartRef = useRef4(null);
|
|
1631
1691
|
const clickTimerRef = useRef4(null);
|
|
1632
1692
|
const lastClickRef = useRef4(null);
|
|
@@ -1647,7 +1707,7 @@ function ComputerViewport(props) {
|
|
|
1647
1707
|
readClipboardRef.current = props.onReadClipboard;
|
|
1648
1708
|
errorRef.current = props.onError;
|
|
1649
1709
|
const streamFailed = props.connectionState === "error";
|
|
1650
|
-
const rawInputEnabled = !streamFailed && !props.machineLocked && (!props.backgroundActions || props.target?.kind === "screen" || props.target?.focused === true);
|
|
1710
|
+
const rawInputEnabled = !streamFailed && !props.controlUnavailable && !props.machineLocked && (props.backgroundInput || !props.backgroundActions || props.target?.kind === "screen" || props.target?.focused === true);
|
|
1651
1711
|
const clearBufferedInput = useCallback4(() => {
|
|
1652
1712
|
if (clickTimerRef.current) clearTimeout(clickTimerRef.current);
|
|
1653
1713
|
if (wheelRef.current?.timer) clearTimeout(wheelRef.current.timer);
|
|
@@ -1657,10 +1717,25 @@ function ComputerViewport(props) {
|
|
|
1657
1717
|
pendingTextRef.current = null;
|
|
1658
1718
|
pointerStartRef.current = null;
|
|
1659
1719
|
lastClickRef.current = null;
|
|
1720
|
+
composingRef.current = false;
|
|
1660
1721
|
if (inputRef.current) inputRef.current.value = "";
|
|
1661
1722
|
}, []);
|
|
1662
1723
|
const pointerInputEnabled = rawInputEnabled && props.pointerInput;
|
|
1663
1724
|
const keyboardInputEnabled = rawInputEnabled && props.keyboardInput;
|
|
1725
|
+
useLayoutEffect(() => {
|
|
1726
|
+
const canvas = canvasRef.current;
|
|
1727
|
+
const viewport = canvas?.parentElement;
|
|
1728
|
+
if (!canvas || !viewport) return;
|
|
1729
|
+
const fit = () => fitComputerCanvas(canvas);
|
|
1730
|
+
fit();
|
|
1731
|
+
if (typeof ResizeObserver === "undefined") {
|
|
1732
|
+
window.addEventListener("resize", fit);
|
|
1733
|
+
return () => window.removeEventListener("resize", fit);
|
|
1734
|
+
}
|
|
1735
|
+
const observer = new ResizeObserver(fit);
|
|
1736
|
+
observer.observe(viewport);
|
|
1737
|
+
return () => observer.disconnect();
|
|
1738
|
+
}, []);
|
|
1664
1739
|
const paintQueuedFrames = useCallback4(() => {
|
|
1665
1740
|
if (decodingFrameRef.current) return;
|
|
1666
1741
|
decodingFrameRef.current = true;
|
|
@@ -1925,6 +2000,9 @@ function ComputerViewport(props) {
|
|
|
1925
2000
|
};
|
|
1926
2001
|
const keyDown = (event) => {
|
|
1927
2002
|
if (!keyboardInputEnabled) return;
|
|
2003
|
+
if (composingRef.current || event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229) {
|
|
2004
|
+
return;
|
|
2005
|
+
}
|
|
1928
2006
|
flushPendingWheel();
|
|
1929
2007
|
const command = event.metaKey || event.ctrlKey;
|
|
1930
2008
|
if (props.clipboardEnabled && command && !event.altKey && ["c", "v"].includes(event.key.toLowerCase())) {
|
|
@@ -1970,7 +2048,8 @@ function ComputerViewport(props) {
|
|
|
1970
2048
|
await dispatch({ type: "clipboard", operation: "paste" }, null);
|
|
1971
2049
|
});
|
|
1972
2050
|
};
|
|
1973
|
-
const input = (value) => {
|
|
2051
|
+
const input = (value, nativeComposing = false) => {
|
|
2052
|
+
if (composingRef.current || nativeComposing) return;
|
|
1974
2053
|
if (!value || !keyboardInputEnabled) return;
|
|
1975
2054
|
flushPendingWheel();
|
|
1976
2055
|
flushPendingClick();
|
|
@@ -1987,6 +2066,10 @@ function ComputerViewport(props) {
|
|
|
1987
2066
|
}
|
|
1988
2067
|
if (inputRef.current) inputRef.current.value = "";
|
|
1989
2068
|
};
|
|
2069
|
+
const compositionEnd = (event) => {
|
|
2070
|
+
composingRef.current = false;
|
|
2071
|
+
input(event.currentTarget.value || event.data);
|
|
2072
|
+
};
|
|
1990
2073
|
const showCanvas = props.frame !== null && paintedFrame !== null && sameComputerTarget(props.frame, paintedFrame) && !props.machineLocked && !streamFailed;
|
|
1991
2074
|
return /* @__PURE__ */ jsxs("div", { className: "relative min-h-0 flex-1 overflow-hidden bg-black", children: [
|
|
1992
2075
|
/* @__PURE__ */ jsx(
|
|
@@ -2013,7 +2096,11 @@ function ComputerViewport(props) {
|
|
|
2013
2096
|
{
|
|
2014
2097
|
ref: inputRef,
|
|
2015
2098
|
defaultValue: "",
|
|
2016
|
-
onInput: (event) => input(event.currentTarget.value),
|
|
2099
|
+
onInput: (event) => input(event.currentTarget.value, event.nativeEvent.isComposing),
|
|
2100
|
+
onCompositionStart: () => {
|
|
2101
|
+
composingRef.current = true;
|
|
2102
|
+
},
|
|
2103
|
+
onCompositionEnd: compositionEnd,
|
|
2017
2104
|
onKeyDown: keyDown,
|
|
2018
2105
|
onCopy: copy,
|
|
2019
2106
|
onPaste: paste,
|
|
@@ -2030,6 +2117,7 @@ function ComputerViewport(props) {
|
|
|
2030
2117
|
{
|
|
2031
2118
|
observation: props.observation,
|
|
2032
2119
|
machineLocked: props.machineLocked,
|
|
2120
|
+
controlUnavailable: props.controlUnavailable,
|
|
2033
2121
|
connectionState: props.connectionState,
|
|
2034
2122
|
error: props.connectionError,
|
|
2035
2123
|
onAction: (action) => enqueue(action, null),
|
|
@@ -2069,14 +2157,14 @@ function ComputerViewportFallback(props) {
|
|
|
2069
2157
|
] }) });
|
|
2070
2158
|
}
|
|
2071
2159
|
const controlFailure = interactionControlFailureFromError(props.error);
|
|
2072
|
-
const interactive =
|
|
2160
|
+
const interactive = semanticControls(props.observation).filter((node) => semanticAction(node) !== null).slice(0, 10);
|
|
2073
2161
|
return /* @__PURE__ */ jsx("div", { className: "absolute inset-0 grid place-items-center bg-og-bg p-6", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-md rounded-og-lg border border-og-border bg-og-surface-1 p-4 shadow-lg", children: [
|
|
2074
2162
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2075
2163
|
props.error ? /* @__PURE__ */ jsx(CircleAlertIcon, { className: "size-4 text-og-danger" }) : /* @__PURE__ */ jsx(LoaderCircleIcon, { className: "size-4 animate-spin text-og-fg-muted" }),
|
|
2076
|
-
/* @__PURE__ */ jsx("p", { className: "text-og-menu font-medium text-og-fg", children: isAttachedChromeGenerationLossError(props.error) ? "Chrome reconnected\u2014open a fresh browser/desktop." : props.error ? "Live view disconnected" : computerConnectionLabel(props.connectionState) })
|
|
2164
|
+
/* @__PURE__ */ jsx("p", { className: "text-og-menu font-medium text-og-fg", children: isAttachedChromeGenerationLossError(props.error) ? "Chrome reconnected\u2014open a fresh browser/desktop." : props.controlUnavailable ? "Desktop controls unavailable" : props.error ? "Live view disconnected" : computerConnectionLabel(props.connectionState) })
|
|
2077
2165
|
] }),
|
|
2078
2166
|
props.error ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-og-control leading-5 text-og-fg-muted", children: isAttachedChromeGenerationLossError(props.error) ? "Chrome reconnected\u2014open a fresh browser/desktop. Use Browser \u2192 New browser \u2192 Connected Chrome." : controlFailure?.message ?? props.error.message }) : null,
|
|
2079
|
-
interactive.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mt-3 border-t border-og-border pt-3", children: [
|
|
2167
|
+
interactive.length > 0 && !props.controlUnavailable ? /* @__PURE__ */ jsxs("div", { className: "mt-3 border-t border-og-border pt-3", children: [
|
|
2080
2168
|
/* @__PURE__ */ jsx("p", { className: "mb-2 text-og-xs text-og-fg-subtle", children: "App controls remain available" }),
|
|
2081
2169
|
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: interactive.map((node) => /* @__PURE__ */ jsx(
|
|
2082
2170
|
"button",
|
|
@@ -2104,13 +2192,14 @@ function ComputerViewportFallback(props) {
|
|
|
2104
2192
|
] }) });
|
|
2105
2193
|
}
|
|
2106
2194
|
function ComputerSemanticPanel(props) {
|
|
2107
|
-
const nodes =
|
|
2195
|
+
const nodes = semanticControls(props.observation).slice(0, 100);
|
|
2108
2196
|
return /* @__PURE__ */ jsxs("aside", { className: "box-border max-h-[40%] w-full shrink-0 overflow-y-auto border-t border-og-border bg-og-surface-1 p-2 @xl/computer-viewer:max-h-none @xl/computer-viewer:w-64 @xl/computer-viewer:border-t-0 @xl/computer-viewer:border-l", children: [
|
|
2109
2197
|
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center gap-1.5 px-1 text-og-xs font-medium uppercase tracking-[0.1em] text-og-fg-subtle", children: [
|
|
2110
2198
|
/* @__PURE__ */ jsx(KeyboardIcon, { className: "size-3" }),
|
|
2111
2199
|
" App controls"
|
|
2112
2200
|
] }),
|
|
2113
|
-
|
|
2201
|
+
props.controlUnavailable ? /* @__PURE__ */ jsx("p", { className: "px-1 py-2 text-og-control leading-5 text-og-fg-muted", children: "Reconnect to use app controls." }) : null,
|
|
2202
|
+
nodes.length === 0 ? props.controlUnavailable ? null : /* @__PURE__ */ jsx("p", { className: "px-1 py-2 text-og-control leading-5 text-og-fg-muted", children: "This view has no accessibility controls. Use the live image instead." }) : /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: nodes.map((node) => /* @__PURE__ */ jsx(
|
|
2114
2203
|
ComputerSemanticControl,
|
|
2115
2204
|
{
|
|
2116
2205
|
node,
|
|
@@ -2199,8 +2288,8 @@ function ComputerStatusBar(props) {
|
|
|
2199
2288
|
)
|
|
2200
2289
|
}
|
|
2201
2290
|
),
|
|
2202
|
-
/* @__PURE__ */ jsx("span", { children: props.connectionState === "live" ? "Live" : computerConnectionLabel(props.connectionState) }),
|
|
2203
|
-
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: screen ? "Full screen \xB7 input may move pointer and focus" : props.session?.capabilities?.backgroundActions ? "Window \xB7 app controls work in the background" : props.target?.kind ?? "Desktop" }),
|
|
2291
|
+
/* @__PURE__ */ jsx("span", { children: props.controlUnavailable ? "Controls unavailable" : props.connectionState === "live" ? "Live" : computerConnectionLabel(props.connectionState) }),
|
|
2292
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: props.controlUnavailable ? "Reconnect to use desktop input" : screen ? "Full screen \xB7 input may move pointer and focus" : props.session?.capabilities?.backgroundInput ? "Window \xB7 clicks and typing stay in the background" : props.session?.capabilities?.backgroundActions ? "Window \xB7 app controls work in the background" : props.target?.kind ?? "Desktop" }),
|
|
2204
2293
|
screen ? /* @__PURE__ */ jsx(MousePointer2Icon, { className: "size-3", "aria-hidden": true }) : null,
|
|
2205
2294
|
props.refreshing ? /* @__PURE__ */ jsx(LoaderCircleIcon, { className: "size-3 animate-spin" }) : null,
|
|
2206
2295
|
/* @__PURE__ */ jsxs(
|
|
@@ -2236,11 +2325,30 @@ function ComputerNotice(props) {
|
|
|
2236
2325
|
}
|
|
2237
2326
|
);
|
|
2238
2327
|
}
|
|
2239
|
-
|
|
2328
|
+
var structuralRoles = /* @__PURE__ */ new Set([
|
|
2329
|
+
"frame",
|
|
2330
|
+
"panel",
|
|
2331
|
+
"section",
|
|
2332
|
+
"document",
|
|
2333
|
+
"document web",
|
|
2334
|
+
"static",
|
|
2335
|
+
"static text",
|
|
2336
|
+
"heading",
|
|
2337
|
+
"paragraph",
|
|
2338
|
+
"notification",
|
|
2339
|
+
"separator",
|
|
2340
|
+
"tool bar",
|
|
2341
|
+
"page tab list"
|
|
2342
|
+
]);
|
|
2343
|
+
function semanticControls(observation) {
|
|
2240
2344
|
if (observation?.semantic?.kind !== "snapshot") return [];
|
|
2241
2345
|
const result = [];
|
|
2242
2346
|
const visit = (node) => {
|
|
2243
|
-
|
|
2347
|
+
const role = node.role.trim().toLowerCase();
|
|
2348
|
+
const label = node.name?.trim() || node.identifier?.trim();
|
|
2349
|
+
if (node.actions.includes("set_value") || label && label.toLowerCase() !== role && !structuralRoles.has(role) && semanticAction(node) !== null) {
|
|
2350
|
+
result.push(node);
|
|
2351
|
+
}
|
|
2244
2352
|
node.children?.forEach(visit);
|
|
2245
2353
|
};
|
|
2246
2354
|
observation.semantic.roots.forEach(visit);
|
|
@@ -2261,11 +2369,24 @@ function semanticValue(node) {
|
|
|
2261
2369
|
return typeof node.value === "string" ? node.value : null;
|
|
2262
2370
|
}
|
|
2263
2371
|
function paintCanvas(canvas, image, width, height) {
|
|
2372
|
+
const dimensionsChanged = canvas.width !== width || canvas.height !== height;
|
|
2264
2373
|
canvas.width = width;
|
|
2265
2374
|
canvas.height = height;
|
|
2266
2375
|
const context = canvas.getContext("2d", { alpha: false });
|
|
2267
2376
|
if (!context) throw new Error("Desktop canvas is unavailable.");
|
|
2268
2377
|
context.drawImage(image, 0, 0, width, height);
|
|
2378
|
+
if (dimensionsChanged) fitComputerCanvas(canvas);
|
|
2379
|
+
}
|
|
2380
|
+
function fitComputerCanvas(canvas) {
|
|
2381
|
+
const viewport = canvas.parentElement;
|
|
2382
|
+
if (!viewport || canvas.width <= 0 || canvas.height <= 0) return;
|
|
2383
|
+
const scale = Math.min(
|
|
2384
|
+
viewport.clientWidth / canvas.width,
|
|
2385
|
+
viewport.clientHeight / canvas.height
|
|
2386
|
+
);
|
|
2387
|
+
if (!Number.isFinite(scale) || scale <= 0) return;
|
|
2388
|
+
canvas.style.width = `${canvas.width * scale}px`;
|
|
2389
|
+
canvas.style.height = `${canvas.height * scale}px`;
|
|
2269
2390
|
}
|
|
2270
2391
|
function loadImage(url) {
|
|
2271
2392
|
return new Promise((resolve, reject) => {
|
|
@@ -2423,4 +2544,4 @@ export {
|
|
|
2423
2544
|
ComputerViewer,
|
|
2424
2545
|
computerKey
|
|
2425
2546
|
};
|
|
2426
|
-
//# sourceMappingURL=chunk-
|
|
2547
|
+
//# sourceMappingURL=chunk-YN7I3STW.js.map
|