@agent-native/dispatch 0.20.4 → 0.22.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/dist/actions/get-agent-thread-debug.d.ts +2 -0
- package/dist/actions/provider-api-register.d.ts +7 -7
- package/dist/actions/search-agent-threads.js +2 -2
- package/dist/actions/search-agent-threads.js.map +1 -1
- package/dist/actions/start-workspace-app-creation.js +1 -1
- package/dist/actions/start-workspace-app-creation.js.map +1 -1
- package/dist/components/create-app-popover.d.ts.map +1 -1
- package/dist/components/create-app-popover.js +5 -71
- package/dist/components/create-app-popover.js.map +1 -1
- package/dist/components/layout/HeaderActions.d.ts +1 -17
- package/dist/components/layout/HeaderActions.d.ts.map +1 -1
- package/dist/components/layout/HeaderActions.js +1 -51
- package/dist/components/layout/HeaderActions.js.map +1 -1
- package/dist/components/layout/Layout.d.ts +23 -1
- package/dist/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +707 -18
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/ui/dialog.d.ts +1 -19
- package/dist/components/ui/dialog.d.ts.map +1 -1
- package/dist/components/ui/dialog.js +1 -22
- package/dist/components/ui/dialog.js.map +1 -1
- package/dist/components/ui/dropdown-menu.d.ts +1 -27
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
- package/dist/components/ui/dropdown-menu.js +1 -35
- package/dist/components/ui/dropdown-menu.js.map +1 -1
- package/dist/components/ui/popover.d.ts +2 -1
- package/dist/components/ui/popover.d.ts.map +1 -1
- package/dist/components/ui/popover.js +2 -1
- package/dist/components/ui/popover.js.map +1 -1
- package/dist/components/ui/select.d.ts +1 -13
- package/dist/components/ui/select.d.ts.map +1 -1
- package/dist/components/ui/select.js +1 -26
- package/dist/components/ui/select.js.map +1 -1
- package/dist/hooks/use-mobile.d.ts +1 -1
- package/dist/hooks/use-mobile.d.ts.map +1 -1
- package/dist/hooks/use-mobile.js +1 -15
- package/dist/hooks/use-mobile.js.map +1 -1
- package/dist/lib/automation-display.js +1 -1
- package/dist/lib/automation-display.js.map +1 -1
- package/dist/lib/workspace-apps.d.ts +6 -0
- package/dist/lib/workspace-apps.d.ts.map +1 -1
- package/dist/lib/workspace-apps.js +21 -0
- package/dist/lib/workspace-apps.js.map +1 -1
- package/dist/routes/pages/settings.d.ts.map +1 -1
- package/dist/routes/pages/settings.js +21 -1
- package/dist/routes/pages/settings.js.map +1 -1
- package/dist/routes/pages/thread-debug.d.ts.map +1 -1
- package/dist/routes/pages/thread-debug.js +288 -118
- package/dist/routes/pages/thread-debug.js.map +1 -1
- package/dist/server/lib/app-creation-store.d.ts.map +1 -1
- package/dist/server/lib/app-creation-store.js +13 -0
- package/dist/server/lib/app-creation-store.js.map +1 -1
- package/dist/server/lib/thread-debug-store.d.ts +2 -0
- package/dist/server/lib/thread-debug-store.d.ts.map +1 -1
- package/dist/server/lib/thread-debug-store.js +6 -2
- package/dist/server/lib/thread-debug-store.js.map +1 -1
- package/dist/server/plugins/agent-chat.js +1 -0
- package/dist/server/plugins/agent-chat.js.map +1 -1
- package/dist/server/plugins/integrations.js +1 -1
- package/dist/server/plugins/integrations.js.map +1 -1
- package/package.json +3 -3
- package/src/actions/search-agent-threads.ts +2 -2
- package/src/actions/start-workspace-app-creation.ts +1 -1
- package/src/components/create-app-popover.spec.tsx +22 -0
- package/src/components/create-app-popover.tsx +30 -94
- package/src/components/layout/HeaderActions.tsx +1 -84
- package/src/components/layout/Layout.spec.tsx +35 -10
- package/src/components/layout/Layout.tsx +1394 -74
- package/src/components/ui/dialog.tsx +1 -120
- package/src/components/ui/dropdown-menu.tsx +1 -198
- package/src/components/ui/popover.tsx +3 -1
- package/src/components/ui/select.tsx +1 -158
- package/src/hooks/use-mobile.tsx +1 -21
- package/src/lib/automation-display.spec.ts +1 -1
- package/src/lib/automation-display.ts +1 -1
- package/src/lib/workspace-apps.ts +24 -0
- package/src/routes/pages/settings.tsx +72 -0
- package/src/routes/pages/thread-debug.spec.tsx +103 -5
- package/src/routes/pages/thread-debug.tsx +1051 -451
- package/src/server/lib/app-creation-store.spec.ts +13 -0
- package/src/server/lib/app-creation-store.ts +13 -0
- package/src/server/lib/mcp-gateway.spec.ts +18 -0
- package/src/server/lib/thread-debug-store.spec.ts +17 -0
- package/src/server/lib/thread-debug-store.ts +9 -2
- package/src/server/plugins/agent-chat.ts +1 -0
- package/src/server/plugins/integrations.ts +1 -1
- package/src/styles/dispatch.css +29 -0
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { AgentSidebar, focusAgentChat, navigateWithAgentChatViewTransition, useAgentChatHomeHandoff, useAgentChatHomeHandoffLinks, useChatThreads, } from "@agent-native/core/client/agent-chat";
|
|
2
|
+
import { CHAT_FIRST_MODE_CHANGED_EVENT, AgentChatSurface, chatFirstSurfaceTabId, AgentSidebar, ChatFirstSurfacePanelToggle, closeChatFirstSessionWatch, emitChatFirstSessionWatch, getChatFirstSurfaceTabsStore, focusAgentChat, navigateWithAgentChatViewTransition, readChatFirstAppLayout, readChatFirstMode, resolveChatFirstBrowserTarget, resolveChatFirstAppTarget, subscribeChatFirstOpenBrowser, subscribeChatFirstOpenApp, useChatFirstSessionWatch, useChatFirstSurfacePanel, useChatFirstSurfaceResize, useChatFirstSurfaceTabs, useAgentChatHomeHandoff, useAgentChatHomeHandoffLinks, useChatThreads, } from "@agent-native/core/client/agent-chat";
|
|
3
3
|
import { appBasePath, appPath } from "@agent-native/core/client/api-path";
|
|
4
|
+
import { readClientAppState, writeClientAppState, } from "@agent-native/core/client/application-state";
|
|
5
|
+
import { ChatFirstAgentsPane, ChatFirstAppPane, ChatFirstAppsRail, ChatFirstBrowserPane, ChatFirstChatHistory, ChatFirstPrimaryNavigation, ChatFirstSessionWatchPane, ChatFirstSurfacePanel, ChatFirstSurfaceContent, ChatFirstSurfaceTabs, defaultChatFirstCopy, } from "@agent-native/core/client/chat-first";
|
|
6
|
+
import { writeClipboardText } from "@agent-native/core/client/clipboard";
|
|
7
|
+
import { useActionMutation, useActionQuery, } from "@agent-native/core/client/hooks";
|
|
4
8
|
import { useT } from "@agent-native/core/client/i18n";
|
|
5
9
|
import { openCommandMenu } from "@agent-native/core/client/navigation";
|
|
6
10
|
import { InvitationBanner, OrgSwitcher } from "@agent-native/core/client/org";
|
|
7
11
|
import { FeedbackButton } from "@agent-native/core/client/ui";
|
|
8
12
|
import { SidebarFooterActions } from "@agent-native/toolkit/app-shell";
|
|
9
13
|
import { ChatHistoryRail, } from "@agent-native/toolkit/chat-history";
|
|
10
|
-
import { IconApps, IconBrandSlack, IconBrandTelegram, IconMessageQuestion, IconBroadcast, IconLayoutSidebarLeftCollapse, IconLayoutSidebarLeftExpand, IconSettings, IconShield, IconSearch, IconWorld, IconDeviceDesktop, } from "@tabler/icons-react";
|
|
11
|
-
import { createContext, useEffect, useMemo, useRef, useState, useContext, } from "react";
|
|
14
|
+
import { IconApps, IconBrandSlack, IconBrandTelegram, IconCopy, IconEye, IconMessageQuestion, IconBroadcast, IconLayoutSidebarLeftCollapse, IconLayoutSidebarLeftExpand, IconSettings, IconShield, IconSearch, IconWorld, IconDeviceDesktop, IconPlus, } from "@tabler/icons-react";
|
|
15
|
+
import { createContext, useEffect, useMemo, useRef, useState, useContext, useCallback, } from "react";
|
|
12
16
|
import { Link, useLocation, useNavigate } from "react-router";
|
|
17
|
+
import { toast } from "sonner";
|
|
13
18
|
import { cn } from "../../lib/utils.js";
|
|
19
|
+
import { mergeChatFirstWorkspaceApps, } from "../../lib/workspace-apps.js";
|
|
20
|
+
import { AppIcon } from "../app-icon.js";
|
|
21
|
+
import { CreateAppPopover } from "../create-app-popover.js";
|
|
14
22
|
import { Sheet, SheetContent, SheetDescription, SheetTitle } from "../ui/sheet.js";
|
|
15
23
|
import { Skeleton } from "../ui/skeleton.js";
|
|
16
24
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip.js";
|
|
17
25
|
import { Header } from "./Header.js";
|
|
18
26
|
import { HeaderActionsProvider } from "./HeaderActions.js";
|
|
19
|
-
import { WorkspaceAppsRail } from "./workspace-apps-rail.js";
|
|
20
27
|
const PRIMARY_NAV_ITEMS = [
|
|
21
28
|
{
|
|
22
29
|
id: "overview",
|
|
@@ -59,6 +66,10 @@ const DISPATCH_SIDEBAR_LABEL = "Dispatch";
|
|
|
59
66
|
const CHROMELESS_PATHS = ["/approval", "/browser-chat", "/browser-connect"];
|
|
60
67
|
const SIDEBAR_COLLAPSE_KEY = "dispatch.sidebar.collapsed";
|
|
61
68
|
const CHAT_HISTORY_SOURCE_KEY = "dispatch.chat-history.source";
|
|
69
|
+
const CHAT_FIRST_PANE_STATE_KEY = "chat-first-pane";
|
|
70
|
+
export function buildChatFirstEmbedSessionInput(appId, path) {
|
|
71
|
+
return { app: appId, path, chrome: "minimal" };
|
|
72
|
+
}
|
|
62
73
|
const DispatchExtensionsContext = createContext(undefined);
|
|
63
74
|
export function useDispatchExtensions() {
|
|
64
75
|
return useContext(DispatchExtensionsContext);
|
|
@@ -120,8 +131,147 @@ function dispatchNavLinkTarget(path) {
|
|
|
120
131
|
const routerHasBasename = pathname === basePath || pathname.startsWith(`${basePath}/`);
|
|
121
132
|
return routerHasBasename ? path : appPath(path);
|
|
122
133
|
}
|
|
134
|
+
function chatFirstResolutionMessage(reason) {
|
|
135
|
+
switch (reason) {
|
|
136
|
+
case "empty-detail":
|
|
137
|
+
return "The agent did not provide an app target to open.";
|
|
138
|
+
case "invalid-url":
|
|
139
|
+
return "The requested app route was not registered for this workspace app.";
|
|
140
|
+
case "unknown-app":
|
|
141
|
+
return "That app is not available in this workspace.";
|
|
142
|
+
}
|
|
143
|
+
return "The requested app could not be opened.";
|
|
144
|
+
}
|
|
145
|
+
function chatFirstBrowserResolutionMessage(reason) {
|
|
146
|
+
return reason === "empty-detail"
|
|
147
|
+
? "The agent did not provide a browser URL to open."
|
|
148
|
+
: "The requested browser URL is not a safe HTTP(S) address.";
|
|
149
|
+
}
|
|
150
|
+
const DISPATCH_CHAT_FIRST_COPY_KEYS = {
|
|
151
|
+
workspaceApps: "chatFirstWorkspaceApps",
|
|
152
|
+
createWorkspaceApp: "chatFirstCreateWorkspaceApp",
|
|
153
|
+
openApp: "chatFirstOpenApp",
|
|
154
|
+
appsLoadError: "chatFirstAppsLoadError",
|
|
155
|
+
noWorkspaceApps: "chatFirstNoWorkspaceApps",
|
|
156
|
+
createApp: "chatFirstCreateApp",
|
|
157
|
+
retry: "chatFirstRetry",
|
|
158
|
+
dismiss: "chatFirstDismiss",
|
|
159
|
+
unpinApp: "chatFirstUnpinApp",
|
|
160
|
+
pinApp: "chatFirstPinApp",
|
|
161
|
+
removePinned: "chatFirstRemovePinned",
|
|
162
|
+
pinTop: "chatFirstPinTop",
|
|
163
|
+
openSideSurfaces: "chatFirstOpenSideSurfaces",
|
|
164
|
+
closeTab: "chatFirstCloseTab",
|
|
165
|
+
close: "chatFirstClose",
|
|
166
|
+
closeOthers: "chatFirstCloseOthers",
|
|
167
|
+
closeToRight: "chatFirstCloseToRight",
|
|
168
|
+
closeAll: "chatFirstCloseAll",
|
|
169
|
+
unavailable: "chatFirstUnavailable",
|
|
170
|
+
openActivity: "chatFirstOpenActivity",
|
|
171
|
+
deferred: "chatFirstDeferred",
|
|
172
|
+
browserBack: "chatFirstBrowserBack",
|
|
173
|
+
browserForward: "chatFirstBrowserForward",
|
|
174
|
+
browserReload: "chatFirstBrowserReload",
|
|
175
|
+
browserAddress: "chatFirstBrowserAddress",
|
|
176
|
+
browserOpenExternal: "chatFirstBrowserOpenExternal",
|
|
177
|
+
browserClose: "chatFirstBrowserClose",
|
|
178
|
+
browserPage: "chatFirstBrowserPage",
|
|
179
|
+
browserInvalidUrl: "chatFirstBrowserInvalidUrl",
|
|
180
|
+
browserPreviewStarting: "chatFirstBrowserPreviewStarting",
|
|
181
|
+
browserPreviewError: "chatFirstBrowserPreviewError",
|
|
182
|
+
appUnavailable: "chatFirstAppUnavailable",
|
|
183
|
+
appLoading: "chatFirstLoadingApp",
|
|
184
|
+
agentActivityEyebrow: "chatFirstAgentActivityEyebrow",
|
|
185
|
+
agentActivityTitle: "chatFirstAgentActivityTitle",
|
|
186
|
+
agentActivityDescription: "chatFirstAgentActivityDescription",
|
|
187
|
+
refreshAgentActivity: "chatFirstRefreshAgentActivity",
|
|
188
|
+
noAgentSessions: "chatFirstNoAgentSessions",
|
|
189
|
+
startAgentSession: "chatFirstStartAgentSession",
|
|
190
|
+
watchSession: "chatFirstWatchSession",
|
|
191
|
+
copySessionId: "chatFirstCopySessionId",
|
|
192
|
+
copySessionIdFor: "chatFirstCopySessionIdFor",
|
|
193
|
+
sessionIdCopied: "chatFirstSessionIdCopied",
|
|
194
|
+
sessionIdShort: "chatFirstSessionIdShort",
|
|
195
|
+
copied: "chatFirstCopied",
|
|
196
|
+
agentActivityStatusQueued: "chatFirstAgentActivityStatusQueued",
|
|
197
|
+
agentActivityStatusRunning: "chatFirstAgentActivityStatusRunning",
|
|
198
|
+
agentActivityStatusPaused: "chatFirstAgentActivityStatusPaused",
|
|
199
|
+
agentActivityStatusNeedsApproval: "chatFirstAgentActivityStatusNeedsApproval",
|
|
200
|
+
agentActivityStatusCompleted: "chatFirstAgentActivityStatusCompleted",
|
|
201
|
+
agentActivityStatusErrored: "chatFirstAgentActivityStatusErrored",
|
|
202
|
+
agentActivityStatusRecent: "chatFirstAgentActivityStatusRecent",
|
|
203
|
+
agentActivityStatusUnknown: "chatFirstAgentActivityStatusUnknown",
|
|
204
|
+
watchingSession: "chatFirstWatchingSession",
|
|
205
|
+
session: "chatFirstSession",
|
|
206
|
+
stopWatchingSession: "chatFirstStopWatchingSession",
|
|
207
|
+
stopWatching: "chatFirstStopWatching",
|
|
208
|
+
watchedSession: "chatFirstWatchedSession",
|
|
209
|
+
agentsTitle: "chatFirstAgentsTitle",
|
|
210
|
+
};
|
|
211
|
+
const DISPATCH_CHAT_FIRST_SURFACE_COPY_KEYS = {
|
|
212
|
+
browser: {
|
|
213
|
+
label: "chatFirstSurfaceBrowserLabel",
|
|
214
|
+
reason: "chatFirstSurfaceBrowserReason",
|
|
215
|
+
},
|
|
216
|
+
terminal: {
|
|
217
|
+
label: "chatFirstSurfaceTerminalLabel",
|
|
218
|
+
reason: "chatFirstSurfaceTerminalReason",
|
|
219
|
+
},
|
|
220
|
+
files: {
|
|
221
|
+
label: "chatFirstSurfaceFilesLabel",
|
|
222
|
+
reason: "chatFirstSurfaceFilesReason",
|
|
223
|
+
},
|
|
224
|
+
diff: {
|
|
225
|
+
label: "chatFirstSurfaceDiffLabel",
|
|
226
|
+
reason: "chatFirstSurfaceDiffReason",
|
|
227
|
+
},
|
|
228
|
+
"side-chat": {
|
|
229
|
+
label: "chatFirstSurfaceSideChatLabel",
|
|
230
|
+
reason: "chatFirstSurfaceSideChatReason",
|
|
231
|
+
},
|
|
232
|
+
agents: {
|
|
233
|
+
label: "chatFirstSurfaceAgentsLabel",
|
|
234
|
+
reason: "chatFirstSurfaceAgentsReason",
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
function createDispatchChatFirstCopy(t) {
|
|
238
|
+
return (key, values) => {
|
|
239
|
+
if (key.startsWith("surface.")) {
|
|
240
|
+
const [, kind, field] = key.split(".");
|
|
241
|
+
const surface = DISPATCH_CHAT_FIRST_SURFACE_COPY_KEYS[kind];
|
|
242
|
+
const translationKey = surface && (field === "label" || field === "reason")
|
|
243
|
+
? surface[field]
|
|
244
|
+
: undefined;
|
|
245
|
+
if (translationKey) {
|
|
246
|
+
return t(`dispatch.pages.${translationKey}`, {
|
|
247
|
+
...(values ?? {}),
|
|
248
|
+
defaultValue: defaultChatFirstCopy(key, values),
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const translationKey = DISPATCH_CHAT_FIRST_COPY_KEYS[key];
|
|
253
|
+
if (!translationKey)
|
|
254
|
+
return defaultChatFirstCopy(key, values);
|
|
255
|
+
return t(`dispatch.pages.${translationKey}`, {
|
|
256
|
+
...(values ?? {}),
|
|
257
|
+
defaultValue: defaultChatFirstCopy(key, values),
|
|
258
|
+
});
|
|
259
|
+
};
|
|
260
|
+
}
|
|
123
261
|
function chatThreadPath(threadId) {
|
|
124
|
-
return `/chat/${encodeURIComponent(threadId)}
|
|
262
|
+
return threadId ? `/chat/${encodeURIComponent(threadId)}` : "/chat";
|
|
263
|
+
}
|
|
264
|
+
function persistedChatFirstPane(value) {
|
|
265
|
+
if (!value || typeof value !== "object")
|
|
266
|
+
return null;
|
|
267
|
+
const record = value;
|
|
268
|
+
if (typeof record.appId !== "string" || !record.appId.trim())
|
|
269
|
+
return null;
|
|
270
|
+
return {
|
|
271
|
+
appId: record.appId,
|
|
272
|
+
...(typeof record.path === "string" ? { path: record.path } : {}),
|
|
273
|
+
...(typeof record.view === "string" ? { view: record.view } : {}),
|
|
274
|
+
};
|
|
125
275
|
}
|
|
126
276
|
function threadIdFromPath(pathname) {
|
|
127
277
|
const match = pathname.match(/^\/chat\/([^/]+)/);
|
|
@@ -185,8 +335,9 @@ function threadUpdatedAt(thread) {
|
|
|
185
335
|
? thread.createdAt
|
|
186
336
|
: 0;
|
|
187
337
|
}
|
|
188
|
-
function DispatchChatsSection({ onNavigate }) {
|
|
338
|
+
function DispatchChatsSection({ onNavigate, showNewChat = false, prelude, chatFirstMode = false, chatFirstEmbedded = false, chatFirstNavigation, }) {
|
|
189
339
|
const t = useT();
|
|
340
|
+
const chatFirstCopy = useMemo(() => createDispatchChatFirstCopy(t), [t]);
|
|
190
341
|
const navigate = useNavigate();
|
|
191
342
|
const location = useLocation();
|
|
192
343
|
const [includeExternal, setIncludeExternal] = useState(false);
|
|
@@ -266,7 +417,7 @@ function DispatchChatsSection({ onNavigate }) {
|
|
|
266
417
|
if (threadId)
|
|
267
418
|
openThread(threadId, { isNew: true });
|
|
268
419
|
}
|
|
269
|
-
return (_jsxs("div", { className: "ms-4 min-w-0 space-y-0.5", children: [_jsx("div", { className: "flex justify-end px-2 pt-0.5", children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "data-dispatch-chat-source-toggle": true, "aria-pressed": includeExternal, "aria-label": includeExternal
|
|
420
|
+
return (_jsxs("div", { className: cn("ms-4 min-w-0 space-y-0.5", showNewChat && "dispatch-chat-first-chats"), children: [showNewChat && chatFirstNavigation ? (_jsx("nav", { className: "space-y-0.5 px-2 py-2", children: _jsx(ChatFirstPrimaryNavigation, { copy: chatFirstCopy, onNewChat: () => void handleNewChat(), onOpenIntegrations: chatFirstNavigation.onOpenIntegrations, onOpenScheduled: chatFirstNavigation.onOpenScheduled, onSearch: openCommandMenu }) })) : null, prelude, !chatFirstMode ? (_jsx("div", { className: "flex justify-end px-2 pt-0.5", children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "data-dispatch-chat-source-toggle": true, "aria-pressed": includeExternal, "aria-label": includeExternal
|
|
270
421
|
? t("dispatch.sidebar.showLocalChats", {
|
|
271
422
|
defaultValue: "Show local chats",
|
|
272
423
|
})
|
|
@@ -278,9 +429,33 @@ function DispatchChatsSection({ onNavigate }) {
|
|
|
278
429
|
})
|
|
279
430
|
: t("dispatch.sidebar.showAllChats", {
|
|
280
431
|
defaultValue: "Show all chats",
|
|
281
|
-
}) })] }) }),
|
|
432
|
+
}) })] }) })) : null, !chatFirstMode &&
|
|
433
|
+
chatsLoading &&
|
|
282
434
|
visibleThreads.length === 0 &&
|
|
283
|
-
Array.from({ length: 3 }).map((_, index) => (_jsxs("div", { className: "flex items-center gap-2 px-3 py-1", children: [_jsx(Skeleton, { className: "size-3.5 shrink-0 rounded-sm" }), _jsx(Skeleton, { className: "h-3 w-3/4 rounded" })] }, `chat-skeleton-${index}`))), _jsx(
|
|
435
|
+
Array.from({ length: 3 }).map((_, index) => (_jsxs("div", { className: "flex items-center gap-2 px-3 py-1", children: [_jsx(Skeleton, { className: "size-3.5 shrink-0 rounded-sm" }), _jsx(Skeleton, { className: "h-3 w-3/4 rounded" })] }, `chat-skeleton-${index}`))), chatFirstMode ? (_jsx(ChatFirstChatHistory, { items: chatItems, activeId: displayedActiveThreadId, loading: chatsLoading && visibleThreads.length === 0, loadingLabel: _jsx("div", { className: "space-y-1 px-2 py-1", children: [0, 1, 2].map((index) => (_jsxs("div", { className: "flex items-center gap-2 px-1 py-1", children: [_jsx(Skeleton, { className: "size-3.5 shrink-0 rounded-sm" }), _jsx(Skeleton, { className: "h-3 w-3/4 rounded" })] }, index))) }), label: t("dispatch.sidebar.chats", { defaultValue: "Chats" }), onSelect: (threadId) => openThread(threadId), renameMaxLength: 160, onRename: (threadId, title) => void renameThread(threadId, title), labels: {
|
|
436
|
+
options: (item) => t("dispatch.sidebar.chatOptions", {
|
|
437
|
+
title: item.titleText ?? "",
|
|
438
|
+
}),
|
|
439
|
+
renameInput: (item) => t("dispatch.sidebar.renameThread", {
|
|
440
|
+
title: item.titleText ?? "",
|
|
441
|
+
}),
|
|
442
|
+
rename: t("dispatch.sidebar.renameChat"),
|
|
443
|
+
}, renderAdditionalRowActions: (item, closeMenu) => (_jsxs(_Fragment, { children: [_jsxs("button", { type: "button", role: "menuitem", className: "an-chat-history-row__menu-item", onClick: () => {
|
|
444
|
+
closeMenu();
|
|
445
|
+
void writeClipboardText(item.id).then((copied) => {
|
|
446
|
+
toast[copied ? "success" : "error"](copied
|
|
447
|
+
? "Session ID copied"
|
|
448
|
+
: "Could not copy the session ID");
|
|
449
|
+
});
|
|
450
|
+
}, children: [_jsx(IconCopy, { size: 13, strokeWidth: 1.8 }), _jsx("span", { children: "Copy session ID" })] }), !chatFirstEmbedded ? (_jsxs("button", { type: "button", role: "menuitem", className: "an-chat-history-row__menu-item", onClick: () => {
|
|
451
|
+
closeMenu();
|
|
452
|
+
emitChatFirstSessionWatch({
|
|
453
|
+
sessionId: item.id,
|
|
454
|
+
title: item.titleText,
|
|
455
|
+
kind: "agent-chat",
|
|
456
|
+
sourceSessionId: displayedActiveThreadId ?? undefined,
|
|
457
|
+
});
|
|
458
|
+
}, children: [_jsx(IconEye, { size: 13, strokeWidth: 1.8 }), _jsx("span", { children: "Watch and message session" })] })) : null] })), className: "min-w-0" })) : (_jsx(ChatHistoryRail, { items: chatItems, activeId: displayedActiveThreadId, onSelect: (threadId) => openThread(threadId), onNewChat: () => void handleNewChat(), railLabels: {
|
|
284
459
|
newChat: t("dispatch.sidebar.newChat"),
|
|
285
460
|
showMore: t("dispatch.sidebar.chats"),
|
|
286
461
|
showLess: t("dispatch.sidebar.chats"),
|
|
@@ -292,10 +467,26 @@ function DispatchChatsSection({ onNavigate }) {
|
|
|
292
467
|
title: item.titleText ?? "",
|
|
293
468
|
}),
|
|
294
469
|
rename: t("dispatch.sidebar.renameChat"),
|
|
295
|
-
}, className: "
|
|
470
|
+
}, renderAdditionalRowActions: (item, closeMenu) => (_jsxs(_Fragment, { children: [_jsxs("button", { type: "button", role: "menuitem", className: "an-chat-history-row__menu-item", onClick: () => {
|
|
471
|
+
closeMenu();
|
|
472
|
+
void writeClipboardText(item.id).then((copied) => {
|
|
473
|
+
toast[copied ? "success" : "error"](copied
|
|
474
|
+
? "Session ID copied"
|
|
475
|
+
: "Could not copy the session ID");
|
|
476
|
+
});
|
|
477
|
+
}, children: [_jsx(IconCopy, { size: 13, strokeWidth: 1.8 }), _jsx("span", { children: "Copy session ID" })] }), chatFirstMode && !chatFirstEmbedded ? (_jsxs("button", { type: "button", role: "menuitem", className: "an-chat-history-row__menu-item", onClick: () => {
|
|
478
|
+
closeMenu();
|
|
479
|
+
emitChatFirstSessionWatch({
|
|
480
|
+
sessionId: item.id,
|
|
481
|
+
title: item.titleText,
|
|
482
|
+
kind: "agent-chat",
|
|
483
|
+
sourceSessionId: displayedActiveThreadId ?? undefined,
|
|
484
|
+
});
|
|
485
|
+
}, children: [_jsx(IconEye, { size: 13, strokeWidth: 1.8 }), _jsx("span", { children: "Watch and message session" })] })) : null] })), className: "min-w-0" }))] }));
|
|
296
486
|
}
|
|
297
|
-
export function NavContent({ onNavigate, extensions, collapsed = false, collapsible = false, onCollapsedChange, }) {
|
|
487
|
+
export function NavContent({ onNavigate, extensions, chatFirstMode = false, chatFirstEmbedded = false, collapsed = false, collapsible = false, onCollapsedChange, chatFirstAppLayout, onChatFirstAppLayoutChange, chatFirstApps = [], chatFirstAppsLoading = false, chatFirstAppsError, chatFirstActiveAppId, onChatFirstAppOpen, onChatFirstAppsRetry, }) {
|
|
298
488
|
const t = useT();
|
|
489
|
+
const chatFirstCopy = useMemo(() => createDispatchChatFirstCopy(t), [t]);
|
|
299
490
|
const location = useLocation();
|
|
300
491
|
const navigate = useNavigate();
|
|
301
492
|
const extensionNavItems = extensions?.navItems ?? EMPTY_NAV_ITEMS;
|
|
@@ -317,6 +508,11 @@ export function NavContent({ onNavigate, extensions, collapsed = false, collapsi
|
|
|
317
508
|
: t("sidebar.collapseSidebar"), className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-sidebar-foreground/65 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", children: collapsed ? (_jsx(IconLayoutSidebarLeftExpand, { className: "h-4 w-4 rtl:-scale-x-100" })) : (_jsx(IconLayoutSidebarLeftCollapse, { className: "h-4 w-4 rtl:-scale-x-100" })) }) }), _jsx(TooltipContent, { side: "right", children: collapsed ? t("sidebar.expandSidebar") : t("sidebar.collapseSidebar") })] })) : null;
|
|
318
509
|
const searchButton = (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: openCommandMenu, "aria-label": t("sidebar.search"), className: "flex h-8 w-8 items-center justify-center rounded-md text-sidebar-foreground/65 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", children: _jsx(IconSearch, { className: "h-4 w-4" }) }) }), _jsx(TooltipContent, { side: "right", children: t("sidebar.search") })] }));
|
|
319
510
|
const feedbackButton = (_jsx(FeedbackButton, { variant: collapsed ? "icon" : "sidebar", side: "right", className: collapsed ? "size-8" : "min-w-0" }));
|
|
511
|
+
const chatFirstCreateAppTrigger = (_jsx(CreateAppPopover, { align: "start", trigger: _jsx("button", { type: "button", className: "flex size-6 items-center justify-center rounded text-sidebar-foreground/55 hover:bg-sidebar-accent hover:text-sidebar-foreground", "aria-label": chatFirstCopy("createWorkspaceApp"), title: chatFirstCopy("createWorkspaceApp"), children: _jsx(IconPlus, { size: 14, "aria-hidden": "true" }) }) }));
|
|
512
|
+
const chatFirstAppsRail = (_jsx(ChatFirstAppsRail, { apps: chatFirstApps, activeAppId: chatFirstActiveAppId, collapsed: collapsed, loading: chatFirstAppsLoading, error: chatFirstAppsError, layout: chatFirstAppLayout, onLayoutChange: onChatFirstAppLayoutChange, onRetry: onChatFirstAppsRetry, onOpenApp: (app) => {
|
|
513
|
+
onChatFirstAppOpen?.(app);
|
|
514
|
+
onNavigate?.();
|
|
515
|
+
}, createAppTrigger: chatFirstCreateAppTrigger, renderIcon: (app) => (_jsx(AppIcon, { id: app.id, name: app.name, size: "sm", className: "size-5 rounded-md" })), copy: chatFirstCopy }));
|
|
320
516
|
const renderNavItem = (item) => {
|
|
321
517
|
const Icon = item.icon;
|
|
322
518
|
const itemMatchesLocalPath = navItemMatchesPath(item, localPathname);
|
|
@@ -334,7 +530,7 @@ export function NavContent({ onNavigate, extensions, collapsed = false, collapsi
|
|
|
334
530
|
return;
|
|
335
531
|
}
|
|
336
532
|
onNavigate?.();
|
|
337
|
-
}, "aria-label": label, className: cn("flex size-9 items-center justify-center rounded-md text-sm", itemMatchesLocalPath
|
|
533
|
+
}, "aria-label": label, "aria-current": itemMatchesLocalPath ? "page" : undefined, className: cn("flex size-9 items-center justify-center rounded-md text-sm", itemMatchesLocalPath
|
|
338
534
|
? "bg-sidebar-accent font-medium text-sidebar-accent-foreground"
|
|
339
535
|
: "text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"), children: Icon ? (_jsx(Icon, { size: 16, className: "shrink-0" })) : (_jsx("span", { className: "h-4 w-4 shrink-0", "aria-hidden": "true" })) }) }), _jsx(TooltipContent, { side: "right", children: label })] })) : (_jsxs(Link, { to: dispatchNavLinkTarget(item.to), onClick: (event) => {
|
|
340
536
|
if (item.id === "chat" &&
|
|
@@ -349,11 +545,20 @@ export function NavContent({ onNavigate, extensions, collapsed = false, collapsi
|
|
|
349
545
|
return;
|
|
350
546
|
}
|
|
351
547
|
onNavigate?.();
|
|
352
|
-
}, className: cn("flex h-8 w-full items-center gap-2 rounded-md px-2 text-sm", itemMatchesLocalPath
|
|
548
|
+
}, "aria-current": itemMatchesLocalPath ? "page" : undefined, className: cn("flex h-8 w-full items-center gap-2 rounded-md px-2 text-sm", itemMatchesLocalPath
|
|
353
549
|
? "bg-sidebar-accent font-medium text-sidebar-accent-foreground"
|
|
354
|
-
: "text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"), children: [Icon ? (_jsx(Icon, { size: 16, className: "shrink-0" })) : (_jsx("span", { className: "h-4 w-4 shrink-0", "aria-hidden": "true" })), _jsx("span", { className: "truncate", children: label })] })), !collapsed && item.id === "chat" && itemMatchesLocalPath ? (_jsx(DispatchChatsSection, { onNavigate: onNavigate })) : null] }, item.id));
|
|
550
|
+
: "text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"), children: [Icon ? (_jsx(Icon, { size: 16, className: "shrink-0" })) : (_jsx("span", { className: "h-4 w-4 shrink-0", "aria-hidden": "true" })), _jsx("span", { className: "truncate", children: label })] })), !collapsed && item.id === "chat" && itemMatchesLocalPath ? (_jsx(DispatchChatsSection, { onNavigate: onNavigate, chatFirstMode: chatFirstMode, chatFirstEmbedded: chatFirstEmbedded })) : null] }, item.id));
|
|
355
551
|
};
|
|
356
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { className: cn("flex h-12 shrink-0 items-center border-b border-sidebar-border", collapsed ? "justify-center px-0" : "px-4"), children: _jsxs("div", { className: cn("flex items-center", collapsed ? "justify-center" : "gap-2"), children: [_jsx("img", { src: appPath("/agent-native-icon-light.svg"), alt: "", "aria-hidden": "true", width: 35, height: 20, className: cn("block shrink-0 object-contain object-center dark:hidden", collapsed ? "h-4 w-7" : "h-5 w-[35px]") }), _jsx("img", { src: appPath("/agent-native-icon-dark.svg"), alt: "", "aria-hidden": "true", width: 35, height: 20, className: cn("hidden shrink-0 object-contain object-center dark:block", collapsed ? "h-4 w-7" : "h-5 w-[35px]") }), !collapsed && (_jsx("div", { className: "min-w-0 flex-1", children: _jsx("div", { "data-dispatch-sidebar-label": true, className: "truncate text-lg font-bold tracking-tight text-foreground", children: DISPATCH_SIDEBAR_LABEL }) }))] }) }),
|
|
552
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: cn("flex h-12 shrink-0 items-center border-b border-sidebar-border", collapsed ? "justify-center px-0" : "px-4"), children: _jsxs("div", { className: cn("flex items-center", collapsed ? "justify-center" : "gap-2"), children: [_jsx("img", { src: appPath("/agent-native-icon-light.svg"), alt: "", "aria-hidden": "true", width: 35, height: 20, className: cn("block shrink-0 object-contain object-center dark:hidden", collapsed ? "h-4 w-7" : "h-5 w-[35px]") }), _jsx("img", { src: appPath("/agent-native-icon-dark.svg"), alt: "", "aria-hidden": "true", width: 35, height: 20, className: cn("hidden shrink-0 object-contain object-center dark:block", collapsed ? "h-4 w-7" : "h-5 w-[35px]") }), !collapsed && (_jsx("div", { className: "min-w-0 flex-1", children: _jsx("div", { "data-dispatch-sidebar-label": true, className: "truncate text-lg font-bold tracking-tight text-foreground", children: DISPATCH_SIDEBAR_LABEL }) }))] }) }), chatFirstMode ? (_jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-y-auto", children: !collapsed ? (_jsx(DispatchChatsSection, { onNavigate: onNavigate, showNewChat: true, chatFirstMode: true, chatFirstEmbedded: chatFirstEmbedded, chatFirstNavigation: {
|
|
553
|
+
onOpenIntegrations: () => {
|
|
554
|
+
navigate(dispatchNavLinkTarget("/admin/integrations"));
|
|
555
|
+
onNavigate?.();
|
|
556
|
+
},
|
|
557
|
+
onOpenScheduled: () => {
|
|
558
|
+
navigate(dispatchNavLinkTarget("/admin/automations"));
|
|
559
|
+
onNavigate?.();
|
|
560
|
+
},
|
|
561
|
+
}, prelude: chatFirstAppsRail })) : (chatFirstAppsRail) })) : null, _jsxs("div", { className: cn("flex min-h-0 flex-1 flex-col overflow-y-auto", chatFirstMode && "hidden"), children: [_jsx("nav", { className: cn("py-2", collapsed ? "px-1.5" : "px-2"), children: _jsx("ul", { className: cn(collapsed ? "flex flex-col items-center gap-1" : "space-y-0.5"), children: primaryNavItems.map(renderNavItem) }) }), _jsxs("div", { className: "mt-auto shrink-0", children: [_jsx("nav", { className: cn("py-1", collapsed ? "px-1.5" : "px-2"), children: _jsx("ul", { className: cn(collapsed ? "flex flex-col items-center gap-1" : "space-y-0.5"), children: BOTTOM_NAV_ITEMS.map(renderNavItem) }) }), _jsx("div", { className: cn("py-2", collapsed ? "flex justify-center px-1" : "px-3"), children: _jsx(OrgSwitcher, { compact: collapsed, reserveSpace: true }) })] }), _jsx(SidebarFooterActions, { collapsed: collapsed, feedback: feedbackButton, search: searchButton, collapse: collapseButton })] }), chatFirstMode && collapsed ? (_jsx("div", { className: "mt-auto shrink-0", children: _jsx(SidebarFooterActions, { collapsed: true, feedback: feedbackButton, search: searchButton, collapse: collapseButton }) })) : null] }));
|
|
357
562
|
}
|
|
358
563
|
export function Layout({ children, extensions, agentPageHref, }) {
|
|
359
564
|
const t = useT();
|
|
@@ -372,7 +577,181 @@ export function Layout({ children, extensions, agentPageHref, }) {
|
|
|
372
577
|
});
|
|
373
578
|
const localPathname = localDispatchPath(location.pathname);
|
|
374
579
|
const isChatRoute = localPathname === "/chat" || localPathname.startsWith("/chat/");
|
|
580
|
+
const chatFirstSurfaceScope = threadIdFromPath(localPathname) ?? "new";
|
|
375
581
|
const isWorkspaceAppHostRoute = localPathname.startsWith("/apps/");
|
|
582
|
+
const [chatFirstPreference, setChatFirstPreference] = useState(() => readChatFirstMode());
|
|
583
|
+
const chatFirstEmbedded = typeof window !== "undefined" &&
|
|
584
|
+
new URLSearchParams(window.location.search).get("chatFirst") === "1";
|
|
585
|
+
const chatFirstMode = extensions?.chatFirst === true || chatFirstPreference || chatFirstEmbedded;
|
|
586
|
+
const [chatFirstAppLayout, setChatFirstAppLayout] = useState(() => readChatFirstAppLayout());
|
|
587
|
+
const chatFirstAppLayoutHydratedRef = useRef(false);
|
|
588
|
+
const chatFirstAppsQuery = useActionQuery("list-workspace-apps", { includeAgentCards: false }, { enabled: chatFirstMode && isChatRoute });
|
|
589
|
+
const chatFirstWorkspaceApps = useMemo(() => mergeChatFirstWorkspaceApps(chatFirstAppsQuery.data), [chatFirstAppsQuery.data]);
|
|
590
|
+
const chatFirstAppRegistrations = useMemo(() => chatFirstWorkspaceApps.map((app) => ({
|
|
591
|
+
id: app.id,
|
|
592
|
+
name: app.name,
|
|
593
|
+
path: app.path,
|
|
594
|
+
url: app.url,
|
|
595
|
+
enabled: app.status !== "pending" && app.archived !== true,
|
|
596
|
+
})), [chatFirstWorkspaceApps]);
|
|
597
|
+
const chatFirstAppItems = useMemo(() => chatFirstWorkspaceApps.map((app) => ({
|
|
598
|
+
id: app.id,
|
|
599
|
+
name: app.name,
|
|
600
|
+
})), [chatFirstWorkspaceApps]);
|
|
601
|
+
const chatFirstCopy = useMemo(() => createDispatchChatFirstCopy(t), [t]);
|
|
602
|
+
const createChatFirstEmbedSession = useActionMutation("create_embed_session", { skipActionQueryInvalidation: true });
|
|
603
|
+
const [chatFirstPane, setChatFirstPane] = useState(null);
|
|
604
|
+
const [chatFirstEmbedUrl, setChatFirstEmbedUrl] = useState(null);
|
|
605
|
+
const [chatFirstEmbedError, setChatFirstEmbedError] = useState(null);
|
|
606
|
+
const [chatFirstEmbedAttempt, setChatFirstEmbedAttempt] = useState(0);
|
|
607
|
+
const [chatFirstNotice, setChatFirstNotice] = useState(null);
|
|
608
|
+
const chatFirstSessionWatch = useChatFirstSessionWatch();
|
|
609
|
+
const chatFirstSurfaceTabs = useChatFirstSurfaceTabs(chatFirstSurfaceScope);
|
|
610
|
+
const chatFirstSurfaceTabsStore = getChatFirstSurfaceTabsStore(chatFirstSurfaceScope);
|
|
611
|
+
const chatFirstAgentsQuery = useActionQuery("search-agent-threads", { sourceId: "current", limit: 12 }, {
|
|
612
|
+
enabled: chatFirstMode &&
|
|
613
|
+
isChatRoute &&
|
|
614
|
+
chatFirstSurfaceTabs.activeTabId?.startsWith("agents:") === true,
|
|
615
|
+
});
|
|
616
|
+
const chatFirstSurfacePanel = useChatFirstSurfacePanel(chatFirstSurfaceScope);
|
|
617
|
+
const { setOpen: setChatFirstSurfacePanelOpen } = chatFirstSurfacePanel;
|
|
618
|
+
const chatFirstSurfaceResize = useChatFirstSurfaceResize(chatFirstSurfaceScope);
|
|
619
|
+
const chatFirstPaneHydratedRef = useRef(false);
|
|
620
|
+
const pendingChatFirstOpenAppRef = useRef(null);
|
|
621
|
+
const previousChatFirstSurfaceScopeRef = useRef(chatFirstSurfaceScope);
|
|
622
|
+
const previousChatFirstSurfaceTabCountRef = useRef(null);
|
|
623
|
+
const activeChatFirstSurfaceTab = useMemo(() => chatFirstSurfaceTabs.tabs.find((tab) => tab.id === chatFirstSurfaceTabs.activeTabId) ?? null, [chatFirstSurfaceTabs]);
|
|
624
|
+
const activeChatFirstApp = useMemo(() => activeChatFirstSurfaceTab?.kind === "app" &&
|
|
625
|
+
activeChatFirstSurfaceTab.appId
|
|
626
|
+
? (chatFirstWorkspaceApps.find((app) => app.id === activeChatFirstSurfaceTab.appId) ?? null)
|
|
627
|
+
: null, [activeChatFirstSurfaceTab, chatFirstWorkspaceApps]);
|
|
628
|
+
const chatFirstAgentActivities = useMemo(() => (chatFirstAgentsQuery.data?.threads ?? []).map((thread) => ({
|
|
629
|
+
sessionId: thread.id,
|
|
630
|
+
title: thread.title || chatFirstCopy("agentsTitle", { name: thread.id }),
|
|
631
|
+
subtitle: thread.snippet || thread.preview || chatFirstCopy("session"),
|
|
632
|
+
status: "recent",
|
|
633
|
+
...(thread.updatedAt ? { updatedAt: thread.updatedAt } : {}),
|
|
634
|
+
})), [chatFirstAgentsQuery.data, chatFirstCopy]);
|
|
635
|
+
const chatFirstEmbedPath = activeChatFirstSurfaceTab?.kind === "app"
|
|
636
|
+
? (activeChatFirstSurfaceTab.path ??
|
|
637
|
+
chatFirstPane?.path ??
|
|
638
|
+
activeChatFirstApp?.path)
|
|
639
|
+
: null;
|
|
640
|
+
useEffect(() => {
|
|
641
|
+
if (!chatFirstMode || !isChatRoute || !activeChatFirstApp) {
|
|
642
|
+
setChatFirstEmbedUrl(null);
|
|
643
|
+
setChatFirstEmbedError(null);
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
if (!chatFirstEmbedPath?.startsWith("/")) {
|
|
647
|
+
setChatFirstEmbedUrl(null);
|
|
648
|
+
setChatFirstEmbedError(chatFirstCopy("appUnavailable"));
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
let cancelled = false;
|
|
652
|
+
setChatFirstEmbedUrl(null);
|
|
653
|
+
setChatFirstEmbedError(null);
|
|
654
|
+
void createChatFirstEmbedSession
|
|
655
|
+
.mutateAsync(buildChatFirstEmbedSessionInput(activeChatFirstApp.id, chatFirstEmbedPath))
|
|
656
|
+
.then((result) => {
|
|
657
|
+
if (!cancelled)
|
|
658
|
+
setChatFirstEmbedUrl(result.startUrl);
|
|
659
|
+
})
|
|
660
|
+
.catch((cause) => {
|
|
661
|
+
if (!cancelled) {
|
|
662
|
+
setChatFirstEmbedError(cause instanceof Error
|
|
663
|
+
? cause.message
|
|
664
|
+
: chatFirstCopy("appUnavailable"));
|
|
665
|
+
}
|
|
666
|
+
});
|
|
667
|
+
return () => {
|
|
668
|
+
cancelled = true;
|
|
669
|
+
};
|
|
670
|
+
}, [
|
|
671
|
+
activeChatFirstApp,
|
|
672
|
+
chatFirstCopy,
|
|
673
|
+
chatFirstEmbedAttempt,
|
|
674
|
+
chatFirstEmbedPath,
|
|
675
|
+
chatFirstMode,
|
|
676
|
+
createChatFirstEmbedSession.mutateAsync,
|
|
677
|
+
isChatRoute,
|
|
678
|
+
]);
|
|
679
|
+
const persistChatFirstPane = useCallback((pane) => {
|
|
680
|
+
setChatFirstPane(pane);
|
|
681
|
+
void writeClientAppState(CHAT_FIRST_PANE_STATE_KEY, pane).catch(() => {
|
|
682
|
+
setChatFirstNotice("The app pane opened locally, but its focus could not be synced.");
|
|
683
|
+
});
|
|
684
|
+
}, []);
|
|
685
|
+
const openChatFirstPane = useCallback((pane) => {
|
|
686
|
+
setChatFirstNotice(null);
|
|
687
|
+
closeChatFirstSessionWatch();
|
|
688
|
+
const app = chatFirstAppRegistrations.find((candidate) => candidate.id === pane.appId);
|
|
689
|
+
chatFirstSurfaceTabsStore.open({
|
|
690
|
+
id: chatFirstSurfaceTabId("app", `${pane.appId}:${pane.path ?? pane.view ?? "/"}`),
|
|
691
|
+
kind: "app",
|
|
692
|
+
title: app?.name ?? pane.appId,
|
|
693
|
+
appId: pane.appId,
|
|
694
|
+
...(pane.path ? { path: pane.path } : {}),
|
|
695
|
+
...(pane.view ? { view: pane.view } : {}),
|
|
696
|
+
});
|
|
697
|
+
persistChatFirstPane(pane);
|
|
698
|
+
}, [
|
|
699
|
+
chatFirstAppRegistrations,
|
|
700
|
+
chatFirstSurfaceTabsStore,
|
|
701
|
+
persistChatFirstPane,
|
|
702
|
+
]);
|
|
703
|
+
const openChatFirstSurface = useCallback((kind) => {
|
|
704
|
+
if (kind !== "agents")
|
|
705
|
+
return;
|
|
706
|
+
persistChatFirstPane(null);
|
|
707
|
+
closeChatFirstSessionWatch();
|
|
708
|
+
chatFirstSurfaceTabsStore.open({
|
|
709
|
+
id: chatFirstSurfaceTabId("agents", "activity"),
|
|
710
|
+
kind: "agents",
|
|
711
|
+
title: "Agents",
|
|
712
|
+
});
|
|
713
|
+
}, [chatFirstSurfaceTabsStore, persistChatFirstPane]);
|
|
714
|
+
const resolveChatFirstOpenBrowser = useCallback((detail) => {
|
|
715
|
+
const resolution = resolveChatFirstBrowserTarget(detail);
|
|
716
|
+
if (resolution.status === "unresolved") {
|
|
717
|
+
setChatFirstNotice(chatFirstBrowserResolutionMessage(resolution.reason));
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
persistChatFirstPane(null);
|
|
721
|
+
closeChatFirstSessionWatch();
|
|
722
|
+
setChatFirstNotice(null);
|
|
723
|
+
chatFirstSurfaceTabsStore.open({
|
|
724
|
+
id: chatFirstSurfaceTabId("browser", resolution.target.url),
|
|
725
|
+
kind: "browser",
|
|
726
|
+
title: resolution.target.title ?? "Browser",
|
|
727
|
+
url: resolution.target.url,
|
|
728
|
+
});
|
|
729
|
+
}, [chatFirstSurfaceTabsStore, persistChatFirstPane]);
|
|
730
|
+
const resolveChatFirstOpenApp = useCallback((detail) => {
|
|
731
|
+
if (chatFirstAppsQuery.isLoading) {
|
|
732
|
+
pendingChatFirstOpenAppRef.current = detail;
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
if (chatFirstAppsQuery.isError) {
|
|
736
|
+
pendingChatFirstOpenAppRef.current = null;
|
|
737
|
+
setChatFirstNotice("Workspace apps could not be loaded, so the requested app was not opened.");
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
const resolution = resolveChatFirstAppTarget(detail, chatFirstAppRegistrations, {
|
|
741
|
+
currentOrigin: typeof window === "undefined" ? undefined : window.location.origin,
|
|
742
|
+
});
|
|
743
|
+
pendingChatFirstOpenAppRef.current = null;
|
|
744
|
+
if (resolution.status === "unresolved") {
|
|
745
|
+
setChatFirstNotice(chatFirstResolutionMessage(resolution.reason));
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
openChatFirstPane(resolution.target);
|
|
749
|
+
}, [
|
|
750
|
+
chatFirstAppRegistrations,
|
|
751
|
+
chatFirstAppsQuery.isError,
|
|
752
|
+
chatFirstAppsQuery.isLoading,
|
|
753
|
+
openChatFirstPane,
|
|
754
|
+
]);
|
|
376
755
|
const sidebarBeforeAppRef = useRef(null);
|
|
377
756
|
const sidebarAutoCollapsedRef = useRef(false);
|
|
378
757
|
const chatHomeHandoffActive = useAgentChatHomeHandoff({
|
|
@@ -386,6 +765,194 @@ export function Layout({ children, extensions, agentPageHref, }) {
|
|
|
386
765
|
requireActiveHandoff: true,
|
|
387
766
|
};
|
|
388
767
|
useAgentChatHomeHandoffLinks(chatHandoffLinkOptions);
|
|
768
|
+
useEffect(() => {
|
|
769
|
+
const handleModeChange = (event) => {
|
|
770
|
+
const enabled = event.detail
|
|
771
|
+
?.enabled;
|
|
772
|
+
setChatFirstPreference(enabled === true);
|
|
773
|
+
};
|
|
774
|
+
window.addEventListener(CHAT_FIRST_MODE_CHANGED_EVENT, handleModeChange);
|
|
775
|
+
return () => window.removeEventListener(CHAT_FIRST_MODE_CHANGED_EVENT, handleModeChange);
|
|
776
|
+
}, []);
|
|
777
|
+
useEffect(() => {
|
|
778
|
+
if (!chatFirstMode ||
|
|
779
|
+
!isChatRoute ||
|
|
780
|
+
chatFirstAppLayoutHydratedRef.current) {
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
chatFirstAppLayoutHydratedRef.current = true;
|
|
784
|
+
void readClientAppState("chat-first-app-layout")
|
|
785
|
+
.then((value) => {
|
|
786
|
+
if (!value || typeof value !== "object")
|
|
787
|
+
return;
|
|
788
|
+
const candidate = value;
|
|
789
|
+
const ids = (input) => Array.isArray(input)
|
|
790
|
+
? input.filter((id) => typeof id === "string" && id.trim().length > 0)
|
|
791
|
+
: [];
|
|
792
|
+
setChatFirstAppLayout({
|
|
793
|
+
pinnedIds: [...new Set(ids(candidate.pinnedIds))],
|
|
794
|
+
orderedIds: [...new Set(ids(candidate.orderedIds))],
|
|
795
|
+
});
|
|
796
|
+
})
|
|
797
|
+
.catch(() => {
|
|
798
|
+
// Device-local layout remains the fallback when workspace state is unavailable.
|
|
799
|
+
});
|
|
800
|
+
}, [chatFirstMode, isChatRoute]);
|
|
801
|
+
const persistChatFirstAppLayout = useCallback((layout) => {
|
|
802
|
+
setChatFirstAppLayout(layout);
|
|
803
|
+
void writeClientAppState("chat-first-app-layout", layout).catch(() => {
|
|
804
|
+
setChatFirstNotice("App order changed locally, but workspace state could not be synced.");
|
|
805
|
+
});
|
|
806
|
+
}, []);
|
|
807
|
+
useEffect(() => {
|
|
808
|
+
if (!chatFirstMode || !isChatRoute) {
|
|
809
|
+
setChatFirstPane(null);
|
|
810
|
+
closeChatFirstSessionWatch();
|
|
811
|
+
chatFirstSurfaceTabsStore.closeAll();
|
|
812
|
+
setChatFirstNotice(null);
|
|
813
|
+
pendingChatFirstOpenAppRef.current = null;
|
|
814
|
+
chatFirstPaneHydratedRef.current = false;
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
const unsubscribeApp = subscribeChatFirstOpenApp(resolveChatFirstOpenApp);
|
|
818
|
+
const unsubscribeBrowser = subscribeChatFirstOpenBrowser(resolveChatFirstOpenBrowser);
|
|
819
|
+
return () => {
|
|
820
|
+
unsubscribeApp();
|
|
821
|
+
unsubscribeBrowser();
|
|
822
|
+
};
|
|
823
|
+
}, [
|
|
824
|
+
chatFirstMode,
|
|
825
|
+
isChatRoute,
|
|
826
|
+
chatFirstSurfaceTabsStore,
|
|
827
|
+
resolveChatFirstOpenApp,
|
|
828
|
+
resolveChatFirstOpenBrowser,
|
|
829
|
+
]);
|
|
830
|
+
useEffect(() => {
|
|
831
|
+
if (!chatFirstMode ||
|
|
832
|
+
!isChatRoute ||
|
|
833
|
+
chatFirstPaneHydratedRef.current ||
|
|
834
|
+
chatFirstAppsQuery.isLoading ||
|
|
835
|
+
chatFirstAppsQuery.isError) {
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
chatFirstPaneHydratedRef.current = true;
|
|
839
|
+
if (chatFirstPane)
|
|
840
|
+
return;
|
|
841
|
+
let active = true;
|
|
842
|
+
void readClientAppState(CHAT_FIRST_PANE_STATE_KEY)
|
|
843
|
+
.then((value) => {
|
|
844
|
+
if (!active)
|
|
845
|
+
return;
|
|
846
|
+
const persisted = persistedChatFirstPane(value);
|
|
847
|
+
if (!persisted)
|
|
848
|
+
return;
|
|
849
|
+
const resolution = resolveChatFirstAppTarget({
|
|
850
|
+
app: persisted.appId,
|
|
851
|
+
path: persisted.path,
|
|
852
|
+
view: persisted.view,
|
|
853
|
+
}, chatFirstAppRegistrations, {
|
|
854
|
+
currentOrigin: typeof window === "undefined"
|
|
855
|
+
? undefined
|
|
856
|
+
: window.location.origin,
|
|
857
|
+
});
|
|
858
|
+
if (resolution.status === "ready")
|
|
859
|
+
openChatFirstPane(resolution.target);
|
|
860
|
+
})
|
|
861
|
+
.catch(() => {
|
|
862
|
+
if (active) {
|
|
863
|
+
setChatFirstNotice("The last app pane could not be restored from workspace state.");
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
return () => {
|
|
867
|
+
active = false;
|
|
868
|
+
};
|
|
869
|
+
}, [
|
|
870
|
+
chatFirstAppsQuery.isError,
|
|
871
|
+
chatFirstAppsQuery.isLoading,
|
|
872
|
+
chatFirstAppRegistrations,
|
|
873
|
+
chatFirstMode,
|
|
874
|
+
chatFirstPane,
|
|
875
|
+
isChatRoute,
|
|
876
|
+
openChatFirstPane,
|
|
877
|
+
]);
|
|
878
|
+
useEffect(() => {
|
|
879
|
+
if (previousChatFirstSurfaceScopeRef.current === chatFirstSurfaceScope) {
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
previousChatFirstSurfaceScopeRef.current = chatFirstSurfaceScope;
|
|
883
|
+
persistChatFirstPane(null);
|
|
884
|
+
setChatFirstEmbedUrl(null);
|
|
885
|
+
setChatFirstEmbedError(null);
|
|
886
|
+
setChatFirstNotice(null);
|
|
887
|
+
pendingChatFirstOpenAppRef.current = null;
|
|
888
|
+
chatFirstPaneHydratedRef.current = true;
|
|
889
|
+
chatFirstSurfaceTabsStore.closeAll();
|
|
890
|
+
setChatFirstSurfacePanelOpen(false);
|
|
891
|
+
closeChatFirstSessionWatch();
|
|
892
|
+
}, [
|
|
893
|
+
chatFirstSurfaceScope,
|
|
894
|
+
chatFirstSurfaceTabsStore,
|
|
895
|
+
persistChatFirstPane,
|
|
896
|
+
setChatFirstSurfacePanelOpen,
|
|
897
|
+
]);
|
|
898
|
+
useEffect(() => {
|
|
899
|
+
const tabCount = chatFirstSurfaceTabs.tabs.length;
|
|
900
|
+
const previousTabCount = previousChatFirstSurfaceTabCountRef.current;
|
|
901
|
+
if (!chatFirstMode || !isChatRoute) {
|
|
902
|
+
setChatFirstSurfacePanelOpen(false);
|
|
903
|
+
}
|
|
904
|
+
else if (tabCount > 0 &&
|
|
905
|
+
(previousTabCount === null || previousTabCount === 0)) {
|
|
906
|
+
setChatFirstSurfacePanelOpen(true);
|
|
907
|
+
}
|
|
908
|
+
else if (tabCount === 0 &&
|
|
909
|
+
previousTabCount !== null &&
|
|
910
|
+
previousTabCount > 0) {
|
|
911
|
+
setChatFirstSurfacePanelOpen(false);
|
|
912
|
+
}
|
|
913
|
+
previousChatFirstSurfaceTabCountRef.current = tabCount;
|
|
914
|
+
}, [
|
|
915
|
+
chatFirstMode,
|
|
916
|
+
setChatFirstSurfacePanelOpen,
|
|
917
|
+
chatFirstSurfaceTabs.tabs.length,
|
|
918
|
+
isChatRoute,
|
|
919
|
+
]);
|
|
920
|
+
useEffect(() => {
|
|
921
|
+
const activeTab = activeChatFirstSurfaceTab;
|
|
922
|
+
if (activeTab?.kind === "side-chat" &&
|
|
923
|
+
activeTab.session &&
|
|
924
|
+
!chatFirstSessionWatch.target) {
|
|
925
|
+
emitChatFirstSessionWatch(activeTab.session);
|
|
926
|
+
}
|
|
927
|
+
}, [activeChatFirstSurfaceTab, chatFirstSessionWatch.target]);
|
|
928
|
+
useEffect(() => {
|
|
929
|
+
const pending = pendingChatFirstOpenAppRef.current;
|
|
930
|
+
if (!pending || chatFirstAppsQuery.isLoading)
|
|
931
|
+
return;
|
|
932
|
+
resolveChatFirstOpenApp(pending);
|
|
933
|
+
}, [
|
|
934
|
+
chatFirstAppsQuery.data,
|
|
935
|
+
chatFirstAppsQuery.isError,
|
|
936
|
+
chatFirstAppsQuery.isLoading,
|
|
937
|
+
resolveChatFirstOpenApp,
|
|
938
|
+
]);
|
|
939
|
+
useEffect(() => {
|
|
940
|
+
const target = chatFirstSessionWatch.target;
|
|
941
|
+
if (!target || !chatFirstMode || !isChatRoute)
|
|
942
|
+
return;
|
|
943
|
+
setChatFirstPane(null);
|
|
944
|
+
chatFirstSurfaceTabsStore.open({
|
|
945
|
+
id: chatFirstSurfaceTabId("side-chat", target.sessionId),
|
|
946
|
+
kind: "side-chat",
|
|
947
|
+
title: target.title ? `Watch · ${target.title}` : "Watched session",
|
|
948
|
+
session: target,
|
|
949
|
+
});
|
|
950
|
+
}, [
|
|
951
|
+
chatFirstMode,
|
|
952
|
+
chatFirstSessionWatch.target,
|
|
953
|
+
chatFirstSurfaceTabsStore,
|
|
954
|
+
isChatRoute,
|
|
955
|
+
]);
|
|
389
956
|
useEffect(() => {
|
|
390
957
|
if (isWorkspaceAppHostRoute) {
|
|
391
958
|
if (!sidebarAutoCollapsedRef.current) {
|
|
@@ -416,9 +983,114 @@ export function Layout({ children, extensions, agentPageHref, }) {
|
|
|
416
983
|
// Ignore storage failures; the in-memory preference still works.
|
|
417
984
|
}
|
|
418
985
|
}, [isWorkspaceAppHostRoute, sidebarCollapsed]);
|
|
986
|
+
const activateChatFirstSurfaceTab = useCallback((tab) => {
|
|
987
|
+
chatFirstSurfaceTabsStore.activate(tab.id);
|
|
988
|
+
if (tab.kind === "app" && tab.appId) {
|
|
989
|
+
closeChatFirstSessionWatch();
|
|
990
|
+
persistChatFirstPane({
|
|
991
|
+
appId: tab.appId,
|
|
992
|
+
...(tab.path ? { path: tab.path } : {}),
|
|
993
|
+
...(tab.view ? { view: tab.view } : {}),
|
|
994
|
+
});
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
if (tab.kind === "browser" && tab.url) {
|
|
998
|
+
persistChatFirstPane(null);
|
|
999
|
+
closeChatFirstSessionWatch();
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
if (tab.kind === "side-chat" && tab.session) {
|
|
1003
|
+
persistChatFirstPane(null);
|
|
1004
|
+
emitChatFirstSessionWatch(tab.session);
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
if (tab.kind === "agents") {
|
|
1008
|
+
persistChatFirstPane(null);
|
|
1009
|
+
closeChatFirstSessionWatch();
|
|
1010
|
+
}
|
|
1011
|
+
}, [
|
|
1012
|
+
chatFirstSurfaceTabs.tabs,
|
|
1013
|
+
chatFirstSurfaceTabsStore,
|
|
1014
|
+
persistChatFirstPane,
|
|
1015
|
+
]);
|
|
1016
|
+
const closeChatFirstSurfaceTab = useCallback((tab) => {
|
|
1017
|
+
const isActive = chatFirstSurfaceTabs.activeTabId === tab.id;
|
|
1018
|
+
if (tab.kind === "app" && isActive)
|
|
1019
|
+
persistChatFirstPane(null);
|
|
1020
|
+
if (tab.kind === "side-chat" && isActive) {
|
|
1021
|
+
closeChatFirstSessionWatch();
|
|
1022
|
+
}
|
|
1023
|
+
chatFirstSurfaceTabsStore.close(tab.id);
|
|
1024
|
+
}, [chatFirstSurfaceTabs, chatFirstSurfaceTabsStore, persistChatFirstPane]);
|
|
1025
|
+
const closeAllChatFirstSurfaceTabs = useCallback(() => {
|
|
1026
|
+
persistChatFirstPane(null);
|
|
1027
|
+
closeChatFirstSessionWatch();
|
|
1028
|
+
chatFirstSurfaceTabsStore.closeAll();
|
|
1029
|
+
}, [chatFirstSurfaceTabsStore, persistChatFirstPane]);
|
|
1030
|
+
const renderChatFirstWatchChat = useCallback((target) => (_jsx(AgentChatSurface, { mode: "page", className: "h-full min-h-0 w-full", defaultMode: "chat", storageKey: `dispatch-session-watch:${target.sessionId}`, restoreActiveThread: false, threadUrlSync: {
|
|
1031
|
+
routeThreadId: target.sessionId,
|
|
1032
|
+
getPath: chatThreadPath,
|
|
1033
|
+
navigate: () => undefined,
|
|
1034
|
+
}, showHeader: false, showTabBar: false, showPageNewChatButton: false, chatOnly: true, dynamicSuggestions: false, suggestions: [], emptyStateDisplay: "hidden", composerPlaceholder: t("dispatch.pages.chatFirstSessionMessagePlaceholder") })), [t]);
|
|
1035
|
+
const renderChatFirstSurfaceTab = useCallback((tab) => {
|
|
1036
|
+
if (tab.kind === "app") {
|
|
1037
|
+
if (tab.id !== chatFirstSurfaceTabs.activeTabId)
|
|
1038
|
+
return null;
|
|
1039
|
+
const app = tab.appId
|
|
1040
|
+
? (chatFirstWorkspaceApps.find((candidate) => candidate.id === tab.appId) ?? null)
|
|
1041
|
+
: null;
|
|
1042
|
+
return (_jsx(ChatFirstAppPane, { app: app, status: chatFirstEmbedError
|
|
1043
|
+
? "error"
|
|
1044
|
+
: chatFirstEmbedUrl
|
|
1045
|
+
? "ready"
|
|
1046
|
+
: chatFirstAppsQuery.isLoading
|
|
1047
|
+
? "loading"
|
|
1048
|
+
: app
|
|
1049
|
+
? "loading"
|
|
1050
|
+
: "unresolved", embedUrl: chatFirstEmbedUrl, errorMessage: chatFirstEmbedError, onRetry: () => setChatFirstEmbedAttempt((value) => value + 1), renderEmbed: ({ url, title }) => (_jsx("iframe", { "data-dispatch-chat-first-app-frame": true, src: url, title: title ?? chatFirstCopy("appUnavailable"), referrerPolicy: "no-referrer", allow: "clipboard-read; clipboard-write", className: "h-full w-full border-0 bg-background" })), copy: chatFirstCopy }));
|
|
1051
|
+
}
|
|
1052
|
+
if (tab.kind === "browser" && tab.url) {
|
|
1053
|
+
return (_jsx(ChatFirstBrowserPane, { url: tab.url, title: tab.title, onClose: () => closeChatFirstSurfaceTab(tab), renderEmbed: ({ url, title, key }) => (_jsx("iframe", { src: url, title: title ?? chatFirstCopy("browserPage"), referrerPolicy: "no-referrer", allow: "clipboard-read; clipboard-write", className: "h-full w-full border-0 bg-background" }, key)), copy: chatFirstCopy }));
|
|
1054
|
+
}
|
|
1055
|
+
if (tab.kind === "side-chat") {
|
|
1056
|
+
const target = tab.session ??
|
|
1057
|
+
(tab.id === chatFirstSurfaceTabs.activeTabId
|
|
1058
|
+
? chatFirstSessionWatch.target
|
|
1059
|
+
: null);
|
|
1060
|
+
return target ? (_jsx(ChatFirstSessionWatchPane, { target: target, onClose: () => closeChatFirstSurfaceTab(tab), renderChat: renderChatFirstWatchChat, copy: chatFirstCopy })) : null;
|
|
1061
|
+
}
|
|
1062
|
+
if (tab.kind === "agents") {
|
|
1063
|
+
return (_jsx(ChatFirstAgentsPane, { activities: chatFirstAgentActivities, loading: chatFirstAgentsQuery.isLoading, error: chatFirstAgentsQuery.isError
|
|
1064
|
+
? chatFirstAgentsQuery.error.message
|
|
1065
|
+
: null, onRefresh: () => void chatFirstAgentsQuery.refetch(), onWatch: (activity) => emitChatFirstSessionWatch({
|
|
1066
|
+
sessionId: activity.sessionId,
|
|
1067
|
+
title: activity.title,
|
|
1068
|
+
kind: "agent-chat",
|
|
1069
|
+
...(activity.goalId ? { goalId: activity.goalId } : {}),
|
|
1070
|
+
}), copy: chatFirstCopy }));
|
|
1071
|
+
}
|
|
1072
|
+
return null;
|
|
1073
|
+
}, [
|
|
1074
|
+
chatFirstAgentActivities,
|
|
1075
|
+
chatFirstAgentsQuery.error,
|
|
1076
|
+
chatFirstAgentsQuery.isError,
|
|
1077
|
+
chatFirstAgentsQuery.isLoading,
|
|
1078
|
+
chatFirstAppsQuery.isLoading,
|
|
1079
|
+
chatFirstCopy,
|
|
1080
|
+
chatFirstEmbedError,
|
|
1081
|
+
chatFirstEmbedUrl,
|
|
1082
|
+
chatFirstSessionWatch.target,
|
|
1083
|
+
chatFirstSurfaceTabs.activeTabId,
|
|
1084
|
+
chatFirstWorkspaceApps,
|
|
1085
|
+
closeChatFirstSurfaceTab,
|
|
1086
|
+
renderChatFirstWatchChat,
|
|
1087
|
+
]);
|
|
419
1088
|
if (CHROMELESS_PATHS.some((path) => localPathname === path)) {
|
|
420
1089
|
return _jsx(_Fragment, { children: children });
|
|
421
1090
|
}
|
|
1091
|
+
if (isWorkspaceAppHostRoute) {
|
|
1092
|
+
return (_jsx(DispatchExtensionsContext.Provider, { value: extensions, children: _jsx(HeaderActionsProvider, { children: _jsx("div", { "data-dispatch-workspace-app-chrome-less": true, className: "h-screen w-full overflow-hidden bg-background", children: children }) }) }));
|
|
1093
|
+
}
|
|
422
1094
|
const showHeader = !isChatRoute && !pageOwnsToolbar(localPathname);
|
|
423
1095
|
function openAskAgentFullscreen() {
|
|
424
1096
|
focusAgentChat();
|
|
@@ -429,10 +1101,27 @@ export function Layout({ children, extensions, agentPageHref, }) {
|
|
|
429
1101
|
t("dispatch.sidebar.suggestionRouteSlack"),
|
|
430
1102
|
t("dispatch.sidebar.suggestionGrantKey"),
|
|
431
1103
|
];
|
|
432
|
-
const appContent = (_jsxs("div", { className: "flex h-full min-w-0 flex-1 flex-col overflow-hidden", children: [showHeader ? _jsx(Header, { onOpenMobile: () => setMobileOpen(true) }) : null, _jsx(InvitationBanner, {}), _jsx("main", { className: cn("flex-1", isChatRoute || isWorkspaceAppHostRoute
|
|
1104
|
+
const appContent = (_jsxs("div", { className: "relative flex h-full min-w-0 flex-1 flex-col overflow-hidden", children: [showHeader ? _jsx(Header, { onOpenMobile: () => setMobileOpen(true) }) : null, _jsx(InvitationBanner, {}), isChatRoute && chatFirstMode ? (_jsx(ChatFirstSurfacePanelToggle, { open: chatFirstSurfacePanel.open, onToggle: chatFirstSurfacePanel.toggle, className: "absolute right-3 top-2 z-[4]" })) : null, isChatRoute && chatFirstMode && chatFirstNotice ? (_jsxs("div", { className: "dispatch-chat-first-notice", role: "status", "aria-live": "polite", children: [_jsx("span", { children: chatFirstNotice }), _jsx("button", { type: "button", onClick: () => setChatFirstNotice(null), "aria-label": "Dismiss app notice", children: "Dismiss" })] })) : null, _jsx("main", { className: cn("flex-1", isChatRoute || isWorkspaceAppHostRoute
|
|
433
1105
|
? "min-h-0 overflow-hidden"
|
|
434
1106
|
: "overflow-y-auto"), children: showHeader ? (_jsx("div", { className: "mx-auto max-w-7xl space-y-10 px-4 py-6 sm:px-6", children: children })) : (children) })] }));
|
|
435
|
-
const content = isChatRoute ? (
|
|
436
|
-
|
|
1107
|
+
const content = isChatRoute ? (_jsxs("div", { className: cn("agent-layout-main-surface flex min-w-0 flex-1 overflow-hidden", chatFirstMode && "dispatch-chat-first-surface"), children: [appContent, chatFirstMode && chatFirstSurfacePanel.open ? (_jsxs(ChatFirstSurfacePanel, { width: chatFirstSurfaceResize.width, onResizePointerDown: chatFirstSurfaceResize.onPointerDown, copy: chatFirstCopy, children: [_jsx(ChatFirstSurfaceTabs, { tabs: chatFirstSurfaceTabs.tabs, activeTabId: chatFirstSurfaceTabs.activeTabId, onActivate: activateChatFirstSurfaceTab, onClose: closeChatFirstSurfaceTab, onCloseOthers: (tab) => {
|
|
1108
|
+
activateChatFirstSurfaceTab(tab);
|
|
1109
|
+
chatFirstSurfaceTabsStore.closeOthers(tab.id);
|
|
1110
|
+
}, onCloseToRight: (tab) => {
|
|
1111
|
+
const targetIndex = chatFirstSurfaceTabs.tabs.findIndex((candidate) => candidate.id === tab.id);
|
|
1112
|
+
const activeIndex = chatFirstSurfaceTabs.tabs.findIndex((candidate) => candidate.id === chatFirstSurfaceTabs.activeTabId);
|
|
1113
|
+
if (activeIndex > targetIndex)
|
|
1114
|
+
activateChatFirstSurfaceTab(tab);
|
|
1115
|
+
chatFirstSurfaceTabsStore.closeToRight(tab.id);
|
|
1116
|
+
}, onCloseAll: closeAllChatFirstSurfaceTabs, onOpenSurface: openChatFirstSurface, copy: chatFirstCopy }), chatFirstSurfaceTabs.tabs.length > 0 ? (_jsx(ChatFirstSurfaceContent, { tabs: chatFirstSurfaceTabs.tabs, activeTabId: chatFirstSurfaceTabs.activeTabId, renderTab: renderChatFirstSurfaceTab })) : null] })) : null] })) : (_jsx(AgentSidebar, { position: "right", defaultOpen: false, agentPageHref: agentPageHref, chatViewTransition: true, storageKey: "dispatch", openOnChatRunning: chatHomeHandoffActive, onFullscreenRequest: openAskAgentFullscreen, emptyStateText: t("dispatch.sidebar.emptyAgentText"), suggestions: sidebarSuggestions, children: appContent }));
|
|
1117
|
+
return (_jsx(DispatchExtensionsContext.Provider, { value: extensions, children: _jsx(HeaderActionsProvider, { children: _jsxs("div", { className: "agent-layout-shell flex h-screen w-full overflow-hidden bg-background", children: [_jsx("aside", { "data-collapsed": sidebarCollapsed ? "true" : "false", className: cn("agent-layout-left-drawer hidden shrink-0 flex-col border-e !border-e-sidebar-border bg-sidebar text-sidebar-foreground transition-[width] duration-200 ease-out lg:flex", sidebarCollapsed ? "w-14" : "w-56"), children: _jsx(NavContent, { extensions: extensions, chatFirstMode: chatFirstMode, chatFirstEmbedded: chatFirstEmbedded, collapsed: sidebarCollapsed, chatFirstAppLayout: chatFirstAppLayout, onChatFirstAppLayoutChange: persistChatFirstAppLayout, chatFirstApps: chatFirstAppItems, chatFirstAppsLoading: chatFirstAppsQuery.isLoading, chatFirstAppsError: chatFirstAppsQuery.isError
|
|
1118
|
+
? chatFirstCopy("appsLoadError")
|
|
1119
|
+
: null, chatFirstActiveAppId: activeChatFirstSurfaceTab?.kind === "app"
|
|
1120
|
+
? activeChatFirstSurfaceTab.appId
|
|
1121
|
+
: undefined, onChatFirstAppOpen: (app) => openChatFirstPane({ appId: app.id }), onChatFirstAppsRetry: () => void chatFirstAppsQuery.refetch(), collapsible: true, onCollapsedChange: setSidebarCollapsed }) }), _jsx(Sheet, { open: mobileOpen, onOpenChange: setMobileOpen, children: _jsxs(SheetContent, { side: "left", className: "w-72 p-0 bg-sidebar text-sidebar-foreground [&>button]:hidden", children: [_jsx(SheetTitle, { className: "sr-only", children: t("dispatch.nav.navigation") }), _jsx(SheetDescription, { className: "sr-only", children: t("dispatch.nav.navigationDescription") }), _jsx("div", { className: "flex h-full w-full flex-col", children: _jsx(NavContent, { extensions: extensions, chatFirstMode: chatFirstMode, chatFirstEmbedded: chatFirstEmbedded, collapsed: false, chatFirstAppLayout: chatFirstAppLayout, onChatFirstAppLayoutChange: persistChatFirstAppLayout, chatFirstApps: chatFirstAppItems, chatFirstAppsLoading: chatFirstAppsQuery.isLoading, chatFirstAppsError: chatFirstAppsQuery.isError
|
|
1122
|
+
? chatFirstCopy("appsLoadError")
|
|
1123
|
+
: null, chatFirstActiveAppId: activeChatFirstSurfaceTab?.kind === "app"
|
|
1124
|
+
? activeChatFirstSurfaceTab.appId
|
|
1125
|
+
: undefined, onChatFirstAppOpen: (app) => openChatFirstPane({ appId: app.id }), onChatFirstAppsRetry: () => void chatFirstAppsQuery.refetch(), onNavigate: () => setMobileOpen(false) }) })] }) }), content] }) }) }));
|
|
437
1126
|
}
|
|
438
1127
|
//# sourceMappingURL=Layout.js.map
|