@agent-native/core 0.153.0 → 0.153.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/corpus/templates/calendar/app/components/calendar/DayView.tsx +3 -2
- package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +3 -2
- package/corpus/templates/calendar/app/lib/event-layout.ts +16 -35
- package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +27 -44
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +72 -33
- package/corpus/templates/clips/app/components/sharing/share-ui.tsx +18 -6
- package/corpus/templates/clips/desktop/src/app.tsx +1 -1
- package/corpus/templates/clips/desktop/src/styles.css +10 -2
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +2 -2
- package/corpus/templates/clips/desktop/src-tauri/src/util.rs +1 -1
- package/corpus/templates/factory/app/routes/factory.tsx +0 -3
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/ShareDialog.tsx +28 -25
- package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +50 -0
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +12 -60
- package/dist/agent/production-agent.d.ts +8 -0
- package/dist/agent/production-agent.js +25 -2
- package/dist/agent/run-manager.js +13 -3
- package/dist/client/AgentPanel.js +6 -4
- package/dist/client/org/WorkspaceNotice.js +7 -4
- package/dist/client/sharing/ShareButton.d.ts +2 -2
- package/dist/client/sharing/ShareButton.js +18 -13
- package/dist/client/sharing/ShareDialog.d.ts +1 -1
- package/dist/client/sharing/ShareDialog.js +13 -10
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.js +18 -4
- package/dist/server/better-auth-instance.js +8 -1
- package/dist/server/magic-link-attribution.d.ts +21 -0
- package/dist/server/magic-link-attribution.js +115 -0
- package/dist/server/realtime-token.d.ts +1 -1
- package/package.json +1 -1
|
@@ -36,6 +36,8 @@ import {
|
|
|
36
36
|
IconStackBack,
|
|
37
37
|
IconStackFront,
|
|
38
38
|
IconUnderline,
|
|
39
|
+
IconZoomIn,
|
|
40
|
+
IconZoomOut,
|
|
39
41
|
} from "@tabler/icons-react";
|
|
40
42
|
import type { ReactNode } from "react";
|
|
41
43
|
|
|
@@ -150,6 +152,7 @@ export function SlideContextToolbar({
|
|
|
150
152
|
objectSelectionCount = 0,
|
|
151
153
|
onAlignObjects,
|
|
152
154
|
onDistributeObjects,
|
|
155
|
+
zoomControls,
|
|
153
156
|
}: {
|
|
154
157
|
snapshot: SlideStyleSnapshot | null;
|
|
155
158
|
background: string | undefined;
|
|
@@ -164,6 +167,13 @@ export function SlideContextToolbar({
|
|
|
164
167
|
objectSelectionCount?: number;
|
|
165
168
|
onAlignObjects?: (alignment: SlideObjectAlignment) => void;
|
|
166
169
|
onDistributeObjects?: (distribution: SlideObjectDistribution) => void;
|
|
170
|
+
zoomControls?: {
|
|
171
|
+
value: number;
|
|
172
|
+
onZoomOut: () => void;
|
|
173
|
+
onZoomIn: () => void;
|
|
174
|
+
canZoomOut: boolean;
|
|
175
|
+
canZoomIn: boolean;
|
|
176
|
+
};
|
|
167
177
|
}) {
|
|
168
178
|
const t = useT();
|
|
169
179
|
const documentColors = tokenPalette(designSystem, t).map(
|
|
@@ -914,6 +924,46 @@ export function SlideContextToolbar({
|
|
|
914
924
|
</Popover>
|
|
915
925
|
</>
|
|
916
926
|
)}
|
|
927
|
+
{zoomControls && (
|
|
928
|
+
<>
|
|
929
|
+
<div className={TOOLBAR_DIVIDER} />
|
|
930
|
+
<Tooltip>
|
|
931
|
+
<TooltipTrigger asChild>
|
|
932
|
+
<Button
|
|
933
|
+
type="button"
|
|
934
|
+
variant="ghost"
|
|
935
|
+
size="icon"
|
|
936
|
+
className={MENU_BUTTON_CLASS}
|
|
937
|
+
onClick={zoomControls.onZoomOut}
|
|
938
|
+
disabled={!zoomControls.canZoomOut}
|
|
939
|
+
aria-label={t("raw.zoomOut")}
|
|
940
|
+
>
|
|
941
|
+
<IconZoomOut className="size-3.5" />
|
|
942
|
+
</Button>
|
|
943
|
+
</TooltipTrigger>
|
|
944
|
+
<TooltipContent>{t("raw.zoomOut")}</TooltipContent>
|
|
945
|
+
</Tooltip>
|
|
946
|
+
<span className="w-11 shrink-0 text-center text-xs tabular-nums text-muted-foreground">
|
|
947
|
+
{zoomControls.value}%
|
|
948
|
+
</span>
|
|
949
|
+
<Tooltip>
|
|
950
|
+
<TooltipTrigger asChild>
|
|
951
|
+
<Button
|
|
952
|
+
type="button"
|
|
953
|
+
variant="ghost"
|
|
954
|
+
size="icon"
|
|
955
|
+
className={MENU_BUTTON_CLASS}
|
|
956
|
+
onClick={zoomControls.onZoomIn}
|
|
957
|
+
disabled={!zoomControls.canZoomIn}
|
|
958
|
+
aria-label={t("raw.zoomIn")}
|
|
959
|
+
>
|
|
960
|
+
<IconZoomIn className="size-3.5" />
|
|
961
|
+
</Button>
|
|
962
|
+
</TooltipTrigger>
|
|
963
|
+
<TooltipContent>{t("raw.zoomIn")}</TooltipContent>
|
|
964
|
+
</Tooltip>
|
|
965
|
+
</>
|
|
966
|
+
)}
|
|
917
967
|
</div>
|
|
918
968
|
);
|
|
919
969
|
}
|
|
@@ -21,13 +21,10 @@ import {
|
|
|
21
21
|
IconBrush,
|
|
22
22
|
IconClipboard,
|
|
23
23
|
IconCopy,
|
|
24
|
-
IconMaximize,
|
|
25
24
|
IconStackBack,
|
|
26
25
|
IconStackFront,
|
|
27
26
|
IconTrash,
|
|
28
27
|
IconX,
|
|
29
|
-
IconZoomIn,
|
|
30
|
-
IconZoomOut,
|
|
31
28
|
} from "@tabler/icons-react";
|
|
32
29
|
import {
|
|
33
30
|
useState,
|
|
@@ -1252,10 +1249,6 @@ export default function SlideEditor({
|
|
|
1252
1249
|
.find((preset) => preset < canvasZoom);
|
|
1253
1250
|
setManualCanvasZoom(previous ?? CANVAS_ZOOM_PRESETS[0]);
|
|
1254
1251
|
}, [canvasZoom, setManualCanvasZoom]);
|
|
1255
|
-
const fitCanvasToScreen = useCallback(() => {
|
|
1256
|
-
userSetCanvasZoomRef.current = false;
|
|
1257
|
-
setCanvasZoom(fitCanvasZoom);
|
|
1258
|
-
}, [fitCanvasZoom]);
|
|
1259
1252
|
|
|
1260
1253
|
usePinchZoom({
|
|
1261
1254
|
containerRef: scrollContainerRef,
|
|
@@ -5010,6 +5003,16 @@ export default function SlideEditor({
|
|
|
5010
5003
|
const objectOperationSelection = getObjectOperationSelection();
|
|
5011
5004
|
const hasObjectSelection = objectOperationSelection !== null;
|
|
5012
5005
|
const objectSelectionCount = objectOperationSelection?.elements.length ?? 0;
|
|
5006
|
+
const zoomControls = slide.excalidrawData
|
|
5007
|
+
? undefined
|
|
5008
|
+
: {
|
|
5009
|
+
value: canvasZoom,
|
|
5010
|
+
onZoomOut: canvasZoomOut,
|
|
5011
|
+
onZoomIn: canvasZoomIn,
|
|
5012
|
+
canZoomOut: canvasZoom > MIN_CANVAS_ZOOM,
|
|
5013
|
+
canZoomIn:
|
|
5014
|
+
canvasZoom < CANVAS_ZOOM_PRESETS[CANVAS_ZOOM_PRESETS.length - 1],
|
|
5015
|
+
};
|
|
5013
5016
|
|
|
5014
5017
|
// Excalidraw slides have no selectable slide content, so the row collapses
|
|
5015
5018
|
// to its slide-level state — but that state owns the background picker, and
|
|
@@ -5038,6 +5041,7 @@ export default function SlideEditor({
|
|
|
5038
5041
|
objectSelectionCount={objectSelectionCount}
|
|
5039
5042
|
onAlignObjects={handleAlignSelectedObjects}
|
|
5040
5043
|
onDistributeObjects={handleDistributeSelectedObjects}
|
|
5044
|
+
zoomControls={zoomControls}
|
|
5041
5045
|
/>
|
|
5042
5046
|
</div>
|
|
5043
5047
|
) : null;
|
|
@@ -5061,6 +5065,7 @@ export default function SlideEditor({
|
|
|
5061
5065
|
objectSelectionCount={objectSelectionCount}
|
|
5062
5066
|
onAlignObjects={handleAlignSelectedObjects}
|
|
5063
5067
|
onDistributeObjects={handleDistributeSelectedObjects}
|
|
5068
|
+
zoomControls={zoomControls}
|
|
5064
5069
|
className="slide-context-toolbar--top-row"
|
|
5065
5070
|
/>
|
|
5066
5071
|
</div>
|
|
@@ -5102,59 +5107,6 @@ export default function SlideEditor({
|
|
|
5102
5107
|
</div>
|
|
5103
5108
|
) : (
|
|
5104
5109
|
<div className="relative h-full bg-[var(--slides-editor-surface)]">
|
|
5105
|
-
<div className="absolute right-3 top-3 z-20 flex h-8 items-center gap-0.5 rounded-md bg-popover/95 px-1">
|
|
5106
|
-
<Tooltip>
|
|
5107
|
-
<TooltipTrigger asChild>
|
|
5108
|
-
<Button
|
|
5109
|
-
variant="ghost"
|
|
5110
|
-
size="icon"
|
|
5111
|
-
className="h-6 w-6 cursor-pointer"
|
|
5112
|
-
onClick={canvasZoomOut}
|
|
5113
|
-
disabled={canvasZoom <= MIN_CANVAS_ZOOM}
|
|
5114
|
-
aria-label={t("raw.zoomOut")}
|
|
5115
|
-
>
|
|
5116
|
-
<IconZoomOut className="h-3.5 w-3.5" />
|
|
5117
|
-
</Button>
|
|
5118
|
-
</TooltipTrigger>
|
|
5119
|
-
<TooltipContent>{t("raw.zoomOut")}</TooltipContent>
|
|
5120
|
-
</Tooltip>
|
|
5121
|
-
<span className="w-11 text-center text-xs tabular-nums text-muted-foreground">
|
|
5122
|
-
{canvasZoom}%
|
|
5123
|
-
</span>
|
|
5124
|
-
<Tooltip>
|
|
5125
|
-
<TooltipTrigger asChild>
|
|
5126
|
-
<Button
|
|
5127
|
-
variant="ghost"
|
|
5128
|
-
size="icon"
|
|
5129
|
-
className="h-6 w-6 cursor-pointer"
|
|
5130
|
-
onClick={canvasZoomIn}
|
|
5131
|
-
disabled={
|
|
5132
|
-
canvasZoom >=
|
|
5133
|
-
CANVAS_ZOOM_PRESETS[CANVAS_ZOOM_PRESETS.length - 1]
|
|
5134
|
-
}
|
|
5135
|
-
aria-label={t("raw.zoomIn")}
|
|
5136
|
-
>
|
|
5137
|
-
<IconZoomIn className="h-3.5 w-3.5" />
|
|
5138
|
-
</Button>
|
|
5139
|
-
</TooltipTrigger>
|
|
5140
|
-
<TooltipContent>{t("raw.zoomIn")}</TooltipContent>
|
|
5141
|
-
</Tooltip>
|
|
5142
|
-
<div className="mx-0.5 h-4 w-px bg-border" />
|
|
5143
|
-
<Tooltip>
|
|
5144
|
-
<TooltipTrigger asChild>
|
|
5145
|
-
<Button
|
|
5146
|
-
variant="ghost"
|
|
5147
|
-
size="icon"
|
|
5148
|
-
className="h-6 w-6 cursor-pointer"
|
|
5149
|
-
onClick={fitCanvasToScreen}
|
|
5150
|
-
aria-label={t("raw.fitSlideToScreen")}
|
|
5151
|
-
>
|
|
5152
|
-
<IconMaximize className="h-3.5 w-3.5" />
|
|
5153
|
-
</Button>
|
|
5154
|
-
</TooltipTrigger>
|
|
5155
|
-
<TooltipContent>{t("raw.fitToScreen")}</TooltipContent>
|
|
5156
|
-
</Tooltip>
|
|
5157
|
-
</div>
|
|
5158
5110
|
<div
|
|
5159
5111
|
ref={scrollContainerRef}
|
|
5160
5112
|
className={`h-full overflow-auto ${
|
|
@@ -373,6 +373,14 @@ export interface ProductionAgentOptions {
|
|
|
373
373
|
};
|
|
374
374
|
}
|
|
375
375
|
export declare function resolveAgentOwnerEmail(options: Pick<ProductionAgentOptions, "resolveOwnerEmail">, event: any): Promise<string | null>;
|
|
376
|
+
/**
|
|
377
|
+
* A transient database failure in the completion callback used to prevent a
|
|
378
|
+
* background continuation from ever being handed off. Keep the retry bounded
|
|
379
|
+
* and database-only so a permanent persistence error still fails loudly.
|
|
380
|
+
*/
|
|
381
|
+
export declare function runCompletionCallbackWithDatabaseRetry(callback: () => void | Promise<void>, options?: {
|
|
382
|
+
sleep?: (ms: number) => Promise<void>;
|
|
383
|
+
}): Promise<void>;
|
|
376
384
|
declare function generateRunId(): string;
|
|
377
385
|
/** Check if an error is transient and should be retried
|
|
378
386
|
* @internal exported for unit tests only
|
|
@@ -5,7 +5,7 @@ import { parseA2AAgentActivityPart } from "../a2a/activity.js";
|
|
|
5
5
|
import { describeToolParameterSignature, isAgentActionStopError, } from "../action.js";
|
|
6
6
|
import { readAppState } from "../application-state/script-helpers.js";
|
|
7
7
|
import { isReadOnlyShellCommand } from "../coding-tools/index.js";
|
|
8
|
-
import { getDbExec } from "../db/client.js";
|
|
8
|
+
import { getDbExec, isTransientDatabaseError } from "../db/client.js";
|
|
9
9
|
import { extensionIdFromPathname } from "../extensions/path.js";
|
|
10
10
|
import { preUploadAttachments } from "../file-upload/pre-upload-attachments.js";
|
|
11
11
|
import { isMcpActionResult } from "../mcp-client/app-result.js";
|
|
@@ -620,6 +620,29 @@ export async function resolveAgentOwnerEmail(options, event) {
|
|
|
620
620
|
return ownerEmail ?? getRequestUserEmail() ?? null;
|
|
621
621
|
}
|
|
622
622
|
const MAX_RETRIES = 3;
|
|
623
|
+
const COMPLETION_DATABASE_RETRY_DELAYS_MS = [250, 750, 1_500];
|
|
624
|
+
/**
|
|
625
|
+
* A transient database failure in the completion callback used to prevent a
|
|
626
|
+
* background continuation from ever being handed off. Keep the retry bounded
|
|
627
|
+
* and database-only so a permanent persistence error still fails loudly.
|
|
628
|
+
*/
|
|
629
|
+
export async function runCompletionCallbackWithDatabaseRetry(callback, options) {
|
|
630
|
+
const sleep = options?.sleep ??
|
|
631
|
+
((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
632
|
+
for (let attempt = 0;; attempt += 1) {
|
|
633
|
+
try {
|
|
634
|
+
await callback();
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
catch (error) {
|
|
638
|
+
const retryDelay = COMPLETION_DATABASE_RETRY_DELAYS_MS[attempt];
|
|
639
|
+
if (!isTransientDatabaseError(error) || retryDelay === undefined) {
|
|
640
|
+
throw error;
|
|
641
|
+
}
|
|
642
|
+
await sleep(retryDelay);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
623
646
|
/**
|
|
624
647
|
* Retry budget override for `builder_gateway_error` — the no-detail Builder
|
|
625
648
|
* gateway fallback. Production data shows this code is almost never
|
|
@@ -6981,7 +7004,7 @@ export function createProductionAgentHandler(options) {
|
|
|
6981
7004
|
const baseHandleRunComplete = options.onRunComplete || trackedProgressRunId
|
|
6982
7005
|
? async (run) => {
|
|
6983
7006
|
try {
|
|
6984
|
-
await options.onRunComplete?.(run, threadId);
|
|
7007
|
+
await runCompletionCallbackWithDatabaseRetry(() => options.onRunComplete?.(run, threadId));
|
|
6985
7008
|
}
|
|
6986
7009
|
catch (err) {
|
|
6987
7010
|
await completeTrackedProgressRun(run, err);
|
|
@@ -448,6 +448,11 @@ function terminalEventForcesErroredStatus(event) {
|
|
|
448
448
|
return event?.type === "error" || event?.type === "missing_api_key";
|
|
449
449
|
}
|
|
450
450
|
function terminalReasonForRun(finalStatus, terminalEvent, abortReason, completionError) {
|
|
451
|
+
if (finalStatus !== "aborted" &&
|
|
452
|
+
completionError &&
|
|
453
|
+
terminalEvent?.type === "auto_continue") {
|
|
454
|
+
return "completion_error";
|
|
455
|
+
}
|
|
451
456
|
if (terminalEvent?.type === "auto_continue") {
|
|
452
457
|
return terminalEvent.reason || "auto_continue";
|
|
453
458
|
}
|
|
@@ -1295,13 +1300,18 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1295
1300
|
: terminalEventForCompletion?.event.type === "error" ||
|
|
1296
1301
|
terminalEventForCompletion?.event.type === "missing_api_key"
|
|
1297
1302
|
? terminalEventForCompletion.event
|
|
1298
|
-
: terminalEventForCompletion?.event.type === "auto_continue"
|
|
1303
|
+
: terminalEventForCompletion?.event.type === "auto_continue" &&
|
|
1304
|
+
run.continuationTerminalEvent
|
|
1299
1305
|
? // The run was checkpointed at a soft-timeout/loop boundary and
|
|
1300
1306
|
// is recoverable: the partial turn is in agent_run_events and
|
|
1301
|
-
// the continuation run will re-attempt the
|
|
1307
|
+
// the handed-off continuation run will re-attempt the
|
|
1308
|
+
// thread_data save.
|
|
1302
1309
|
// Even though the completion save failed (finalStatus stays
|
|
1303
1310
|
// "errored" for SQL/diagnostics), re-emit the auto_continue so
|
|
1304
|
-
// the client resumes instead of seeing a dead chat.
|
|
1311
|
+
// the client resumes instead of seeing a dead chat. A
|
|
1312
|
+
// pending auto_continue without this handoff marker is not
|
|
1313
|
+
// recoverable: advertising it makes the client poll a dead
|
|
1314
|
+
// run until it reports background_run_lost.
|
|
1305
1315
|
terminalEventForCompletion.event
|
|
1306
1316
|
: {
|
|
1307
1317
|
type: "error",
|
|
@@ -22,7 +22,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
22
22
|
* <AgentChatSurface mode="page" className="h-screen" />
|
|
23
23
|
*/
|
|
24
24
|
import { Tooltip as DesignSystemTooltip } from "@agent-native/toolkit/design-system";
|
|
25
|
-
import { IconMessageCircle, IconMessageDots, IconTerminal2, IconSettings, IconLayoutSidebarRightCollapse, IconLayoutGrid, IconCheck, IconPlus, IconX, IconDotsVertical, IconHistory, IconArrowsHorizontal, IconArrowsMaximize, IconExternalLink, } from "@tabler/icons-react";
|
|
25
|
+
import { IconMessageCircle, IconMessageDots, IconTerminal2, IconSettings, IconLayoutSidebarRightCollapse, IconLayoutGrid, IconCheck, IconPlus, IconX, IconDotsVertical, IconHistory, IconArrowsHorizontal, IconArrowsMaximize, IconExternalLink, IconShare3, } from "@tabler/icons-react";
|
|
26
26
|
import React, { useState, useEffect, useRef, useCallback, useMemo, lazy, Suspense, startTransition, } from "react";
|
|
27
27
|
import { flushSync } from "react-dom";
|
|
28
28
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, } from "./components/ui/dropdown-menu.js";
|
|
@@ -666,6 +666,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
666
666
|
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground"), style: AGENT_PANEL_CONTROL_STYLE, children: [_jsx(IconLayoutGrid, { size: 14 }), t("agentPanel.workspace")] }), content: t("agentPanel.workspaceMode"), delayMs: 200 })] })), [codeAccessEnabled, codeUnavailableDescription, showCliMode, t]);
|
|
667
667
|
const [headerMenuOpen, setHeaderMenuOpen] = useState(false);
|
|
668
668
|
const [feedbackOpen, setFeedbackOpen] = useState(false);
|
|
669
|
+
const [shareFromMenuOpen, setShareFromMenuOpen] = useState(false);
|
|
669
670
|
const getChatThreadShareUrl = useCallback((threadId) => {
|
|
670
671
|
if (typeof window === "undefined")
|
|
671
672
|
return undefined;
|
|
@@ -700,7 +701,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
700
701
|
document.addEventListener("keydown", handleKeyDown);
|
|
701
702
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
702
703
|
}, [mode, onCollapse, wideDrawerAction]);
|
|
703
|
-
const renderHeaderActions = useCallback(({ activeChatSessionId, activeTabId, activeTabMessageCount, addTab, clearActiveTab, closeAllTabs, closeOtherTabs, closeTab, showHistory, tabs, toggleHistory, }) => (_jsxs("div", { className: "relative flex shrink-0 items-center gap-0.5", children: [!onCollapse && SHOW_ONBOARDING && (_jsx(Suspense, { fallback: null, children: _jsx(SetupButton, {}) })), !onCollapse &&
|
|
704
|
+
const renderHeaderActions = useCallback(({ activeChatSessionId, activeTabId, activeTabMessageCount, addTab, clearActiveTab, closeAllTabs, closeOtherTabs, closeTab, showHistory, tabs, toggleHistory, }) => (_jsxs("div", { className: "relative flex shrink-0 items-center gap-0.5", children: [!onCollapse && SHOW_ONBOARDING && (_jsx(Suspense, { fallback: null, children: _jsx(SetupButton, {}) })), (!onCollapse || shareFromMenuOpen) &&
|
|
704
705
|
(() => {
|
|
705
706
|
const activeTab = mode === "chat" && activeChatSessionId
|
|
706
707
|
? tabs.find((tab) => tab.id === activeChatSessionId)
|
|
@@ -709,7 +710,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
709
710
|
(activeTabMessageCount <= 0 && activeTab.status === "idle")) {
|
|
710
711
|
return null;
|
|
711
712
|
}
|
|
712
|
-
return (_jsx(ShareButton, { resourceType: "chat_thread", resourceId: activeTab.id, allowedRoles: ["viewer", "editor", "admin"], resourceTitle: activeTab.label || "Chat", shareUrl: getChatThreadShareUrl(activeTab.id), trigger: "icon", triggerClassName: "h-7 w-7" }));
|
|
713
|
+
return (_jsx(ShareButton, { resourceType: "chat_thread", resourceId: activeTab.id, allowedRoles: ["viewer", "editor", "admin"], resourceTitle: activeTab.label || "Chat", shareUrl: getChatThreadShareUrl(activeTab.id), trigger: "icon", triggerClassName: "h-7 w-7", defaultOpen: onCollapse && shareFromMenuOpen, onOpenChange: onCollapse ? setShareFromMenuOpen : undefined }));
|
|
713
714
|
})(), feedbackEnabled ? (_jsx(FeedbackButton, { variant: "icon", side: "bottom", align: "end", chatSessionId: activeChatSessionId, chatStorageKey: storageKey, open: feedbackOpen, onOpenChange: setFeedbackOpen, trigger: _jsx("button", { type: "button", tabIndex: -1, "aria-hidden": "true", className: "pointer-events-none absolute end-0 top-full h-px w-px opacity-0" }) })) : null, mode === "chat" && (_jsx(IconTooltip, { content: t("agentPanel.newChat"), children: _jsx("button", { onClick: addTab, "aria-label": t("agentPanel.newChat"), className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconPlus, { size: 14 }) }) })), !onCollapse && mode === "cli" && canUseCodeTools && (_jsx(IconTooltip, { content: t("agentPanel.newTerminal"), children: _jsx("button", { onClick: addCliTab, "aria-label": t("agentPanel.newTerminal"), className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconPlus, { size: 14 }) }) })), _jsxs(DropdownMenu, { open: headerMenuOpen, onOpenChange: setHeaderMenuOpen, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { className: cn("flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", (headerMenuOpen || mode === "settings") &&
|
|
714
715
|
"bg-accent text-foreground"), "aria-label": t("agentPanel.panelOptions"), children: _jsx(IconDotsVertical, { size: 14 }) }) }), _jsxs(DropdownMenuContent, { align: "end", sideOffset: 6, className: "w-48", children: [onCollapse && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: onCollapse, children: [_jsx(IconLayoutSidebarRightCollapse, { size: 14, className: "shrink-0" }), t("agentPanel.collapseSidebar"), _jsx(DropdownMenuShortcut, { children: toggleSidebarHint })] }), _jsx(DropdownMenuSeparator, {})] })), onCollapse && mode === "chat" && wideDrawerAction ? (_jsxs(DropdownMenuItem, { onSelect: wideDrawerAction, children: [_jsx(IconArrowsHorizontal, { size: 14, className: "shrink-0" }), wideDrawerLabel, _jsx(DropdownMenuShortcut, { children: widenChatHint })] })) : null, fullViewAction?.kind === "callback" && onFullViewRequest ? (_jsxs(DropdownMenuItem, { onSelect: onFullViewRequest, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] })) : fullViewAction?.kind === "link" ? (_jsx(DropdownMenuItem, { asChild: true, children: _jsxs(Link, { to: fullViewAction.href, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] }) })) : null, (onCollapse && mode === "chat" && wideDrawerAction) ||
|
|
715
716
|
fullViewAction ? (_jsx(DropdownMenuSeparator, {})) : null, onCollapse && mode === "chat" && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: addTab, children: [_jsx(IconPlus, { size: 14, className: "shrink-0" }), t("agentPanel.newChat")] }), (() => {
|
|
@@ -720,7 +721,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
720
721
|
(activeTabMessageCount <= 0 && activeTab.status === "idle")) {
|
|
721
722
|
return null;
|
|
722
723
|
}
|
|
723
|
-
return (
|
|
724
|
+
return (_jsxs(DropdownMenuItem, { onSelect: (event) => deferAgentPanelOverlayOpen(event, () => setHeaderMenuOpen(false), () => setShareFromMenuOpen(true)), children: [_jsx(IconShare3, { size: 14, className: "shrink-0" }), "Share"] }));
|
|
724
725
|
})()] })), mode === "chat" && toggleHistory && (_jsxs(DropdownMenuItem, { onSelect: (event) => deferAgentPanelOverlayOpen(event, () => setHeaderMenuOpen(false), toggleHistory), children: [_jsx(IconHistory, { size: 14, className: "shrink-0" }), showHistory
|
|
725
726
|
? t("agentPanel.hideChats")
|
|
726
727
|
: t("agentPanel.allChats")] })), mode === "chat" && (_jsx(RunsTrayMenuItem, { pollMs: 0, limit: 12, showRecent: true, onOpenThread: openRunThread })), mode === "chat" && _jsx(DropdownMenuSeparator, {}), mode === "cli" && availableClis.length > 0 && (_jsxs(_Fragment, { children: [availableClis.map((cli) => (_jsxs(DropdownMenuItem, { onSelect: () => selectCli(cli.command), className: cn(cli.command === selectedCli
|
|
@@ -752,6 +753,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
752
753
|
openRunThread,
|
|
753
754
|
selectCli,
|
|
754
755
|
selectedCli,
|
|
756
|
+
shareFromMenuOpen,
|
|
755
757
|
storageKey,
|
|
756
758
|
switchMode,
|
|
757
759
|
t,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { IconExternalLink } from "@tabler/icons-react";
|
|
2
|
+
import { IconAlertTriangle, IconExternalLink } from "@tabler/icons-react";
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import { isLocalDevelopmentOrigin, shouldOfferWorkspace, } from "../../org/workspace-url.js";
|
|
5
5
|
import { useOrg } from "./hooks.js";
|
|
6
|
+
import { isWorkspaceAppEnvironment } from "./workspace-app-links.js";
|
|
6
7
|
const DISMISS_KEY_PREFIX = "agent-native:workspace-notice-dismissed:";
|
|
7
8
|
function dismissKey(workspaceUrl) {
|
|
8
9
|
return `${DISMISS_KEY_PREFIX}${workspaceUrl}`;
|
|
@@ -38,14 +39,16 @@ export function WorkspaceNotice({ className }) {
|
|
|
38
39
|
const workspaceUrl = org?.workspaceUrl ?? null;
|
|
39
40
|
if (typeof window === "undefined")
|
|
40
41
|
return null;
|
|
41
|
-
if (isLocalDevelopmentOrigin(window.location.href)
|
|
42
|
+
if (isLocalDevelopmentOrigin(window.location.href) ||
|
|
43
|
+
isWorkspaceAppEnvironment()) {
|
|
42
44
|
return null;
|
|
45
|
+
}
|
|
43
46
|
if (!workspaceUrl || dismissedNow || readDismissed(workspaceUrl))
|
|
44
47
|
return null;
|
|
45
48
|
if (!shouldOfferWorkspace(window.location.href, workspaceUrl))
|
|
46
49
|
return null;
|
|
47
50
|
const workspaceHost = new URL(workspaceUrl).host;
|
|
48
|
-
return (_jsx("div", { className: `border-b border-
|
|
51
|
+
return (_jsx("div", { role: "status", "aria-live": "polite", className: `border-b border-amber-500/30 bg-amber-500/10 px-3 py-3 text-amber-900 dark:text-amber-200 sm:px-4 ${className ?? ""}`, children: _jsxs("div", { className: "flex flex-wrap items-start gap-x-3 gap-y-2 text-sm", children: [_jsx(IconAlertTriangle, { "aria-hidden": "true", className: "mt-0.5 size-4 shrink-0 text-amber-600 dark:text-amber-400" }), _jsxs("span", { className: "min-w-0 flex-1 leading-5", children: [_jsx("span", { className: "font-medium", children: org?.orgName }), " has its own workspace at ", _jsx("span", { className: "font-medium", children: workspaceHost }), ". Your team's apps live there, not here."] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsxs("a", { href: workspaceUrl, className: "inline-flex items-center gap-1.5 rounded-md border border-amber-600 bg-amber-600 px-3 py-1.5 text-xs font-medium text-primary-foreground no-underline hover:bg-amber-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", children: [_jsx(IconExternalLink, { className: "h-3 w-3" }), "Go there"] }), _jsx("button", { type: "button", onClick: () => {
|
|
49
52
|
try {
|
|
50
53
|
localStorage.setItem(dismissKey(workspaceUrl), "1");
|
|
51
54
|
}
|
|
@@ -53,5 +56,5 @@ export function WorkspaceNotice({ className }) {
|
|
|
53
56
|
// Private-mode storage failure only costs a repeat banner.
|
|
54
57
|
}
|
|
55
58
|
setDismissedNow(true);
|
|
56
|
-
}, className: "rounded-md border border-
|
|
59
|
+
}, className: "cursor-pointer rounded-md border border-amber-500/40 bg-background/60 px-3 py-1.5 text-xs font-medium text-amber-900 hover:bg-amber-500/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 dark:border-amber-800 dark:bg-amber-950/20 dark:text-amber-100 dark:hover:bg-amber-900/40", children: "Stay here" })] })] }) }));
|
|
57
60
|
}
|
|
@@ -29,8 +29,8 @@ export interface ShareButtonProps {
|
|
|
29
29
|
shareUrlLabel?: string;
|
|
30
30
|
/** Optional helper text for the primary copyable link section. */
|
|
31
31
|
shareUrlDescription?: ReactNode;
|
|
32
|
-
/** Where to render share links in the popover. Defaults to the
|
|
33
|
-
*
|
|
32
|
+
/** Where to render share links in the popover. Defaults to the top,
|
|
33
|
+
* keeping the copyable link as the primary share action. */
|
|
34
34
|
shareUrlPlacement?: "top" | "bottom";
|
|
35
35
|
/** Whether to render copyable share URL fields. Defaults to true. */
|
|
36
36
|
showShareLinks?: boolean;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@agent-native/toolkit/ui";
|
|
2
3
|
import * as Select from "@radix-ui/react-select";
|
|
3
4
|
import { IconLock, IconWorld, IconTrash, IconCheck, IconChevronDown, IconCopy, IconLoader2, IconSearch, IconSearchOff, IconShare3, IconUsersGroup, } from "@tabler/icons-react";
|
|
4
5
|
import { useEffect, useId, useRef, useState, } from "react";
|
|
@@ -114,25 +115,29 @@ function SharePanel(props) {
|
|
|
114
115
|
(Boolean(props.shareUrl) ||
|
|
115
116
|
Boolean(props.shareUrlPlaceholder) ||
|
|
116
117
|
Boolean(props.secondaryShareUrl));
|
|
117
|
-
const shareUrlPlacement = props.shareUrlPlacement ?? "
|
|
118
|
+
const shareUrlPlacement = props.shareUrlPlacement ?? "top";
|
|
119
|
+
const [advancedOpen, setAdvancedOpen] = useState(!showShareLinks);
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
setAdvancedOpen(!showShareLinks);
|
|
122
|
+
}, [props.resourceId, showShareLinks]);
|
|
118
123
|
const extraTabs = props.shareTabs?.tabs ?? [];
|
|
119
124
|
const hasTabs = extraTabs.length > 0;
|
|
120
125
|
const shareTabLabel = props.shareTabs?.shareLabel ?? "Share link";
|
|
121
126
|
const titleText = resourceTitle
|
|
122
127
|
? `Share "${resourceTitle}"`
|
|
123
128
|
: `Share ${props.resourceType}`;
|
|
124
|
-
const sharePanel = isLoading ? (_jsxs("div", { children: [!hasTabs ? (_jsx("div", { className: "mb-3 truncate text-base font-semibold", title: titleText, children: titleText })) : null, _jsx("div", { className: "mb-4 h-9 rounded-md bg-muted animate-pulse" }), _jsx("div", { className: "mb-2 text-sm font-semibold", children: peopleAccessLabel }), _jsx("div", { className: "mb-4 h-7 rounded-md bg-muted animate-pulse" }), _jsx("div", { className: "mb-2 text-sm font-semibold", children: generalAccessLabel }), _jsx("div", { className: "mb-4 h-9 rounded-md bg-muted animate-pulse" })] })) : (_jsxs("div", { children: [!hasTabs ? (_jsx("div", { className: "mb-3 truncate text-base font-semibold", title: titleText, children: titleText })) : null, showShareLinks && shareUrlPlacement === "top" ? shareLinks : null, canManage ? (_jsxs("div", { className: "
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
129
|
+
const sharePanel = isLoading ? (_jsxs("div", { children: [!hasTabs ? (_jsx("div", { className: "mb-3 truncate text-base font-semibold", title: titleText, children: titleText })) : null, _jsx("div", { className: "mb-4 h-9 rounded-md bg-muted animate-pulse" }), _jsx("div", { className: "mb-2 text-sm font-semibold", children: peopleAccessLabel }), _jsx("div", { className: "mb-4 h-7 rounded-md bg-muted animate-pulse" }), _jsx("div", { className: "mb-2 text-sm font-semibold", children: generalAccessLabel }), _jsx("div", { className: "mb-4 h-9 rounded-md bg-muted animate-pulse" })] })) : (_jsxs("div", { children: [!hasTabs ? (_jsx("div", { className: "mb-3 truncate text-base font-semibold", title: titleText, children: titleText })) : null, showShareLinks && shareUrlPlacement === "top" ? shareLinks : null, _jsxs(Collapsible, { open: advancedOpen, onOpenChange: setAdvancedOpen, className: "mb-4 overflow-hidden rounded-md border border-border", children: [_jsx(CollapsibleTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "flex min-h-10 w-full items-center justify-between gap-3 px-3 py-2 text-left text-sm font-medium transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset", children: [_jsxs("span", { className: "flex min-w-0 items-center gap-2 truncate", children: [_jsx(IconUsersGroup, { "aria-hidden": true, size: 15, strokeWidth: 1.8, className: "shrink-0 text-muted-foreground" }), canManage ? "Manage access" : peopleAccessLabel] }), _jsx(IconChevronDown, { "aria-hidden": true, size: 16, strokeWidth: 1.8, className: cn("shrink-0 text-muted-foreground transition-transform", advancedOpen && "rotate-180") })] }) }), _jsx(CollapsibleContent, { className: "border-t border-border px-3 py-3", children: _jsxs("div", { className: "space-y-4", children: [canManage ? (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-stretch gap-2", children: [_jsx(MemberAutocomplete, { value: inviteEmail, open: suggestionsOpen, onOpenChange: setSuggestionsOpen, onValueChange: (next) => {
|
|
130
|
+
onInviteEmailChange(next);
|
|
131
|
+
if (shareError)
|
|
132
|
+
setShareError(null);
|
|
133
|
+
}, onSelectMember: (member) => {
|
|
134
|
+
onInviteEmailChange(member.email);
|
|
135
|
+
setSuggestionsOpen(false);
|
|
136
|
+
if (shareError)
|
|
137
|
+
setShareError(null);
|
|
138
|
+
}, onSubmit: handleAdd, placeholder: policy.requireOrgMemberForUserShares
|
|
139
|
+
? "Add people from your organization"
|
|
140
|
+
: "Add people by email", suggestions: memberSuggestions, search: memberSearch }), _jsx(RoleSelect, { value: role, onChange: setRole, roleCopy: props.roleCopy, allowedRoles: props.allowedRoles }), _jsx("button", { type: "button", onClick: handleAdd, disabled: !hasInviteEmail, className: BUTTON_PRIMARY_SM, children: "Add" })] }), shareError ? (_jsx("div", { role: "alert", className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: shareError })) : null, hasInviteEmail ? (_jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2 text-xs text-muted-foreground", children: [_jsxs("label", { className: "inline-flex items-center gap-2", children: [_jsx("input", { type: "checkbox", checked: notifyPeople, onChange: (e) => setNotifyPeople(e.target.checked), className: "h-4 w-4 rounded border-input accent-primary" }), "Notify people"] }), notifyPeople ? (_jsx("button", { type: "button", "aria-expanded": messageOpen, onClick: () => setMessageOpen(!messageOpen), className: "rounded-sm px-1 py-0.5 font-medium text-foreground underline decoration-border underline-offset-2 transition-colors hover:bg-accent hover:text-accent-foreground", children: messageOpen ? "Hide message" : "Add a message" })) : null] })) : null, hasInviteEmail && notifyPeople && messageOpen ? (_jsx("div", { className: "rounded-md border border-border/70 bg-muted/20 p-2.5", children: _jsx("textarea", { "aria-label": "Message", placeholder: "Add a short note (optional)", value: shareMessage, onChange: (event) => setShareMessage(event.target.value), maxLength: 500, rows: 3, className: "w-full resize-y rounded-md border border-input bg-card px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background" }) })) : null] })) : null, _jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-semibold", children: peopleAccessLabel }), _jsxs("ul", { className: "flex flex-col gap-1 list-none p-0 m-0", children: [data?.ownerEmail ? (_jsxs("li", { className: "flex items-center gap-3 px-1 py-1.5 text-sm", children: [_jsx(Avatar, { label: displayName(data.ownerEmail, knownMembers) }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: displayName(data.ownerEmail, knownMembers) }), _jsx("span", { className: "text-xs text-muted-foreground", children: "Owner" })] })) : null, shares.map((s) => (_jsxs("li", { className: cn("flex items-center gap-3 px-1 py-1.5 text-sm", inFlight.has(keyOf(s)) && "opacity-60"), children: [_jsx(Avatar, { label: principalLabel(s, knownMembers), org: s.principalType === "org" }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: principalLabel(s, knownMembers) }), canManage ? (_jsx(RoleSelect, { value: s.role, onChange: (r) => handleChangeRole(s, r), disabled: inFlight.has(keyOf(s)), plain: true, roleCopy: props.roleCopy, allowedRoles: props.allowedRoles })) : (_jsx("span", { className: "text-xs text-muted-foreground", children: roleMeta(s.role, props.roleCopy).label })), canManage ? (_jsx("button", { type: "button", "aria-label": "Remove", onClick: () => handleRemove(s), disabled: inFlight.has(keyOf(s)), className: BUTTON_GHOST_ICON, children: _jsx(IconTrash, { size: 14 }) })) : null] }, keyOf(s)))), !shares.length && !data?.ownerEmail ? (_jsx("li", { className: "px-1 py-1.5 text-sm text-muted-foreground", children: "No one has access yet." })) : null] })] })] }) })] }), _jsx("div", { className: "mb-2 text-sm font-semibold", children: generalAccessLabel }), _jsxs("div", { className: "mb-4 flex items-center gap-3", children: [_jsx("span", { "aria-hidden": true, className: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: _jsx(meta.Icon, { size: 16, strokeWidth: 1.75 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(VisibilitySelect, { value: visibility, onChange: handleVisibility, disabled: !canManage, visibilityCopy: props.visibilityCopy, allowPublic: policy.allowPublic }), _jsxs("div", { className: "mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground", children: [_jsx("span", { className: "sr-only", children: meta.description }), visibility === "org" && props.hideInSearchControl ? (_jsx(AdvancedAccessPopover, { control: props.hideInSearchControl, canManage: canManage, onToggle: handleHideInSearch })) : null] })] })] }), shareError && !canManage ? (_jsx("div", { role: "alert", className: "mb-4 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive", children: shareError })) : null, props.accessNote ? (_jsx("div", { className: "mb-4 rounded-md border border-border bg-muted/35 p-3 text-xs text-muted-foreground", children: props.accessNote })) : null, showShareLinks && shareUrlPlacement === "bottom" ? shareLinks : null, props.shareFooterContent] }));
|
|
136
141
|
if (!hasTabs)
|
|
137
142
|
return sharePanel;
|
|
138
143
|
const tabs = [
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { ActionButton, Avatar as DesignSystemAvatar, Dialog as DesignSystemDialog, IconButton, Picker, Status, TextArea, TextField, } from "@agent-native/toolkit/design-system";
|
|
3
|
-
import {
|
|
3
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@agent-native/toolkit/ui";
|
|
4
|
+
import { IconCheck, IconCode, IconCopy, IconChevronDown, IconLink, IconLock, IconMail, IconTrash, IconUsersGroup, IconWorld, } from "@tabler/icons-react";
|
|
5
|
+
import { useState } from "react";
|
|
4
6
|
import { cn } from "../utils.js";
|
|
5
7
|
import { useShareDialogController, } from "./useShareDialogController.js";
|
|
6
8
|
const BUTTON_BASE = "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors active:!scale-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0";
|
|
@@ -49,18 +51,19 @@ function TabTrigger({ active, onClick, icon, label, }) {
|
|
|
49
51
|
}
|
|
50
52
|
function LinkTab({ controller, extras, }) {
|
|
51
53
|
const Icon = VIS_ICONS[controller.visibility.value];
|
|
52
|
-
return (_jsxs("div", { className: "space-y-
|
|
54
|
+
return (_jsxs("div", { className: "space-y-3", children: [_jsx(CopyField, { field: "share-link", label: controller.labels.shareLink, value: controller.shareUrl, controller: controller }), _jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-semibold", children: controller.labels.generalAccess }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { "aria-hidden": true, className: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: _jsx(Icon, { size: 16, strokeWidth: 1.75 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(VisibilitySelect, { controller: controller }), _jsx("div", { className: "sr-only text-xs text-muted-foreground", children: controller.visibility.description })] })] })] }), extras] }));
|
|
53
55
|
}
|
|
54
56
|
function InviteTab({ controller, showVisibility, }) {
|
|
55
57
|
const Icon = VIS_ICONS[controller.visibility.value];
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
const [advancedOpen, setAdvancedOpen] = useState(false);
|
|
59
|
+
return (_jsxs("div", { className: "space-y-3", children: [_jsxs(Collapsible, { open: advancedOpen, onOpenChange: setAdvancedOpen, className: "overflow-hidden rounded-md border border-border", children: [_jsx(CollapsibleTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "flex min-h-10 w-full items-center justify-between gap-3 px-3 py-2 text-left text-sm font-medium transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset", children: [_jsx("span", { className: "truncate", children: controller.labels.peopleWithAccess }), _jsx(IconChevronDown, { "aria-hidden": true, size: 16, strokeWidth: 1.8, className: cn("shrink-0 text-muted-foreground transition-transform", advancedOpen && "rotate-180") })] }) }), _jsx(CollapsibleContent, { className: "border-t border-border px-3 py-3", children: _jsxs("div", { className: "space-y-4", children: [controller.canManage ? (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-stretch gap-2", children: [_jsx("input", { type: "email", placeholder: controller.labels.addPeopleByEmail, value: controller.invite.email, onChange: (event) => controller.invite.setEmail(event.currentTarget.value), onKeyDown: (event) => {
|
|
60
|
+
if (event.key === "Enter")
|
|
61
|
+
controller.invite.submit();
|
|
62
|
+
}, autoComplete: "off", className: "h-9 min-w-0 flex-1 rounded-md border border-input bg-background px-3 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background" }), _jsx(RoleSelect, { controller: controller })] }), controller.invite.showNotifyPeople ? (_jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2 text-xs text-muted-foreground", children: [_jsxs("label", { className: "inline-flex items-center gap-2", children: [_jsx("input", { type: "checkbox", checked: controller.invite.notifyPeople, onChange: (event) => controller.invite.setNotifyPeople(event.currentTarget.checked), className: "h-4 w-4 rounded border-input accent-primary" }), controller.labels.notifyPeople] }), controller.invite.notifyPeople ? (_jsx(ActionButton, { type: "button", emphasis: "ghost", "aria-expanded": controller.invite.messageOpen, onPress: () => controller.invite.setMessageOpen(!controller.invite.messageOpen), className: "!h-auto !rounded-sm !px-1 !py-0.5 text-xs font-medium !text-foreground underline decoration-border underline-offset-2 hover:!bg-accent hover:!text-accent-foreground active:!scale-100", children: controller.invite.messageOpen
|
|
63
|
+
? controller.labels.hideMessage
|
|
64
|
+
: controller.labels.addMessage })) : null] })) : null, controller.invite.showNotifyPeople &&
|
|
65
|
+
controller.invite.notifyPeople &&
|
|
66
|
+
controller.invite.messageOpen ? (_jsx(TextArea, { "aria-label": controller.labels.addMessage, placeholder: controller.labels.messagePlaceholder, value: controller.invite.message, onChange: (value) => controller.invite.setMessage(value), maxLength: 500, rows: 3, className: "min-h-20 resize-y text-sm" })) : null] })) : null, _jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-semibold", children: controller.labels.peopleWithAccess }), _jsxs("ul", { className: "m-0 flex list-none flex-col gap-1 p-0", children: [controller.people.map((person) => (_jsx(PersonRow, { person: person, canManage: controller.canManage, removeLabel: controller.labels.remove, onRemove: controller.removeShare }, person.key))), !controller.people.length ? (_jsx("li", { className: "px-1 py-1.5 text-sm text-muted-foreground", children: controller.labels.noAccess })) : null] })] })] }) })] }), showVisibility ? (_jsxs("div", { children: [_jsx("div", { className: "mb-2 text-sm font-semibold", children: controller.labels.generalAccess }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { "aria-hidden": true, className: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: _jsx(Icon, { size: 16, strokeWidth: 1.75 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(VisibilitySelect, { controller: controller }), _jsx("div", { className: "sr-only text-xs text-muted-foreground", children: controller.visibility.description })] })] })] })) : null] }));
|
|
64
67
|
}
|
|
65
68
|
function PersonRow({ person, canManage, removeLabel, onRemove, }) {
|
|
66
69
|
return (_jsxs("li", { className: "flex items-center gap-3 px-1 py-1.5 text-sm", children: [_jsx(DesignSystemAvatar, { name: person.label, fallback: person.principalType === "org" ? (_jsx(IconUsersGroup, { size: 14, strokeWidth: 1.75 })) : (person.avatarText), size: "compact", className: "inline-flex h-7 w-7 shrink-0 text-[11px] font-semibold" }), _jsx("span", { className: "flex-1 min-w-0 truncate", children: person.label }), _jsx(Status, { tone: "neutral", size: "compact", className: "border-0 bg-transparent px-0 text-xs text-muted-foreground", children: person.roleLabel }), canManage && person.share ? (_jsx(IconButton, { intent: "danger", emphasis: "ghost", size: "compact", icon: _jsx(IconTrash, { size: 14 }), label: removeLabel, "aria-label": removeLabel, onPress: () => onRemove(person.share), className: cn(BUTTON_GHOST_ICON, "[&_svg]:!size-auto") })) : null] }));
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
|
|
|
26
26
|
* Body: { update: string (base64), requestSource?: string }
|
|
27
27
|
*/
|
|
28
28
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
29
|
-
error: string;
|
|
30
29
|
ok?: undefined;
|
|
30
|
+
error: string;
|
|
31
31
|
} | {
|
|
32
32
|
error?: undefined;
|
|
33
33
|
ok: boolean;
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
|
|
14
14
|
*/
|
|
15
15
|
export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
16
|
-
error: string;
|
|
17
16
|
ok?: undefined;
|
|
17
|
+
error: string;
|
|
18
18
|
} | {
|
|
19
19
|
error?: undefined;
|
|
20
20
|
ok: boolean;
|
|
@@ -41,16 +41,16 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
41
41
|
thumbsUpRate: number;
|
|
42
42
|
avgEvalScore: number;
|
|
43
43
|
} | {
|
|
44
|
-
error?: undefined;
|
|
45
44
|
summary: import("./types.js").TraceSummary;
|
|
46
45
|
spans: import("./types.js").TraceSpan[];
|
|
47
46
|
id?: undefined;
|
|
47
|
+
error?: undefined;
|
|
48
48
|
ok?: undefined;
|
|
49
49
|
} | {
|
|
50
|
-
error?: undefined;
|
|
51
50
|
summary?: undefined;
|
|
52
51
|
spans?: undefined;
|
|
53
52
|
id: string;
|
|
53
|
+
error?: undefined;
|
|
54
54
|
ok?: undefined;
|
|
55
55
|
} | {
|
|
56
56
|
summary?: undefined;
|
|
@@ -59,9 +59,9 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
59
59
|
error: any;
|
|
60
60
|
ok?: undefined;
|
|
61
61
|
} | {
|
|
62
|
-
error?: undefined;
|
|
63
62
|
summary?: undefined;
|
|
64
63
|
spans?: undefined;
|
|
65
64
|
id?: undefined;
|
|
65
|
+
error?: undefined;
|
|
66
66
|
ok: boolean;
|
|
67
67
|
}>>;
|