@opengeni/react 0.45.0 → 0.48.0
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 +68 -12
- package/dist/{chunk-U3CSCMWA.js → chunk-FK6VG4LL.js} +9 -13
- package/dist/chunk-FK6VG4LL.js.map +1 -0
- package/dist/{chunk-HFO4ERGQ.js → chunk-FWXGSNXT.js} +2 -2
- package/dist/{chunk-SRFUT2ZU.js → chunk-I4MPFDRP.js} +119 -63
- package/dist/chunk-I4MPFDRP.js.map +1 -0
- package/dist/{chunk-EB67J347.js → chunk-KZ73RL76.js} +111 -31
- package/dist/chunk-KZ73RL76.js.map +1 -0
- package/dist/{chunk-LWR4MXSS.js → chunk-LHLYWG5R.js} +10 -1
- package/dist/chunk-LHLYWG5R.js.map +1 -0
- package/dist/{chunk-L3EWO3UK.js → chunk-NJ7M2B6Z.js} +445 -84
- package/dist/chunk-NJ7M2B6Z.js.map +1 -0
- package/dist/{chunk-VCBFUSUZ.js → chunk-O4VXOBGF.js} +3 -3
- package/dist/{chunk-VCBFUSUZ.js.map → chunk-O4VXOBGF.js.map} +1 -1
- package/dist/{chunk-6EDV6YFE.js → chunk-OL6QVXGF.js} +121 -29
- package/dist/chunk-OL6QVXGF.js.map +1 -0
- package/dist/chunk-VZTQ73XT.js +86 -0
- package/dist/chunk-VZTQ73XT.js.map +1 -0
- package/dist/{chunk-EHSYZ4KP.js → chunk-WYA65Y3F.js} +16 -16
- package/dist/chunk-WYA65Y3F.js.map +1 -0
- package/dist/{chunk-FD72GJMK.js → chunk-XCNTXWBB.js} +274 -125
- package/dist/chunk-XCNTXWBB.js.map +1 -0
- package/dist/client.d.ts +1 -1
- package/dist/components/chat-composer.d.ts +7 -2
- package/dist/components/composer-transcription-control.d.ts +2 -0
- package/dist/components/composer.d.ts +14 -0
- package/dist/components/machines/machine-detail.d.ts +3 -1
- package/dist/components/machines-dashboard.d.ts +3 -3
- package/dist/components/message-timeline.d.ts +12 -2
- package/dist/components/sandbox-files.d.ts +2 -2
- package/dist/components/sandbox-terminal.d.ts +29 -0
- package/dist/components/sandbox-workspace.d.ts +5 -1
- package/dist/components/workspace-dock.d.ts +3 -1
- package/dist/composer.d.ts +2 -2
- package/dist/composer.js +6 -6
- package/dist/hooks/internal.d.ts +6 -0
- package/dist/hooks/use-codex-accounts.d.ts +1 -1
- package/dist/hooks/use-environments.d.ts +10 -4
- package/dist/hooks/use-machines.d.ts +7 -0
- package/dist/hooks/use-sandbox-files.d.ts +19 -0
- package/dist/hooks/use-sandbox-git.d.ts +7 -0
- package/dist/hooks/use-transcription.d.ts +2 -2
- package/dist/hooks/use-voice-input.d.ts +13 -4
- package/dist/index.d.ts +6 -5
- package/dist/index.js +904 -538
- package/dist/index.js.map +1 -1
- package/dist/lib/composer-responsive-context.d.ts +9 -0
- package/dist/lib/use-portal-token-style.d.ts +14 -3
- package/dist/machines.js +2 -2
- package/dist/{queue-surface-implementation-J4XJFKRW.js → queue-surface-implementation-U5JFG7HT.js} +19 -18
- package/dist/queue-surface-implementation-U5JFG7HT.js.map +1 -0
- package/dist/realtime/realtime-control.d.ts +9 -0
- package/dist/realtime.js +29 -32
- package/dist/realtime.js.map +1 -1
- package/dist/session-ui.js +5 -5
- package/dist/session.js +4 -4
- package/dist/timeline/activity-rail.d.ts +3 -2
- package/dist/timeline/index.d.ts +2 -2
- package/dist/timeline/parsers.d.ts +3 -3
- package/dist/timeline/registry.d.ts +3 -0
- package/dist/timeline/screenshot-lightbox.d.ts +1 -1
- package/dist/timeline/types.d.ts +4 -0
- package/dist/voice-recording-store.d.ts +8 -2
- package/package.json +20 -4
- package/src/client.ts +3 -0
- package/src/components/chat-composer.tsx +12 -2
- package/src/components/code-editor.tsx +1 -1
- package/src/components/command-palette.tsx +1 -1
- package/src/components/composer-transcription-control.tsx +41 -16
- package/src/components/composer.tsx +52 -26
- package/src/components/copy-button.tsx +2 -2
- package/src/components/desktop-viewer.tsx +2 -2
- package/src/components/file-browser.tsx +39 -17
- package/src/components/human-input-form.tsx +2 -2
- package/src/components/machine-card.tsx +1 -1
- package/src/components/machines/machine-detail.tsx +39 -15
- package/src/components/machines-dashboard.tsx +7 -6
- package/src/components/message-timeline.tsx +44 -11
- package/src/components/model-picker.tsx +2 -2
- package/src/components/model-policy-picker.tsx +16 -15
- package/src/components/queue-surface-implementation.tsx +20 -16
- package/src/components/queue-surface-state.tsx +2 -2
- package/src/components/sandbox-files.tsx +140 -60
- package/src/components/sandbox-terminal.tsx +24 -5
- package/src/components/sandbox-workspace.tsx +180 -142
- package/src/components/session-chrome.tsx +14 -14
- package/src/components/tooltip.tsx +13 -16
- package/src/components/user-message-body.tsx +1 -1
- package/src/components/workbench-changes.tsx +4 -4
- package/src/components/workspace-dock.tsx +13 -5
- package/src/composer.ts +3 -0
- package/src/hooks/internal.ts +132 -38
- package/src/hooks/use-codex-accounts.ts +4 -4
- package/src/hooks/use-environments.ts +24 -5
- package/src/hooks/use-file-attachments.ts +70 -32
- package/src/hooks/use-goal.ts +17 -5
- package/src/hooks/use-machines.ts +47 -1
- package/src/hooks/use-sandbox-files.ts +310 -59
- package/src/hooks/use-sandbox-git.ts +148 -41
- package/src/hooks/use-session-capabilities.ts +35 -24
- package/src/hooks/use-session-events.ts +18 -4
- package/src/hooks/use-transcription.ts +4 -14
- package/src/hooks/use-turn-queue.ts +17 -5
- package/src/hooks/use-voice-input.ts +481 -36
- package/src/hooks/use-windowed-sections.ts +9 -7
- package/src/index.ts +11 -6
- package/src/lib/composer-responsive-context.ts +15 -0
- package/src/lib/use-portal-token-style.ts +60 -15
- package/src/provider.tsx +52 -7
- package/src/realtime/dropdown-menu.tsx +15 -19
- package/src/realtime/realtime-control.tsx +18 -7
- package/src/timeline/activity-rail.tsx +15 -6
- package/src/timeline/index.ts +1 -1
- package/src/timeline/parsers.ts +33 -20
- package/src/timeline/projection.ts +23 -0
- package/src/timeline/registry.ts +7 -0
- package/src/timeline/screenshot-lightbox.tsx +15 -4
- package/src/timeline/shared.tsx +8 -8
- package/src/timeline/tool-renderers.tsx +166 -22
- package/src/timeline/turn-summary.tsx +6 -6
- package/src/timeline/types.ts +4 -0
- package/src/voice-recording-store.ts +15 -0
- package/styles/compiled.css +5065 -0
- package/styles/compiled.d.ts +2 -0
- package/styles/effective-tokens.css +27 -0
- package/styles/index.css +3 -0
- package/styles/responsive.css +196 -0
- package/styles/responsive.d.ts +2 -0
- package/styles/tokens.css +50 -17
- package/dist/chunk-6EDV6YFE.js.map +0 -1
- package/dist/chunk-EB67J347.js.map +0 -1
- package/dist/chunk-EHSYZ4KP.js.map +0 -1
- package/dist/chunk-FD72GJMK.js.map +0 -1
- package/dist/chunk-JB5725BI.js +0 -48
- package/dist/chunk-JB5725BI.js.map +0 -1
- package/dist/chunk-L3EWO3UK.js.map +0 -1
- package/dist/chunk-LWR4MXSS.js.map +0 -1
- package/dist/chunk-SRFUT2ZU.js.map +0 -1
- package/dist/chunk-U3CSCMWA.js.map +0 -1
- package/dist/queue-surface-implementation-J4XJFKRW.js.map +0 -1
- /package/dist/{chunk-HFO4ERGQ.js.map → chunk-FWXGSNXT.js.map} +0 -0
|
@@ -14,32 +14,34 @@
|
|
|
14
14
|
// tokens only. `apps/web` consumes this through the exact public surface an
|
|
15
15
|
// external embedder uses — that is criterion F1.
|
|
16
16
|
import { type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
17
|
-
import { Popover } from "radix-ui";
|
|
18
17
|
import type { SessionEvent } from "@opengeni/sdk";
|
|
19
18
|
import {
|
|
20
19
|
CircleCheckIcon,
|
|
21
20
|
CpuIcon,
|
|
22
|
-
|
|
21
|
+
FileCode2Icon,
|
|
22
|
+
GitCompareArrowsIcon,
|
|
23
23
|
LoaderCircleIcon,
|
|
24
|
+
MonitorIcon,
|
|
24
25
|
RefreshCwIcon,
|
|
26
|
+
SquareTerminalIcon,
|
|
25
27
|
TriangleAlertIcon,
|
|
26
28
|
} from "lucide-react";
|
|
27
29
|
|
|
28
30
|
import { type ClientOverride, useOpenGeni } from "../provider";
|
|
29
31
|
import { cn } from "../lib/cn";
|
|
30
32
|
import { xtermThemeFromTokens } from "../lib/xterm-theme";
|
|
31
|
-
import { usePortalTokenStyle } from "../lib/use-portal-token-style";
|
|
32
33
|
import { useSessionCapabilities } from "../hooks/use-session-capabilities";
|
|
33
34
|
import { useSandboxFiles } from "../hooks/use-sandbox-files";
|
|
34
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
useSandboxGit,
|
|
37
|
+
type SandboxGitComparison,
|
|
38
|
+
type UseSandboxGitResult,
|
|
39
|
+
} from "../hooks/use-sandbox-git";
|
|
35
40
|
import { useSandboxTerminal } from "../hooks/use-sandbox-terminal";
|
|
36
41
|
import { useWorkspaceCapture } from "../hooks/use-workspace-capture";
|
|
37
|
-
import {
|
|
42
|
+
import { useMachineChip, type MachineChip } from "../hooks/use-machine-chip";
|
|
38
43
|
import { useMachines } from "../hooks/use-machines";
|
|
39
44
|
import type { MachineView } from "../types/machines";
|
|
40
|
-
import { connectionStatusForState } from "../types/machines";
|
|
41
|
-
import { ConnectionStatusPill } from "./machine-status-pill";
|
|
42
|
-
import { SharedMachineDisclosure } from "./machine-dock-bar";
|
|
43
45
|
import { SandboxFiles } from "./sandbox-files";
|
|
44
46
|
import { WorkbenchChanges } from "./workbench-changes";
|
|
45
47
|
import { SandboxTerminal, type XtermTheme } from "./sandbox-terminal";
|
|
@@ -97,6 +99,17 @@ function captureDegradedMessage(reason: string): string {
|
|
|
97
99
|
}
|
|
98
100
|
}
|
|
99
101
|
|
|
102
|
+
function WorkbenchTabLabel({ icon, children }: { icon: ReactNode; children: ReactNode }) {
|
|
103
|
+
return (
|
|
104
|
+
<span className="inline-flex items-center gap-1.5">
|
|
105
|
+
<span className="[&>svg]:size-3.5" aria-hidden>
|
|
106
|
+
{icon}
|
|
107
|
+
</span>
|
|
108
|
+
<span>{children}</span>
|
|
109
|
+
</span>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
100
113
|
/**
|
|
101
114
|
* Decide a workspace tab from an already-local event log: the newest
|
|
102
115
|
* `workspace.revision.captured` announce carries the change surface stats, so
|
|
@@ -181,6 +194,8 @@ export type UseSandboxWorkspaceTabsOptions = ClientOverride & {
|
|
|
181
194
|
/** Override the source-driven default tab (e.g. a host landing tab id). When
|
|
182
195
|
* omitted the workbench picks Changes-vs-Files from capture or live Git. */
|
|
183
196
|
initialTab?: string | null | undefined;
|
|
197
|
+
/** Actually selected dock tab. Inactive data surfaces retain cache but issue no live reads. */
|
|
198
|
+
activeTab?: string | null | undefined;
|
|
184
199
|
/** Host-routed notifications (mutation errors, desktop-consent failures). The
|
|
185
200
|
* package never imports a toast library — the host decides how to surface. */
|
|
186
201
|
onNotify?: ((notification: WorkspaceNotification) => void) | undefined;
|
|
@@ -234,6 +249,7 @@ export function useSandboxWorkspaceTabs(
|
|
|
234
249
|
const { sessionId, events, onNotify, requestedFilePath, requestedFileRequestId, onOpenFile } =
|
|
235
250
|
options;
|
|
236
251
|
const initialTab = options.initialTab ?? null;
|
|
252
|
+
const activeTab = options.activeTab ?? initialTab;
|
|
237
253
|
const requestedSurfaces = options.surfaces ?? WORKBENCH_SURFACES;
|
|
238
254
|
const surfaceSet = new Set<SandboxWorkspaceSurface>(requestedSurfaces);
|
|
239
255
|
const changesEnabled = surfaceSet.has(WORKBENCH_TAB_CHANGES);
|
|
@@ -242,6 +258,13 @@ export function useSandboxWorkspaceTabs(
|
|
|
242
258
|
const desktopEnabled = surfaceSet.has(WORKBENCH_TAB_DESKTOP);
|
|
243
259
|
const workspaceDataEnabled = changesEnabled || filesEnabled;
|
|
244
260
|
const anySurfaceEnabled = workspaceDataEnabled || terminalEnabled || desktopEnabled;
|
|
261
|
+
// Do not speculatively activate both remote workspace surfaces while the dock
|
|
262
|
+
// is still resolving its selected tab. Modal calls cannot be cancelled after
|
|
263
|
+
// dispatch, so that transient state otherwise creates an aborted duplicate
|
|
264
|
+
// batch immediately before the real selected-tab request.
|
|
265
|
+
const resolvedActiveTab = activeTab ?? initialTab;
|
|
266
|
+
const changesActive = resolvedActiveTab === WORKBENCH_TAB_CHANGES;
|
|
267
|
+
const filesActive = resolvedActiveTab === WORKBENCH_TAB_FILES;
|
|
245
268
|
const surfaceIdentity = WORKBENCH_SURFACES.filter((surface) => surfaceSet.has(surface)).join(",");
|
|
246
269
|
|
|
247
270
|
// The three box-warming INTENTS, each off by default and each
|
|
@@ -382,6 +405,8 @@ export function useSandboxWorkspaceTabs(
|
|
|
382
405
|
// No passive Channel-A reads while cold, even after a conclusive capture
|
|
383
406
|
// miss. A missing capture gets an explicit "Open live workspace" gate.
|
|
384
407
|
enabled: filesEnabled && (captureAvailable || (fileSystemOn && liveWorkspaceExpected)),
|
|
408
|
+
active: filesActive,
|
|
409
|
+
repoPaths,
|
|
385
410
|
liveness,
|
|
386
411
|
capture: captureState.capture,
|
|
387
412
|
// A reverted optimistic mutation (e.g. a 409 rename collision) surfaces as a
|
|
@@ -392,24 +417,58 @@ export function useSandboxWorkspaceTabs(
|
|
|
392
417
|
message: `Could not ${op}: ${error.message}`,
|
|
393
418
|
}),
|
|
394
419
|
});
|
|
420
|
+
const [storedChangesComparison, setStoredChangesComparison] = useState<{
|
|
421
|
+
sessionId: string;
|
|
422
|
+
value: SandboxGitComparison;
|
|
423
|
+
} | null>(null);
|
|
424
|
+
const captureSupportsBranch =
|
|
425
|
+
captureState.capture !== null &&
|
|
426
|
+
captureState.capture.repos.length > 0 &&
|
|
427
|
+
captureState.capture.repos.every((repo) => repo.branchDiff !== undefined);
|
|
428
|
+
// A sleeping workspace can truthfully serve only the captured working-tree
|
|
429
|
+
// comparison. A live workspace defaults to the branch comparison so committed
|
|
430
|
+
// agent work remains visible. Explicit user selection is scoped per session.
|
|
431
|
+
const changesComparison =
|
|
432
|
+
storedChangesComparison?.sessionId === sessionId
|
|
433
|
+
? storedChangesComparison.value
|
|
434
|
+
: liveWorkspaceExpected || captureSupportsBranch
|
|
435
|
+
? "branch"
|
|
436
|
+
: "working";
|
|
437
|
+
const setChangesComparison = useCallback(
|
|
438
|
+
(value: SandboxGitComparison) => setStoredChangesComparison({ sessionId, value }),
|
|
439
|
+
[sessionId],
|
|
440
|
+
);
|
|
395
441
|
const git = useSandboxGit(sessionId, {
|
|
396
442
|
events,
|
|
397
|
-
enabled:
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
//
|
|
405
|
-
//
|
|
406
|
-
|
|
407
|
-
staged: true,
|
|
443
|
+
enabled:
|
|
444
|
+
changesComparison === "working"
|
|
445
|
+
? workspaceDataEnabled && (captureAvailable || (gitOn && liveWorkspaceExpected))
|
|
446
|
+
: changesComparison === "branch"
|
|
447
|
+
? workspaceDataEnabled && (captureSupportsBranch || (gitOn && liveWorkspaceExpected))
|
|
448
|
+
: workspaceDataEnabled && gitOn && liveWorkspaceExpected,
|
|
449
|
+
// Before the dock chooses its source-driven default, Git is the sole probe
|
|
450
|
+
// that may need to resolve that choice on a live workspace. Files remains
|
|
451
|
+
// dormant, avoiding the old duplicate full-tree read.
|
|
452
|
+
active: changesActive || resolvedActiveTab === null,
|
|
408
453
|
repoPaths,
|
|
409
454
|
liveness,
|
|
410
|
-
|
|
455
|
+
comparison: changesComparison,
|
|
456
|
+
capture: changesComparison === "staged" ? null : captureState.capture,
|
|
411
457
|
});
|
|
412
|
-
|
|
458
|
+
useEffect(() => {
|
|
459
|
+
if (
|
|
460
|
+
changesComparison === "branch" &&
|
|
461
|
+
git.error &&
|
|
462
|
+
storedChangesComparison?.sessionId !== sessionId
|
|
463
|
+
) {
|
|
464
|
+
// `origin/HEAD` is not guaranteed on a newly initialized repository, a
|
|
465
|
+
// connected machine, or a clone whose remote was renamed. The implicit
|
|
466
|
+
// live default must not strand the whole Changes surface when its ordinary
|
|
467
|
+
// working-tree comparison is still valid. Fall back once; an explicit
|
|
468
|
+
// user-selected Branch view remains selected and surfaces its real error.
|
|
469
|
+
setStoredChangesComparison({ sessionId, value: "working" });
|
|
470
|
+
}
|
|
471
|
+
}, [changesComparison, git.error, sessionId, storedChangesComparison?.sessionId]);
|
|
413
472
|
// Token-derived xterm theme; re-derive on a `data-og-theme` flip. Generic — it
|
|
414
473
|
// belongs in the package (an embedder's theme toggle drives it too).
|
|
415
474
|
const [xtermTheme, setXtermTheme] = useState<XtermTheme | undefined>(undefined);
|
|
@@ -485,6 +544,10 @@ export function useSandboxWorkspaceTabs(
|
|
|
485
544
|
const captureIsAuthoritative =
|
|
486
545
|
!liveWorkspaceExpected && (liveness !== undefined || caps.error !== null);
|
|
487
546
|
const captureUnavailable = captureState.fileCount === 0 || captureState.error !== null;
|
|
547
|
+
const implicitBranchFallbackPending =
|
|
548
|
+
changesComparison === "branch" &&
|
|
549
|
+
git.error !== null &&
|
|
550
|
+
storedChangesComparison?.sessionId !== sessionId;
|
|
488
551
|
if (defaultTabRef.current.value === null) {
|
|
489
552
|
if (initialTab && (!isWorkbenchSurface(initialTab) || surfaceSet.has(initialTab))) {
|
|
490
553
|
defaultTabRef.current.value = initialTab;
|
|
@@ -527,9 +590,9 @@ export function useSandboxWorkspaceTabs(
|
|
|
527
590
|
changesEnabled,
|
|
528
591
|
filesEnabled,
|
|
529
592
|
);
|
|
530
|
-
} else if (captureUnavailable && git.error) {
|
|
593
|
+
} else if (captureUnavailable && git.error && !implicitBranchFallbackPending) {
|
|
531
594
|
// No capture and live Git failed: Files is the least surprising fallback
|
|
532
|
-
//
|
|
595
|
+
// after the implicit branch-to-working fallback has also had its chance.
|
|
533
596
|
defaultTabRef.current.value = sourceDrivenDefaultTab(false, changesEnabled, filesEnabled);
|
|
534
597
|
}
|
|
535
598
|
}
|
|
@@ -543,11 +606,13 @@ export function useSandboxWorkspaceTabs(
|
|
|
543
606
|
if (changesEnabled)
|
|
544
607
|
list.push({
|
|
545
608
|
id: WORKBENCH_TAB_CHANGES,
|
|
546
|
-
label:
|
|
609
|
+
label: <WorkbenchTabLabel icon={<GitCompareArrowsIcon />}>Changes</WorkbenchTabLabel>,
|
|
547
610
|
badge: dirtyCount > 0 ? <DirtyBadge count={dirtyCount} /> : undefined,
|
|
548
611
|
content: (
|
|
549
612
|
<ChangesTabBody
|
|
550
613
|
git={git}
|
|
614
|
+
comparison={changesComparison}
|
|
615
|
+
onComparisonChange={setChangesComparison}
|
|
551
616
|
captureAvailable={captureAvailable}
|
|
552
617
|
captureRevision={captureState.revision}
|
|
553
618
|
capturePending={capturePending}
|
|
@@ -573,13 +638,12 @@ export function useSandboxWorkspaceTabs(
|
|
|
573
638
|
if (filesEnabled)
|
|
574
639
|
list.push({
|
|
575
640
|
id: WORKBENCH_TAB_FILES,
|
|
576
|
-
label:
|
|
641
|
+
label: <WorkbenchTabLabel icon={<FileCode2Icon />}>Files</WorkbenchTabLabel>,
|
|
577
642
|
content: (
|
|
578
643
|
<SandboxFiles
|
|
579
644
|
key={sessionId}
|
|
580
645
|
files={files}
|
|
581
646
|
git={git}
|
|
582
|
-
stagedGit={stagedGit}
|
|
583
647
|
fileSystemAvailable={fileSystemOn || captureAvailable}
|
|
584
648
|
editable={
|
|
585
649
|
filesEditable && files.source === "live" && files.error === null && !files.loading
|
|
@@ -615,7 +679,7 @@ export function useSandboxWorkspaceTabs(
|
|
|
615
679
|
if (terminalOn) {
|
|
616
680
|
list.push({
|
|
617
681
|
id: WORKBENCH_TAB_TERMINAL,
|
|
618
|
-
label:
|
|
682
|
+
label: <WorkbenchTabLabel icon={<SquareTerminalIcon />}>Terminal</WorkbenchTabLabel>,
|
|
619
683
|
content: (
|
|
620
684
|
<div className="h-full bg-og-bg p-1">
|
|
621
685
|
<SandboxTerminal
|
|
@@ -636,7 +700,7 @@ export function useSandboxWorkspaceTabs(
|
|
|
636
700
|
if (desktopAdvertised) {
|
|
637
701
|
list.push({
|
|
638
702
|
id: WORKBENCH_TAB_DESKTOP,
|
|
639
|
-
label:
|
|
703
|
+
label: <WorkbenchTabLabel icon={<MonitorIcon />}>Desktop</WorkbenchTabLabel>,
|
|
640
704
|
badge: watchDesktop ? (
|
|
641
705
|
<span className="rounded-og-xs bg-og-status-running/20 px-1 text-og-xs text-og-status-running">
|
|
642
706
|
Live
|
|
@@ -674,7 +738,7 @@ export function useSandboxWorkspaceTabs(
|
|
|
674
738
|
sessionId,
|
|
675
739
|
files,
|
|
676
740
|
git,
|
|
677
|
-
|
|
741
|
+
changesComparison,
|
|
678
742
|
terminal,
|
|
679
743
|
xtermTheme,
|
|
680
744
|
capabilities,
|
|
@@ -722,6 +786,8 @@ export type SandboxWorkspaceProps = ClientOverride & {
|
|
|
722
786
|
/** Controlled collapsed state for hosts with their own dock toggle. */
|
|
723
787
|
collapsed?: boolean | undefined;
|
|
724
788
|
onCollapsedChange?: ((collapsed: boolean) => void) | undefined;
|
|
789
|
+
/** Keep the dock's built-in collapse control with controlled collapsed state. */
|
|
790
|
+
showCollapseControl?: boolean | undefined;
|
|
725
791
|
/** Host navigation shown only in the phone workspace overlay header. */
|
|
726
792
|
mobileLeadingControl?: ReactNode | undefined;
|
|
727
793
|
autoSaveId?: string | undefined;
|
|
@@ -735,7 +801,7 @@ export type SandboxWorkspaceProps = ClientOverride & {
|
|
|
735
801
|
* The whole session workspace, ready to mount: `<SandboxWorkspace>` assembles the
|
|
736
802
|
* capability-gated tabs, pins the machine-state chip in the dock header, and
|
|
737
803
|
* renders the resizable `<WorkspaceDock>`. Wrap the tree in `<OpenGeniProvider>`
|
|
738
|
-
* (client + workspaceId) and import `@opengeni/react/
|
|
804
|
+
* (client + workspaceId) and import `@opengeni/react/compiled.css`; that is the
|
|
739
805
|
* entire integration (see `docs/embedding-workbench.md`).
|
|
740
806
|
*/
|
|
741
807
|
export function SandboxWorkspace(props: SandboxWorkspaceProps): ReactNode {
|
|
@@ -750,6 +816,7 @@ export function SandboxWorkspace(props: SandboxWorkspaceProps): ReactNode {
|
|
|
750
816
|
onNotify,
|
|
751
817
|
collapsed,
|
|
752
818
|
onCollapsedChange,
|
|
819
|
+
showCollapseControl,
|
|
753
820
|
mobileLeadingControl,
|
|
754
821
|
autoSaveId,
|
|
755
822
|
defaultSize,
|
|
@@ -768,6 +835,8 @@ export function SandboxWorkspace(props: SandboxWorkspaceProps): ReactNode {
|
|
|
768
835
|
requestId: number;
|
|
769
836
|
} | null>(null);
|
|
770
837
|
const nextFileRequestId = useRef(0);
|
|
838
|
+
const selectedTab = storedSelection?.sessionId === sessionId ? storedSelection.tab : null;
|
|
839
|
+
const activeTabHint = selectedTab ?? initialTab ?? leadingTabs?.[0]?.id ?? null;
|
|
771
840
|
const openFile = useCallback(
|
|
772
841
|
(path: string) => {
|
|
773
842
|
nextFileRequestId.current += 1;
|
|
@@ -788,6 +857,7 @@ export function SandboxWorkspace(props: SandboxWorkspaceProps): ReactNode {
|
|
|
788
857
|
events,
|
|
789
858
|
...(surfaces ? { surfaces } : {}),
|
|
790
859
|
...(initialTab ? { initialTab } : {}),
|
|
860
|
+
activeTab: activeTabHint,
|
|
791
861
|
...(onNotify ? { onNotify } : {}),
|
|
792
862
|
requestedFilePath: requestedFile?.sessionId === sessionId ? requestedFile.path : null,
|
|
793
863
|
requestedFileRequestId: requestedFile?.sessionId === sessionId ? requestedFile.requestId : null,
|
|
@@ -800,7 +870,6 @@ export function SandboxWorkspace(props: SandboxWorkspaceProps): ReactNode {
|
|
|
800
870
|
// (Changes) — whose body is a connecting/loading state until the capture lands,
|
|
801
871
|
// so committing the real default at first-resolve produces no CONTENT switch.
|
|
802
872
|
const tabs: WorkspaceTab[] = [...(leadingTabs ?? []), ...workbenchTabs, ...(trailingTabs ?? [])];
|
|
803
|
-
const selectedTab = storedSelection?.sessionId === sessionId ? storedSelection.tab : null;
|
|
804
873
|
const preferredTab = selectedTab ?? defaultTab;
|
|
805
874
|
const activeTab =
|
|
806
875
|
preferredTab && tabs.some((tab) => tab.id === preferredTab) ? preferredTab : tabs[0]?.id;
|
|
@@ -817,19 +886,13 @@ export function SandboxWorkspace(props: SandboxWorkspaceProps): ReactNode {
|
|
|
817
886
|
onActiveTabChange={selectTab}
|
|
818
887
|
{...(machine.enabled
|
|
819
888
|
? {
|
|
820
|
-
headerAccessory:
|
|
821
|
-
<MachineStateChip
|
|
822
|
-
chip={machine.chip}
|
|
823
|
-
activeMachine={machine.activeMachine}
|
|
824
|
-
error={machine.error}
|
|
825
|
-
onRetry={() => void machine.refresh()}
|
|
826
|
-
/>
|
|
827
|
-
),
|
|
889
|
+
headerAccessory: <MachineStateChip chip={machine.chip} />,
|
|
828
890
|
}
|
|
829
891
|
: {})}
|
|
830
892
|
{...(mobileLeadingControl !== undefined ? { mobileLeadingControl } : {})}
|
|
831
893
|
{...(collapsed !== undefined ? { collapsed } : {})}
|
|
832
894
|
{...(onCollapsedChange ? { onCollapsedChange } : {})}
|
|
895
|
+
{...(showCollapseControl !== undefined ? { showCollapseControl } : {})}
|
|
833
896
|
{...(autoSaveId !== undefined ? { autoSaveId } : {})}
|
|
834
897
|
{...(defaultSize !== undefined ? { defaultSize } : {})}
|
|
835
898
|
{...(minSize !== undefined ? { minSize } : {})}
|
|
@@ -850,18 +913,6 @@ function DirtyBadge({ count }: { count: number }) {
|
|
|
850
913
|
);
|
|
851
914
|
}
|
|
852
915
|
|
|
853
|
-
/** A machine-kind glyph for the chip popover. */
|
|
854
|
-
function MachineKindIcon({
|
|
855
|
-
kind,
|
|
856
|
-
className,
|
|
857
|
-
}: {
|
|
858
|
-
kind: MachineView["kind"] | undefined;
|
|
859
|
-
className?: string;
|
|
860
|
-
}) {
|
|
861
|
-
const Icon = kind === "selfhosted" ? LaptopIcon : CpuIcon;
|
|
862
|
-
return <Icon className={cn("size-3.5 shrink-0 text-og-fg-subtle", className)} aria-hidden />;
|
|
863
|
-
}
|
|
864
|
-
|
|
865
916
|
function chipDotClass(state: MachineChip["state"]): string {
|
|
866
917
|
if (state === "live") return "bg-og-status-running";
|
|
867
918
|
if (state === "waking") return "bg-og-status-idle animate-pulse motion-reduce:animate-none";
|
|
@@ -869,93 +920,23 @@ function chipDotClass(state: MachineChip["state"]): string {
|
|
|
869
920
|
}
|
|
870
921
|
|
|
871
922
|
/**
|
|
872
|
-
* The dock-header machine
|
|
873
|
-
*
|
|
874
|
-
*
|
|
875
|
-
* fleet failed to resolve (the old per-surface machine bar + Sandbox info tab,
|
|
876
|
-
* folded into one header affordance — recommendation).
|
|
923
|
+
* The dock-header machine status: one quiet, truthful live/waking/offline
|
|
924
|
+
* indicator. It is intentionally not interactive; detailed machine controls do
|
|
925
|
+
* not belong in a transient popover above the workspace tabs.
|
|
877
926
|
*/
|
|
878
|
-
function MachineStateChip({
|
|
879
|
-
chip,
|
|
880
|
-
activeMachine,
|
|
881
|
-
error,
|
|
882
|
-
onRetry,
|
|
883
|
-
}: {
|
|
884
|
-
chip: MachineChip;
|
|
885
|
-
activeMachine: MachineView | null;
|
|
886
|
-
error: Error | null;
|
|
887
|
-
onRetry: () => void;
|
|
888
|
-
}) {
|
|
889
|
-
const triggerRef = useRef<HTMLButtonElement | null>(null);
|
|
890
|
-
const portalStyle = usePortalTokenStyle(triggerRef);
|
|
927
|
+
function MachineStateChip({ chip }: { chip: MachineChip }) {
|
|
891
928
|
return (
|
|
892
|
-
<
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
/>
|
|
904
|
-
<span className="max-w-[11rem] truncate">{chip.label}</span>
|
|
905
|
-
</button>
|
|
906
|
-
</Popover.Trigger>
|
|
907
|
-
<Popover.Portal forceMount>
|
|
908
|
-
<Popover.Content
|
|
909
|
-
forceMount
|
|
910
|
-
data-machine-state-popover
|
|
911
|
-
align="end"
|
|
912
|
-
sideOffset={6}
|
|
913
|
-
collisionPadding={8}
|
|
914
|
-
className="og-root z-50 w-64 max-w-[calc(100vw-1rem)] rounded-og-md border border-og-border bg-og-surface-1 p-3 text-og-sm text-og-fg shadow-lg outline-none"
|
|
915
|
-
style={portalStyle}
|
|
916
|
-
>
|
|
917
|
-
<div className="flex min-w-0 items-center gap-1.5">
|
|
918
|
-
<MachineKindIcon kind={activeMachine?.kind} />
|
|
919
|
-
<span className="min-w-0 truncate font-medium">{activeMachine?.name ?? "Sandbox"}</span>
|
|
920
|
-
</div>
|
|
921
|
-
<div className="mt-2.5 flex items-center justify-between gap-2">
|
|
922
|
-
<span className="text-og-xs text-og-fg-subtle">Connection</span>
|
|
923
|
-
{activeMachine ? (
|
|
924
|
-
<ConnectionStatusPill
|
|
925
|
-
status={connectionStatusForState(activeMachine.state)}
|
|
926
|
-
size="sm"
|
|
927
|
-
/>
|
|
928
|
-
) : (
|
|
929
|
-
<span className="text-og-xs text-og-fg-muted">{chip.label}</span>
|
|
930
|
-
)}
|
|
931
|
-
</div>
|
|
932
|
-
{chip.asOf ? (
|
|
933
|
-
<p className="mt-2.5 text-og-xs leading-4 text-og-fg-subtle">
|
|
934
|
-
Workspace shown as of {formatAsOf(chip.asOf, Date.now())} — the machine is not live.
|
|
935
|
-
</p>
|
|
936
|
-
) : null}
|
|
937
|
-
{activeMachine && activeMachine.sharedSessionCount > 1 ? (
|
|
938
|
-
<div className="mt-2.5">
|
|
939
|
-
<SharedMachineDisclosure
|
|
940
|
-
sharedSessionCount={activeMachine.sharedSessionCount}
|
|
941
|
-
density="full"
|
|
942
|
-
/>
|
|
943
|
-
</div>
|
|
944
|
-
) : null}
|
|
945
|
-
{error ? (
|
|
946
|
-
<div className="mt-2.5 space-y-1.5 border-t border-og-border pt-2.5">
|
|
947
|
-
<p className="text-og-xs leading-4 text-og-danger">
|
|
948
|
-
Couldn't reach the sandbox for this session.
|
|
949
|
-
</p>
|
|
950
|
-
<DockActionButton onClick={onRetry}>
|
|
951
|
-
<RefreshCwIcon className="size-3" />
|
|
952
|
-
Retry
|
|
953
|
-
</DockActionButton>
|
|
954
|
-
</div>
|
|
955
|
-
) : null}
|
|
956
|
-
</Popover.Content>
|
|
957
|
-
</Popover.Portal>
|
|
958
|
-
</Popover.Root>
|
|
929
|
+
<div
|
|
930
|
+
role="status"
|
|
931
|
+
aria-label={`Machine: ${chip.label}`}
|
|
932
|
+
className="inline-flex min-h-7 items-center gap-1.5 px-2 py-1 text-og-xs font-medium text-og-fg-muted max-[1023px]:min-h-11 pointer-coarse:min-h-11"
|
|
933
|
+
>
|
|
934
|
+
<span
|
|
935
|
+
className={cn("size-1.5 shrink-0 rounded-full", chipDotClass(chip.state))}
|
|
936
|
+
aria-hidden
|
|
937
|
+
/>
|
|
938
|
+
<span className="max-w-[11rem] truncate">{chip.label}</span>
|
|
939
|
+
</div>
|
|
959
940
|
);
|
|
960
941
|
}
|
|
961
942
|
|
|
@@ -965,7 +946,7 @@ function DockActionButton({ onClick, children }: { onClick: () => void; children
|
|
|
965
946
|
<button
|
|
966
947
|
type="button"
|
|
967
948
|
onClick={onClick}
|
|
968
|
-
className="inline-flex items-center gap-1.5 rounded-og-sm border border-og-border px-2 py-1 text-og-xs font-medium text-og-fg-muted transition-colors hover:border-og-border-strong hover:text-og-fg focus-visible:outline-
|
|
949
|
+
className="inline-flex items-center gap-1.5 rounded-og-sm border border-og-border px-2 py-1 text-og-xs font-medium text-og-fg-muted transition-colors hover:border-og-border-strong hover:text-og-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 pointer-coarse:min-h-11"
|
|
969
950
|
>
|
|
970
951
|
{children}
|
|
971
952
|
</button>
|
|
@@ -979,7 +960,49 @@ function DockActionButton({ onClick, children }: { onClick: () => void; children
|
|
|
979
960
|
* The dock frame is untouched; this is the M5 seam.
|
|
980
961
|
*/
|
|
981
962
|
function ChangesTabBody({
|
|
963
|
+
comparison,
|
|
964
|
+
onComparisonChange,
|
|
965
|
+
...props
|
|
966
|
+
}: {
|
|
967
|
+
comparison: SandboxGitComparison;
|
|
968
|
+
onComparisonChange: (comparison: SandboxGitComparison) => void;
|
|
969
|
+
} & Parameters<typeof ChangesTabContent>[0]) {
|
|
970
|
+
return (
|
|
971
|
+
<div className="flex h-full min-h-0 flex-col">
|
|
972
|
+
<div className="flex shrink-0 items-center gap-1 border-b border-og-border bg-og-surface-1 px-2 py-1.5">
|
|
973
|
+
{(
|
|
974
|
+
[
|
|
975
|
+
["branch", "Branch"],
|
|
976
|
+
["working", "Uncommitted"],
|
|
977
|
+
["staged", "Staged"],
|
|
978
|
+
] as const
|
|
979
|
+
).map(([value, label]) => (
|
|
980
|
+
<button
|
|
981
|
+
key={value}
|
|
982
|
+
type="button"
|
|
983
|
+
aria-pressed={comparison === value}
|
|
984
|
+
onClick={() => onComparisonChange(value)}
|
|
985
|
+
className={cn(
|
|
986
|
+
"rounded-og-sm px-2 py-1 text-og-xs font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 pointer-coarse:min-h-11",
|
|
987
|
+
comparison === value
|
|
988
|
+
? "bg-og-surface-2 text-og-fg shadow-sm"
|
|
989
|
+
: "text-og-fg-muted hover:bg-og-surface-2 hover:text-og-fg",
|
|
990
|
+
)}
|
|
991
|
+
>
|
|
992
|
+
{label}
|
|
993
|
+
</button>
|
|
994
|
+
))}
|
|
995
|
+
</div>
|
|
996
|
+
<div className="min-h-0 flex-1">
|
|
997
|
+
<ChangesTabContent comparison={comparison} {...props} />
|
|
998
|
+
</div>
|
|
999
|
+
</div>
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
function ChangesTabContent({
|
|
982
1004
|
git,
|
|
1005
|
+
comparison,
|
|
983
1006
|
captureAvailable,
|
|
984
1007
|
captureRevision,
|
|
985
1008
|
capturePending,
|
|
@@ -992,6 +1015,7 @@ function ChangesTabBody({
|
|
|
992
1015
|
onOpenFile,
|
|
993
1016
|
}: {
|
|
994
1017
|
git: UseSandboxGitResult;
|
|
1018
|
+
comparison: SandboxGitComparison;
|
|
995
1019
|
captureAvailable: boolean;
|
|
996
1020
|
captureRevision: number | null;
|
|
997
1021
|
capturePending: boolean;
|
|
@@ -1025,7 +1049,7 @@ function ChangesTabBody({
|
|
|
1025
1049
|
type="button"
|
|
1026
1050
|
onClick={() => void git.refresh()}
|
|
1027
1051
|
disabled={git.loading}
|
|
1028
|
-
className="inline-flex min-h-7 shrink-0 items-center gap-1 rounded-og-sm border border-og-border bg-og-surface-1 px-2 font-medium text-og-fg transition-colors hover:border-og-border-strong focus-visible:outline-
|
|
1052
|
+
className="inline-flex min-h-7 shrink-0 items-center gap-1 rounded-og-sm border border-og-border bg-og-surface-1 px-2 font-medium text-og-fg transition-colors hover:border-og-border-strong focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:min-h-11"
|
|
1029
1053
|
>
|
|
1030
1054
|
<RefreshCwIcon
|
|
1031
1055
|
className={cn("size-3", git.loading && "animate-spin motion-reduce:animate-none")}
|
|
@@ -1085,7 +1109,7 @@ function ChangesTabBody({
|
|
|
1085
1109
|
);
|
|
1086
1110
|
}
|
|
1087
1111
|
|
|
1088
|
-
if (!liveWorkspaceExpected && !captureAvailable) {
|
|
1112
|
+
if (!liveWorkspaceExpected && (comparison !== "working" || !captureAvailable)) {
|
|
1089
1113
|
return (
|
|
1090
1114
|
<CenteredState
|
|
1091
1115
|
icon={
|
|
@@ -1105,7 +1129,11 @@ function ChangesTabBody({
|
|
|
1105
1129
|
<p className="text-og-sm leading-5 text-og-fg-subtle">
|
|
1106
1130
|
{workspaceWaking
|
|
1107
1131
|
? "Connecting to the live working tree…"
|
|
1108
|
-
:
|
|
1132
|
+
: comparison === "branch"
|
|
1133
|
+
? "Wake the sandbox to compare this branch with the remote default branch."
|
|
1134
|
+
: comparison === "staged"
|
|
1135
|
+
? "Wake the sandbox to inspect staged changes."
|
|
1136
|
+
: "No captured revision is available yet. Wake the sandbox to inspect uncommitted changes."}
|
|
1109
1137
|
</p>
|
|
1110
1138
|
{!workspaceWaking ? (
|
|
1111
1139
|
<DockActionButton onClick={onWake}>
|
|
@@ -1135,9 +1163,19 @@ function ChangesTabBody({
|
|
|
1135
1163
|
|
|
1136
1164
|
return (
|
|
1137
1165
|
<CenteredState icon={<CircleCheckIcon className="size-5" aria-hidden />} tone="success">
|
|
1138
|
-
<p className="text-og-sm font-medium text-og-fg">
|
|
1166
|
+
<p className="text-og-sm font-medium text-og-fg">
|
|
1167
|
+
{comparison === "branch"
|
|
1168
|
+
? "No branch changes"
|
|
1169
|
+
: comparison === "staged"
|
|
1170
|
+
? "No staged changes"
|
|
1171
|
+
: "No uncommitted changes"}
|
|
1172
|
+
</p>
|
|
1139
1173
|
<p className="text-og-sm leading-5 text-og-fg-subtle">
|
|
1140
|
-
|
|
1174
|
+
{comparison === "branch"
|
|
1175
|
+
? "This branch matches the remote default branch."
|
|
1176
|
+
: comparison === "staged"
|
|
1177
|
+
? "Stage files to review the next commit here."
|
|
1178
|
+
: "Local edits not yet committed will appear here."}
|
|
1141
1179
|
</p>
|
|
1142
1180
|
</CenteredState>
|
|
1143
1181
|
);
|
|
@@ -560,18 +560,18 @@ export function SessionChrome({
|
|
|
560
560
|
"transition-[background-color,border-color,box-shadow] motion-reduce:transition-none",
|
|
561
561
|
)}
|
|
562
562
|
style={{
|
|
563
|
-
borderRadius: "var(--
|
|
563
|
+
borderRadius: "var(--_og-session-chrome-radius)",
|
|
564
564
|
background: open
|
|
565
|
-
? "var(--
|
|
566
|
-
: "var(--
|
|
565
|
+
? "var(--_og-session-chrome-surface-open)"
|
|
566
|
+
: "var(--_og-session-chrome-surface)",
|
|
567
567
|
borderColor: open
|
|
568
|
-
? "var(--
|
|
569
|
-
: "var(--
|
|
568
|
+
? "var(--_og-session-chrome-border-open)"
|
|
569
|
+
: "var(--_og-session-chrome-border)",
|
|
570
570
|
boxShadow: open
|
|
571
571
|
? "var(--og-session-chrome-shadow-open)"
|
|
572
572
|
: "var(--og-session-chrome-shadow)",
|
|
573
573
|
transitionDuration: "var(--og-session-chrome-duration)",
|
|
574
|
-
transitionTimingFunction: "var(--
|
|
574
|
+
transitionTimingFunction: "var(--_og-session-chrome-ease)",
|
|
575
575
|
}}
|
|
576
576
|
>
|
|
577
577
|
<div
|
|
@@ -594,8 +594,8 @@ export function SessionChrome({
|
|
|
594
594
|
aria-hidden
|
|
595
595
|
className="pointer-events-none absolute left-0 top-0 rounded-og-md"
|
|
596
596
|
style={{
|
|
597
|
-
background: "var(--
|
|
598
|
-
boxShadow: "inset 0 0 0 1px var(--
|
|
597
|
+
background: "var(--_og-session-chrome-highlight)",
|
|
598
|
+
boxShadow: "inset 0 0 0 1px var(--_og-session-chrome-highlight-ring)",
|
|
599
599
|
}}
|
|
600
600
|
initial={false}
|
|
601
601
|
animate={{
|
|
@@ -623,7 +623,7 @@ export function SessionChrome({
|
|
|
623
623
|
data-og-session-chrome-signal={signal.id}
|
|
624
624
|
onClick={() => setActive(selected ? null : signal.id)}
|
|
625
625
|
className={cn(
|
|
626
|
-
"group relative z-[1] inline-flex min-h-[var(--og-session-chrome-chip-min-height)] max-w-full items-center gap-1 rounded-og-md py-1 text-left text-og-xs outline-
|
|
626
|
+
"group relative z-[1] inline-flex min-h-[var(--og-session-chrome-chip-min-height)] max-w-full items-center gap-1 rounded-og-md py-1 text-left text-og-xs outline-hidden",
|
|
627
627
|
// Coarse pointers keep a 44px target (session-pins acceptance).
|
|
628
628
|
"pointer-coarse:min-h-11",
|
|
629
629
|
"transition-colors duration-150 motion-reduce:transition-none",
|
|
@@ -731,7 +731,7 @@ function IncomingPanel({
|
|
|
731
731
|
{inputs.map((input) => (
|
|
732
732
|
<li
|
|
733
733
|
key={input.id}
|
|
734
|
-
className="group flex items-start gap-1.5 rounded-og-sm px-1.5 py-1 transition-colors hover:bg-[var(--
|
|
734
|
+
className="group flex items-start gap-1.5 rounded-og-sm px-1.5 py-1 transition-colors hover:bg-[var(--_og-session-chrome-row-hover)]"
|
|
735
735
|
>
|
|
736
736
|
<span
|
|
737
737
|
className={cn(
|
|
@@ -830,7 +830,7 @@ function QueuePanel({
|
|
|
830
830
|
<li
|
|
831
831
|
key={turn.id}
|
|
832
832
|
data-queue-turn-id={turn.id}
|
|
833
|
-
className="group flex flex-col gap-1 rounded-og-sm px-1.5 py-1 transition-colors hover:bg-[var(--
|
|
833
|
+
className="group flex flex-col gap-1 rounded-og-sm px-1.5 py-1 transition-colors hover:bg-[var(--_og-session-chrome-row-hover)]"
|
|
834
834
|
>
|
|
835
835
|
<div className="flex items-start gap-1.5">
|
|
836
836
|
{voice ? (
|
|
@@ -1003,7 +1003,7 @@ function GoalPanel({
|
|
|
1003
1003
|
? goal.resume()
|
|
1004
1004
|
: goal.pause("Paused from session chrome"))
|
|
1005
1005
|
}
|
|
1006
|
-
className="inline-flex h-6 items-center gap-1 rounded-og-sm px-1.5 text-og-xs font-medium text-og-fg-muted outline-
|
|
1006
|
+
className="inline-flex h-6 items-center gap-1 rounded-og-sm px-1.5 text-og-xs font-medium text-og-fg-muted outline-hidden transition-colors hover:bg-og-surface-3/70 hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent/40 disabled:opacity-50"
|
|
1007
1007
|
>
|
|
1008
1008
|
{goal.updating ? (
|
|
1009
1009
|
<Loader2Icon className="size-3 animate-og-spin" />
|
|
@@ -1019,7 +1019,7 @@ function GoalPanel({
|
|
|
1019
1019
|
type="button"
|
|
1020
1020
|
disabled={goal.updating}
|
|
1021
1021
|
onClick={() => void goal.deleteGoal()}
|
|
1022
|
-
className="inline-flex h-6 items-center gap-1 rounded-og-sm px-1.5 text-og-xs font-medium text-og-fg-subtle outline-
|
|
1022
|
+
className="inline-flex h-6 items-center gap-1 rounded-og-sm px-1.5 text-og-xs font-medium text-og-fg-subtle outline-hidden transition-colors hover:bg-og-surface-3/70 hover:text-og-danger focus-visible:ring-2 focus-visible:ring-og-accent/40 disabled:opacity-50"
|
|
1023
1023
|
>
|
|
1024
1024
|
<Trash2Icon className="size-3" />
|
|
1025
1025
|
Clear
|
|
@@ -1064,7 +1064,7 @@ function IconAction({
|
|
|
1064
1064
|
disabled={disabled}
|
|
1065
1065
|
onClick={onClick}
|
|
1066
1066
|
className={cn(
|
|
1067
|
-
"inline-flex size-6 items-center justify-center rounded-og-sm text-og-fg-subtle outline-
|
|
1067
|
+
"inline-flex size-6 items-center justify-center rounded-og-sm text-og-fg-subtle outline-hidden transition-colors",
|
|
1068
1068
|
"hover:bg-og-surface-2 hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent/40",
|
|
1069
1069
|
"disabled:pointer-events-none disabled:opacity-40 pointer-coarse:size-9",
|
|
1070
1070
|
danger && "hover:text-og-danger",
|