@agent-native/dispatch 0.22.1 → 0.23.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/dist/actions/provider-api-register.d.ts +1 -1
- package/dist/components/app-icon.d.ts +2 -1
- package/dist/components/app-icon.d.ts.map +1 -1
- package/dist/components/app-icon.js +51 -29
- package/dist/components/app-icon.js.map +1 -1
- package/dist/components/app-list-row.d.ts +1 -1
- package/dist/components/app-list-row.d.ts.map +1 -1
- package/dist/components/app-list-row.js +1 -1
- package/dist/components/app-list-row.js.map +1 -1
- package/dist/components/app-open-actions.d.ts +2 -1
- package/dist/components/app-open-actions.d.ts.map +1 -1
- package/dist/components/app-open-actions.js +2 -2
- package/dist/components/app-open-actions.js.map +1 -1
- package/dist/components/dispatch-control-plane.d.ts.map +1 -1
- package/dist/components/dispatch-control-plane.js +16 -17
- package/dist/components/dispatch-control-plane.js.map +1 -1
- package/dist/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +137 -66
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/layout/workspace-apps-rail.d.ts.map +1 -1
- package/dist/components/layout/workspace-apps-rail.js +1 -1
- package/dist/components/layout/workspace-apps-rail.js.map +1 -1
- package/dist/components/other-apps-section.d.ts +3 -1
- package/dist/components/other-apps-section.d.ts.map +1 -1
- package/dist/components/other-apps-section.js +9 -6
- package/dist/components/other-apps-section.js.map +1 -1
- package/dist/components/workspace-app-card.d.ts.map +1 -1
- package/dist/components/workspace-app-card.js +7 -2
- package/dist/components/workspace-app-card.js.map +1 -1
- package/dist/components/workspace-template-card.d.ts.map +1 -1
- package/dist/components/workspace-template-card.js +2 -5
- package/dist/components/workspace-template-card.js.map +1 -1
- package/dist/lib/overview-chat.d.ts.map +1 -1
- package/dist/lib/overview-chat.js +0 -8
- package/dist/lib/overview-chat.js.map +1 -1
- package/dist/routes/pages/chat.js +1 -1
- package/dist/routes/pages/chat.js.map +1 -1
- package/dist/server/lib/mcp-gateway.d.ts.map +1 -1
- package/dist/server/lib/mcp-gateway.js +14 -1
- package/dist/server/lib/mcp-gateway.js.map +1 -1
- package/package.json +3 -3
- package/src/components/app-icon.tsx +71 -43
- package/src/components/app-list-row.tsx +1 -1
- package/src/components/app-open-actions.tsx +4 -2
- package/src/components/dispatch-control-plane.spec.tsx +45 -7
- package/src/components/dispatch-control-plane.tsx +56 -75
- package/src/components/layout/Layout.spec.tsx +53 -0
- package/src/components/layout/Layout.tsx +227 -99
- package/src/components/layout/workspace-apps-rail.tsx +1 -0
- package/src/components/other-apps-section.tsx +61 -40
- package/src/components/workspace-app-card.spec.tsx +63 -66
- package/src/components/workspace-app-card.tsx +10 -3
- package/src/components/workspace-template-card.spec.tsx +7 -8
- package/src/components/workspace-template-card.tsx +21 -11
- package/src/lib/overview-chat.spec.ts +0 -19
- package/src/lib/overview-chat.ts +0 -9
- package/src/routes/pages/chat.tsx +1 -1
- package/src/server/lib/mcp-gateway.spec.ts +64 -2
- package/src/server/lib/mcp-gateway.ts +19 -1
- package/src/styles/dispatch-css.spec.ts +11 -0
- package/src/styles/dispatch.css +2 -2
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
type ChatFirstAppRegistration,
|
|
24
24
|
type ChatFirstAppLayoutPreference,
|
|
25
25
|
type ChatFirstAppResolution,
|
|
26
|
+
type ChatFirstAppSurfacePlacement,
|
|
26
27
|
type ChatFirstOpenBrowserDetail,
|
|
27
28
|
type ChatFirstOpenAppDetail,
|
|
28
29
|
type ChatFirstSessionReference,
|
|
@@ -199,6 +200,7 @@ const CHAT_FIRST_PANE_STATE_KEY = "chat-first-pane";
|
|
|
199
200
|
|
|
200
201
|
interface DispatchChatFirstPane {
|
|
201
202
|
appId: string;
|
|
203
|
+
placement?: ChatFirstAppSurfacePlacement;
|
|
202
204
|
path?: string;
|
|
203
205
|
view?: string;
|
|
204
206
|
}
|
|
@@ -214,6 +216,16 @@ interface ChatFirstEmbedSessionInput {
|
|
|
214
216
|
chrome: "minimal";
|
|
215
217
|
}
|
|
216
218
|
|
|
219
|
+
interface ChatFirstGrantedAppSummary {
|
|
220
|
+
id: string;
|
|
221
|
+
name: string;
|
|
222
|
+
url?: string | null;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
interface ChatFirstGrantedAppsResult {
|
|
226
|
+
apps: ChatFirstGrantedAppSummary[];
|
|
227
|
+
}
|
|
228
|
+
|
|
217
229
|
export function buildChatFirstEmbedSessionInput(
|
|
218
230
|
appId: string,
|
|
219
231
|
path: string,
|
|
@@ -451,6 +463,9 @@ function persistedChatFirstPane(value: unknown): DispatchChatFirstPane | null {
|
|
|
451
463
|
if (typeof record.appId !== "string" || !record.appId.trim()) return null;
|
|
452
464
|
return {
|
|
453
465
|
appId: record.appId,
|
|
466
|
+
...(record.placement === "main" || record.placement === "side"
|
|
467
|
+
? { placement: record.placement }
|
|
468
|
+
: {}),
|
|
454
469
|
...(typeof record.path === "string" ? { path: record.path } : {}),
|
|
455
470
|
...(typeof record.view === "string" ? { view: record.view } : {}),
|
|
456
471
|
};
|
|
@@ -663,12 +678,12 @@ function DispatchChatsSection({
|
|
|
663
678
|
return (
|
|
664
679
|
<div
|
|
665
680
|
className={cn(
|
|
666
|
-
"
|
|
681
|
+
"min-w-0 space-y-0.5",
|
|
667
682
|
showNewChat && "dispatch-chat-first-chats",
|
|
668
683
|
)}
|
|
669
684
|
>
|
|
670
685
|
{showNewChat && chatFirstNavigation ? (
|
|
671
|
-
<nav className="space-y-0.5 px-
|
|
686
|
+
<nav className="space-y-0.5 px-0 py-2">
|
|
672
687
|
<ChatFirstPrimaryNavigation
|
|
673
688
|
copy={chatFirstCopy}
|
|
674
689
|
onNewChat={() => void handleNewChat()}
|
|
@@ -730,7 +745,7 @@ function DispatchChatsSection({
|
|
|
730
745
|
<Skeleton className="h-3 w-3/4 rounded" />
|
|
731
746
|
</div>
|
|
732
747
|
))}
|
|
733
|
-
{chatFirstMode ? (
|
|
748
|
+
{chatFirstMode && (chatsLoading || visibleThreads.length > 0) ? (
|
|
734
749
|
<ChatFirstChatHistory
|
|
735
750
|
items={chatItems}
|
|
736
751
|
activeId={displayedActiveThreadId}
|
|
@@ -1015,7 +1030,7 @@ export function NavContent({
|
|
|
1015
1030
|
id={app.id}
|
|
1016
1031
|
name={app.name}
|
|
1017
1032
|
size="sm"
|
|
1018
|
-
className="size-
|
|
1033
|
+
className="size-7 rounded-lg"
|
|
1019
1034
|
/>
|
|
1020
1035
|
)}
|
|
1021
1036
|
copy={chatFirstCopy}
|
|
@@ -1246,7 +1261,7 @@ export function NavContent({
|
|
|
1246
1261
|
<div className="mt-auto shrink-0">
|
|
1247
1262
|
{bottomNavigation}
|
|
1248
1263
|
{organizationPicker}
|
|
1249
|
-
{
|
|
1264
|
+
{sidebarFooterActions}
|
|
1250
1265
|
</div>
|
|
1251
1266
|
) : null}
|
|
1252
1267
|
</>
|
|
@@ -1278,7 +1293,11 @@ export function Layout({
|
|
|
1278
1293
|
const isChatRoute =
|
|
1279
1294
|
localPathname === "/chat" || localPathname.startsWith("/chat/");
|
|
1280
1295
|
const chatFirstSurfaceScope = threadIdFromPath(localPathname) ?? "new";
|
|
1281
|
-
const
|
|
1296
|
+
const isWorkspaceAppRoute = localPathname.startsWith("/apps/");
|
|
1297
|
+
const isWorkspaceAppHostRoute =
|
|
1298
|
+
isWorkspaceAppRoute &&
|
|
1299
|
+
typeof window !== "undefined" &&
|
|
1300
|
+
new URLSearchParams(window.location.search).get("embedded") === "1";
|
|
1282
1301
|
const [chatFirstPreference, setChatFirstPreference] = useState(() =>
|
|
1283
1302
|
readChatFirstMode(),
|
|
1284
1303
|
);
|
|
@@ -1287,36 +1306,56 @@ export function Layout({
|
|
|
1287
1306
|
new URLSearchParams(window.location.search).get("chatFirst") === "1";
|
|
1288
1307
|
const chatFirstMode =
|
|
1289
1308
|
extensions?.chatFirst === true || chatFirstPreference || chatFirstEmbedded;
|
|
1309
|
+
const chatFirstHasActiveChat = chatFirstSurfaceScope !== "new";
|
|
1290
1310
|
const [chatFirstAppLayout, setChatFirstAppLayout] =
|
|
1291
1311
|
useState<ChatFirstAppLayoutPreference>(() => readChatFirstAppLayout());
|
|
1292
1312
|
const chatFirstAppLayoutHydratedRef = useRef(false);
|
|
1293
1313
|
const chatFirstAppsQuery = useActionQuery<WorkspaceAppSummary[]>(
|
|
1294
1314
|
"list-workspace-apps",
|
|
1295
1315
|
{ includeAgentCards: false },
|
|
1296
|
-
{ enabled: chatFirstMode
|
|
1316
|
+
{ enabled: chatFirstMode },
|
|
1317
|
+
);
|
|
1318
|
+
const chatFirstGrantedAppsQuery = useActionQuery<ChatFirstGrantedAppsResult>(
|
|
1319
|
+
"list_apps",
|
|
1320
|
+
{},
|
|
1321
|
+
{ enabled: chatFirstMode },
|
|
1297
1322
|
);
|
|
1298
1323
|
const chatFirstWorkspaceApps = useMemo(
|
|
1299
1324
|
() => mergeChatFirstWorkspaceApps(chatFirstAppsQuery.data),
|
|
1300
1325
|
[chatFirstAppsQuery.data],
|
|
1301
1326
|
);
|
|
1302
|
-
const chatFirstAppRegistrations = useMemo<ChatFirstAppRegistration[]>(
|
|
1303
|
-
()
|
|
1304
|
-
|
|
1327
|
+
const chatFirstAppRegistrations = useMemo<ChatFirstAppRegistration[]>(() => {
|
|
1328
|
+
const registrations = new Map<string, ChatFirstAppRegistration>();
|
|
1329
|
+
for (const app of chatFirstWorkspaceApps) {
|
|
1330
|
+
registrations.set(app.id.toLowerCase(), {
|
|
1305
1331
|
id: app.id,
|
|
1306
1332
|
name: app.name,
|
|
1307
1333
|
path: app.path,
|
|
1308
1334
|
url: app.url,
|
|
1309
1335
|
enabled: app.status !== "pending" && app.archived !== true,
|
|
1310
|
-
})
|
|
1311
|
-
|
|
1312
|
-
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
for (const app of chatFirstGrantedAppsQuery.data?.apps ?? []) {
|
|
1339
|
+
const id = app.id.trim();
|
|
1340
|
+
if (!id || registrations.has(id.toLowerCase())) continue;
|
|
1341
|
+
registrations.set(id.toLowerCase(), {
|
|
1342
|
+
id,
|
|
1343
|
+
name: app.name,
|
|
1344
|
+
url: app.url,
|
|
1345
|
+
enabled: true,
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
return [...registrations.values()];
|
|
1349
|
+
}, [chatFirstGrantedAppsQuery.data?.apps, chatFirstWorkspaceApps]);
|
|
1313
1350
|
const chatFirstAppItems = useMemo<ChatFirstAppItem[]>(
|
|
1314
1351
|
() =>
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1352
|
+
chatFirstAppRegistrations
|
|
1353
|
+
.filter((app) => app.enabled)
|
|
1354
|
+
.map((app) => ({
|
|
1355
|
+
id: app.id,
|
|
1356
|
+
name: app.name ?? app.id,
|
|
1357
|
+
})),
|
|
1358
|
+
[chatFirstAppRegistrations],
|
|
1320
1359
|
);
|
|
1321
1360
|
const chatFirstCopy = useMemo(() => createDispatchChatFirstCopy(t), [t]);
|
|
1322
1361
|
const createChatFirstEmbedSession = useActionMutation<
|
|
@@ -1366,15 +1405,32 @@ export function Layout({
|
|
|
1366
1405
|
) ?? null,
|
|
1367
1406
|
[chatFirstSurfaceTabs],
|
|
1368
1407
|
);
|
|
1369
|
-
const
|
|
1408
|
+
const chatFirstAppTakesMain =
|
|
1409
|
+
chatFirstMode &&
|
|
1410
|
+
isChatRoute &&
|
|
1411
|
+
activeChatFirstSurfaceTab?.kind === "app" &&
|
|
1412
|
+
activeChatFirstSurfaceTab.placement === "main";
|
|
1413
|
+
const activeChatFirstAppRegistration = useMemo(
|
|
1370
1414
|
() =>
|
|
1371
1415
|
activeChatFirstSurfaceTab?.kind === "app" &&
|
|
1372
1416
|
activeChatFirstSurfaceTab.appId
|
|
1373
|
-
? (
|
|
1417
|
+
? (chatFirstAppRegistrations.find(
|
|
1374
1418
|
(app) => app.id === activeChatFirstSurfaceTab.appId,
|
|
1375
1419
|
) ?? null)
|
|
1376
1420
|
: null,
|
|
1377
|
-
[activeChatFirstSurfaceTab,
|
|
1421
|
+
[activeChatFirstSurfaceTab, chatFirstAppRegistrations],
|
|
1422
|
+
);
|
|
1423
|
+
const activeChatFirstApp = useMemo(
|
|
1424
|
+
() =>
|
|
1425
|
+
activeChatFirstAppRegistration
|
|
1426
|
+
? {
|
|
1427
|
+
id: activeChatFirstAppRegistration.id,
|
|
1428
|
+
name:
|
|
1429
|
+
activeChatFirstAppRegistration.name ??
|
|
1430
|
+
activeChatFirstAppRegistration.id,
|
|
1431
|
+
}
|
|
1432
|
+
: null,
|
|
1433
|
+
[activeChatFirstAppRegistration],
|
|
1378
1434
|
);
|
|
1379
1435
|
const chatFirstAgentActivities = useMemo<ChatFirstAgentActivity[]>(
|
|
1380
1436
|
() =>
|
|
@@ -1392,7 +1448,8 @@ export function Layout({
|
|
|
1392
1448
|
activeChatFirstSurfaceTab?.kind === "app"
|
|
1393
1449
|
? (activeChatFirstSurfaceTab.path ??
|
|
1394
1450
|
chatFirstPane?.path ??
|
|
1395
|
-
|
|
1451
|
+
activeChatFirstAppRegistration?.path ??
|
|
1452
|
+
"/")
|
|
1396
1453
|
: null;
|
|
1397
1454
|
useEffect(() => {
|
|
1398
1455
|
if (!chatFirstMode || !isChatRoute || !activeChatFirstApp) {
|
|
@@ -1451,9 +1508,19 @@ export function Layout({
|
|
|
1451
1508
|
[],
|
|
1452
1509
|
);
|
|
1453
1510
|
const openChatFirstPane = useCallback(
|
|
1454
|
-
(
|
|
1511
|
+
(
|
|
1512
|
+
pane: DispatchChatFirstPane,
|
|
1513
|
+
placement: ChatFirstAppSurfacePlacement = "side",
|
|
1514
|
+
) => {
|
|
1515
|
+
if (placement === "side" && !chatFirstHasActiveChat) return;
|
|
1455
1516
|
setChatFirstNotice(null);
|
|
1456
1517
|
closeChatFirstSessionWatch();
|
|
1518
|
+
if (!isChatRoute) {
|
|
1519
|
+
navigateWithAgentChatViewTransition(
|
|
1520
|
+
navigate,
|
|
1521
|
+
dispatchNavLinkTarget("/chat"),
|
|
1522
|
+
);
|
|
1523
|
+
}
|
|
1457
1524
|
const app = chatFirstAppRegistrations.find(
|
|
1458
1525
|
(candidate) => candidate.id === pane.appId,
|
|
1459
1526
|
);
|
|
@@ -1465,19 +1532,36 @@ export function Layout({
|
|
|
1465
1532
|
kind: "app",
|
|
1466
1533
|
title: app?.name ?? pane.appId,
|
|
1467
1534
|
appId: pane.appId,
|
|
1535
|
+
placement,
|
|
1468
1536
|
...(pane.path ? { path: pane.path } : {}),
|
|
1469
1537
|
...(pane.view ? { view: pane.view } : {}),
|
|
1470
1538
|
});
|
|
1471
|
-
|
|
1539
|
+
setChatFirstSurfacePanelOpen(true);
|
|
1540
|
+
persistChatFirstPane({ ...pane, placement });
|
|
1472
1541
|
},
|
|
1473
1542
|
[
|
|
1474
1543
|
chatFirstAppRegistrations,
|
|
1475
1544
|
chatFirstSurfaceTabsStore,
|
|
1545
|
+
chatFirstHasActiveChat,
|
|
1476
1546
|
persistChatFirstPane,
|
|
1547
|
+
isChatRoute,
|
|
1548
|
+
navigate,
|
|
1549
|
+
setChatFirstSurfacePanelOpen,
|
|
1477
1550
|
],
|
|
1478
1551
|
);
|
|
1479
1552
|
const openChatFirstSurface = useCallback(
|
|
1480
1553
|
(kind: ChatFirstSurfaceKind) => {
|
|
1554
|
+
if (kind === "browser") {
|
|
1555
|
+
persistChatFirstPane(null);
|
|
1556
|
+
closeChatFirstSessionWatch();
|
|
1557
|
+
chatFirstSurfaceTabsStore.open({
|
|
1558
|
+
id: chatFirstSurfaceTabId("browser", "homepage"),
|
|
1559
|
+
kind: "browser",
|
|
1560
|
+
title: "Browser",
|
|
1561
|
+
url: "https://www.google.com/",
|
|
1562
|
+
});
|
|
1563
|
+
return;
|
|
1564
|
+
}
|
|
1481
1565
|
if (kind !== "agents") return;
|
|
1482
1566
|
persistChatFirstPane(null);
|
|
1483
1567
|
closeChatFirstSessionWatch();
|
|
@@ -1498,6 +1582,24 @@ export function Layout({
|
|
|
1498
1582
|
);
|
|
1499
1583
|
return;
|
|
1500
1584
|
}
|
|
1585
|
+
if (resolution.target.openExternally && typeof window !== "undefined") {
|
|
1586
|
+
try {
|
|
1587
|
+
// Builder's Visual Editor rejects iframe ancestors with CSP/X-Frame-
|
|
1588
|
+
// Options. Prefer the real browser tab; the browser pane below is a
|
|
1589
|
+
// visible fallback when popup policy blocks this non-click event.
|
|
1590
|
+
if (
|
|
1591
|
+
window.open(resolution.target.url, "_blank", "noopener,noreferrer")
|
|
1592
|
+
) {
|
|
1593
|
+
return;
|
|
1594
|
+
}
|
|
1595
|
+
} catch (error) {
|
|
1596
|
+
console.warn(
|
|
1597
|
+
"[chat-first] external browser open failed; keeping link fallback",
|
|
1598
|
+
error,
|
|
1599
|
+
);
|
|
1600
|
+
// Fall through to the non-iframe browser pane below.
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1501
1603
|
persistChatFirstPane(null);
|
|
1502
1604
|
closeChatFirstSessionWatch();
|
|
1503
1605
|
setChatFirstNotice(null);
|
|
@@ -1512,7 +1614,7 @@ export function Layout({
|
|
|
1512
1614
|
);
|
|
1513
1615
|
const resolveChatFirstOpenApp = useCallback(
|
|
1514
1616
|
(detail: ChatFirstOpenAppDetail) => {
|
|
1515
|
-
if (chatFirstAppsQuery.isLoading) {
|
|
1617
|
+
if (chatFirstAppsQuery.isLoading || chatFirstGrantedAppsQuery.isLoading) {
|
|
1516
1618
|
pendingChatFirstOpenAppRef.current = detail;
|
|
1517
1619
|
return;
|
|
1518
1620
|
}
|
|
@@ -1543,11 +1645,10 @@ export function Layout({
|
|
|
1543
1645
|
chatFirstAppRegistrations,
|
|
1544
1646
|
chatFirstAppsQuery.isError,
|
|
1545
1647
|
chatFirstAppsQuery.isLoading,
|
|
1648
|
+
chatFirstGrantedAppsQuery.isLoading,
|
|
1546
1649
|
openChatFirstPane,
|
|
1547
1650
|
],
|
|
1548
1651
|
);
|
|
1549
|
-
const sidebarBeforeAppRef = useRef<boolean | null>(null);
|
|
1550
|
-
const sidebarAutoCollapsedRef = useRef(false);
|
|
1551
1652
|
const chatHomeHandoffActive = useAgentChatHomeHandoff({
|
|
1552
1653
|
storageKey: "dispatch",
|
|
1553
1654
|
activePath: localPathname,
|
|
@@ -1618,7 +1719,7 @@ export function Layout({
|
|
|
1618
1719
|
);
|
|
1619
1720
|
|
|
1620
1721
|
useEffect(() => {
|
|
1621
|
-
if (!chatFirstMode
|
|
1722
|
+
if (!chatFirstMode) {
|
|
1622
1723
|
setChatFirstPane(null);
|
|
1623
1724
|
closeChatFirstSessionWatch();
|
|
1624
1725
|
chatFirstSurfaceTabsStore.closeAll();
|
|
@@ -1675,7 +1776,9 @@ export function Layout({
|
|
|
1675
1776
|
: window.location.origin,
|
|
1676
1777
|
},
|
|
1677
1778
|
);
|
|
1678
|
-
if (resolution.status === "ready")
|
|
1779
|
+
if (resolution.status === "ready") {
|
|
1780
|
+
openChatFirstPane(resolution.target, persisted.placement);
|
|
1781
|
+
}
|
|
1679
1782
|
})
|
|
1680
1783
|
.catch(() => {
|
|
1681
1784
|
if (active) {
|
|
@@ -1721,7 +1824,7 @@ export function Layout({
|
|
|
1721
1824
|
useEffect(() => {
|
|
1722
1825
|
const tabCount = chatFirstSurfaceTabs.tabs.length;
|
|
1723
1826
|
const previousTabCount = previousChatFirstSurfaceTabCountRef.current;
|
|
1724
|
-
if (!chatFirstMode || !
|
|
1827
|
+
if (!chatFirstMode || !chatFirstHasActiveChat) {
|
|
1725
1828
|
setChatFirstSurfacePanelOpen(false);
|
|
1726
1829
|
} else if (
|
|
1727
1830
|
tabCount > 0 &&
|
|
@@ -1738,6 +1841,7 @@ export function Layout({
|
|
|
1738
1841
|
previousChatFirstSurfaceTabCountRef.current = tabCount;
|
|
1739
1842
|
}, [
|
|
1740
1843
|
chatFirstMode,
|
|
1844
|
+
chatFirstHasActiveChat,
|
|
1741
1845
|
setChatFirstSurfacePanelOpen,
|
|
1742
1846
|
chatFirstSurfaceTabs.tabs.length,
|
|
1743
1847
|
isChatRoute,
|
|
@@ -1756,12 +1860,19 @@ export function Layout({
|
|
|
1756
1860
|
|
|
1757
1861
|
useEffect(() => {
|
|
1758
1862
|
const pending = pendingChatFirstOpenAppRef.current;
|
|
1759
|
-
if (
|
|
1863
|
+
if (
|
|
1864
|
+
!pending ||
|
|
1865
|
+
chatFirstAppsQuery.isLoading ||
|
|
1866
|
+
chatFirstGrantedAppsQuery.isLoading
|
|
1867
|
+
)
|
|
1868
|
+
return;
|
|
1760
1869
|
resolveChatFirstOpenApp(pending);
|
|
1761
1870
|
}, [
|
|
1762
1871
|
chatFirstAppsQuery.data,
|
|
1763
1872
|
chatFirstAppsQuery.isError,
|
|
1764
1873
|
chatFirstAppsQuery.isLoading,
|
|
1874
|
+
chatFirstGrantedAppsQuery.data,
|
|
1875
|
+
chatFirstGrantedAppsQuery.isLoading,
|
|
1765
1876
|
resolveChatFirstOpenApp,
|
|
1766
1877
|
]);
|
|
1767
1878
|
|
|
@@ -1782,28 +1893,6 @@ export function Layout({
|
|
|
1782
1893
|
isChatRoute,
|
|
1783
1894
|
]);
|
|
1784
1895
|
|
|
1785
|
-
useEffect(() => {
|
|
1786
|
-
if (isWorkspaceAppHostRoute) {
|
|
1787
|
-
if (!sidebarAutoCollapsedRef.current) {
|
|
1788
|
-
sidebarAutoCollapsedRef.current = true;
|
|
1789
|
-
sidebarBeforeAppRef.current = sidebarCollapsed;
|
|
1790
|
-
}
|
|
1791
|
-
if (!sidebarCollapsed) setSidebarCollapsed(true);
|
|
1792
|
-
return;
|
|
1793
|
-
}
|
|
1794
|
-
|
|
1795
|
-
if (!sidebarAutoCollapsedRef.current) return;
|
|
1796
|
-
sidebarAutoCollapsedRef.current = false;
|
|
1797
|
-
const previousSidebarState = sidebarBeforeAppRef.current;
|
|
1798
|
-
sidebarBeforeAppRef.current = null;
|
|
1799
|
-
if (
|
|
1800
|
-
previousSidebarState !== null &&
|
|
1801
|
-
previousSidebarState !== sidebarCollapsed
|
|
1802
|
-
) {
|
|
1803
|
-
setSidebarCollapsed(previousSidebarState);
|
|
1804
|
-
}
|
|
1805
|
-
}, [isWorkspaceAppHostRoute, sidebarCollapsed]);
|
|
1806
|
-
|
|
1807
1896
|
useEffect(() => {
|
|
1808
1897
|
if (typeof window === "undefined" || isWorkspaceAppHostRoute) return;
|
|
1809
1898
|
try {
|
|
@@ -1823,6 +1912,7 @@ export function Layout({
|
|
|
1823
1912
|
closeChatFirstSessionWatch();
|
|
1824
1913
|
persistChatFirstPane({
|
|
1825
1914
|
appId: tab.appId,
|
|
1915
|
+
placement: tab.placement,
|
|
1826
1916
|
...(tab.path ? { path: tab.path } : {}),
|
|
1827
1917
|
...(tab.view ? { view: tab.view } : {}),
|
|
1828
1918
|
});
|
|
@@ -1900,11 +1990,17 @@ export function Layout({
|
|
|
1900
1990
|
(tab: ChatFirstSurfaceTab) => {
|
|
1901
1991
|
if (tab.kind === "app") {
|
|
1902
1992
|
if (tab.id !== chatFirstSurfaceTabs.activeTabId) return null;
|
|
1903
|
-
const
|
|
1904
|
-
? (
|
|
1993
|
+
const registration = tab.appId
|
|
1994
|
+
? (chatFirstAppRegistrations.find(
|
|
1905
1995
|
(candidate) => candidate.id === tab.appId,
|
|
1906
1996
|
) ?? null)
|
|
1907
1997
|
: null;
|
|
1998
|
+
const app = registration
|
|
1999
|
+
? {
|
|
2000
|
+
id: registration.id,
|
|
2001
|
+
name: registration.name ?? registration.id,
|
|
2002
|
+
}
|
|
2003
|
+
: null;
|
|
1908
2004
|
return (
|
|
1909
2005
|
<ChatFirstAppPane
|
|
1910
2006
|
app={app}
|
|
@@ -2007,7 +2103,7 @@ export function Layout({
|
|
|
2007
2103
|
chatFirstEmbedUrl,
|
|
2008
2104
|
chatFirstSessionWatch.target,
|
|
2009
2105
|
chatFirstSurfaceTabs.activeTabId,
|
|
2010
|
-
|
|
2106
|
+
chatFirstAppRegistrations,
|
|
2011
2107
|
closeChatFirstSurfaceTab,
|
|
2012
2108
|
renderChatFirstWatchChat,
|
|
2013
2109
|
],
|
|
@@ -2049,7 +2145,7 @@ export function Layout({
|
|
|
2049
2145
|
<div className="relative flex h-full min-w-0 flex-1 flex-col overflow-hidden">
|
|
2050
2146
|
{showHeader ? <Header onOpenMobile={() => setMobileOpen(true)} /> : null}
|
|
2051
2147
|
<InvitationBanner />
|
|
2052
|
-
{isChatRoute && chatFirstMode ? (
|
|
2148
|
+
{isChatRoute && chatFirstMode && chatFirstHasActiveChat ? (
|
|
2053
2149
|
<ChatFirstSurfacePanelToggle
|
|
2054
2150
|
open={chatFirstSurfacePanel.open}
|
|
2055
2151
|
onToggle={chatFirstSurfacePanel.toggle}
|
|
@@ -2075,7 +2171,7 @@ export function Layout({
|
|
|
2075
2171
|
<main
|
|
2076
2172
|
className={cn(
|
|
2077
2173
|
"flex-1",
|
|
2078
|
-
isChatRoute ||
|
|
2174
|
+
isChatRoute || isWorkspaceAppRoute
|
|
2079
2175
|
? "min-h-0 overflow-hidden"
|
|
2080
2176
|
: "overflow-y-auto",
|
|
2081
2177
|
)}
|
|
@@ -2090,6 +2186,50 @@ export function Layout({
|
|
|
2090
2186
|
</main>
|
|
2091
2187
|
</div>
|
|
2092
2188
|
);
|
|
2189
|
+
const chatFirstSurfaceTabsBar =
|
|
2190
|
+
activeChatFirstSurfaceTab?.kind === "app" ? null : (
|
|
2191
|
+
<ChatFirstSurfaceTabs
|
|
2192
|
+
tabs={chatFirstSurfaceTabs.tabs}
|
|
2193
|
+
activeTabId={chatFirstSurfaceTabs.activeTabId}
|
|
2194
|
+
onActivate={activateChatFirstSurfaceTab}
|
|
2195
|
+
onClose={closeChatFirstSurfaceTab}
|
|
2196
|
+
onCloseOthers={(tab) => {
|
|
2197
|
+
activateChatFirstSurfaceTab(tab);
|
|
2198
|
+
chatFirstSurfaceTabsStore.closeOthers(tab.id);
|
|
2199
|
+
}}
|
|
2200
|
+
onCloseToRight={(tab) => {
|
|
2201
|
+
const targetIndex = chatFirstSurfaceTabs.tabs.findIndex(
|
|
2202
|
+
(candidate) => candidate.id === tab.id,
|
|
2203
|
+
);
|
|
2204
|
+
const activeIndex = chatFirstSurfaceTabs.tabs.findIndex(
|
|
2205
|
+
(candidate) => candidate.id === chatFirstSurfaceTabs.activeTabId,
|
|
2206
|
+
);
|
|
2207
|
+
if (activeIndex > targetIndex) activateChatFirstSurfaceTab(tab);
|
|
2208
|
+
chatFirstSurfaceTabsStore.closeToRight(tab.id);
|
|
2209
|
+
}}
|
|
2210
|
+
onCloseAll={closeAllChatFirstSurfaceTabs}
|
|
2211
|
+
onOpenSurface={openChatFirstSurface}
|
|
2212
|
+
apps={chatFirstAppItems}
|
|
2213
|
+
onOpenApp={(app) => openChatFirstPane({ appId: app.id }, "side")}
|
|
2214
|
+
renderAppIcon={(app) => (
|
|
2215
|
+
<AppIcon
|
|
2216
|
+
id={app.id}
|
|
2217
|
+
name={app.name}
|
|
2218
|
+
size="sm"
|
|
2219
|
+
className="size-7 rounded-lg"
|
|
2220
|
+
/>
|
|
2221
|
+
)}
|
|
2222
|
+
copy={chatFirstCopy}
|
|
2223
|
+
/>
|
|
2224
|
+
);
|
|
2225
|
+
const chatFirstSurfaceContent =
|
|
2226
|
+
chatFirstSurfaceTabs.tabs.length > 0 ? (
|
|
2227
|
+
<ChatFirstSurfaceContent
|
|
2228
|
+
tabs={chatFirstSurfaceTabs.tabs}
|
|
2229
|
+
activeTabId={chatFirstSurfaceTabs.activeTabId}
|
|
2230
|
+
renderTab={renderChatFirstSurfaceTab}
|
|
2231
|
+
/>
|
|
2232
|
+
) : null;
|
|
2093
2233
|
const content = isChatRoute ? (
|
|
2094
2234
|
<div
|
|
2095
2235
|
className={cn(
|
|
@@ -2097,47 +2237,33 @@ export function Layout({
|
|
|
2097
2237
|
chatFirstMode && "dispatch-chat-first-surface",
|
|
2098
2238
|
)}
|
|
2099
2239
|
>
|
|
2100
|
-
{
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
onResizePointerDown={chatFirstSurfaceResize.onPointerDown}
|
|
2105
|
-
copy={chatFirstCopy}
|
|
2240
|
+
{chatFirstAppTakesMain ? (
|
|
2241
|
+
<div
|
|
2242
|
+
className="flex min-w-0 flex-1 flex-col overflow-hidden"
|
|
2243
|
+
data-dispatch-chat-first-main-app
|
|
2106
2244
|
>
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
);
|
|
2124
|
-
if (activeIndex > targetIndex) activateChatFirstSurfaceTab(tab);
|
|
2125
|
-
chatFirstSurfaceTabsStore.closeToRight(tab.id);
|
|
2126
|
-
}}
|
|
2127
|
-
onCloseAll={closeAllChatFirstSurfaceTabs}
|
|
2128
|
-
onOpenSurface={openChatFirstSurface}
|
|
2129
|
-
copy={chatFirstCopy}
|
|
2130
|
-
/>
|
|
2131
|
-
{chatFirstSurfaceTabs.tabs.length > 0 ? (
|
|
2132
|
-
<ChatFirstSurfaceContent
|
|
2133
|
-
tabs={chatFirstSurfaceTabs.tabs}
|
|
2134
|
-
activeTabId={chatFirstSurfaceTabs.activeTabId}
|
|
2135
|
-
renderTab={renderChatFirstSurfaceTab}
|
|
2136
|
-
/>
|
|
2245
|
+
{chatFirstSurfaceContent}
|
|
2246
|
+
</div>
|
|
2247
|
+
) : (
|
|
2248
|
+
<>
|
|
2249
|
+
{appContent}
|
|
2250
|
+
{chatFirstMode &&
|
|
2251
|
+
chatFirstHasActiveChat &&
|
|
2252
|
+
chatFirstSurfacePanel.open ? (
|
|
2253
|
+
<ChatFirstSurfacePanel
|
|
2254
|
+
width={chatFirstSurfaceResize.width}
|
|
2255
|
+
onResizePointerDown={chatFirstSurfaceResize.onPointerDown}
|
|
2256
|
+
copy={chatFirstCopy}
|
|
2257
|
+
>
|
|
2258
|
+
{chatFirstSurfaceTabsBar}
|
|
2259
|
+
{chatFirstSurfaceContent}
|
|
2260
|
+
</ChatFirstSurfacePanel>
|
|
2137
2261
|
) : null}
|
|
2138
|
-
|
|
2139
|
-
)
|
|
2262
|
+
</>
|
|
2263
|
+
)}
|
|
2140
2264
|
</div>
|
|
2265
|
+
) : isWorkspaceAppRoute ? (
|
|
2266
|
+
appContent
|
|
2141
2267
|
) : (
|
|
2142
2268
|
<AgentSidebar
|
|
2143
2269
|
position="right"
|
|
@@ -2184,7 +2310,9 @@ export function Layout({
|
|
|
2184
2310
|
? activeChatFirstSurfaceTab.appId
|
|
2185
2311
|
: undefined
|
|
2186
2312
|
}
|
|
2187
|
-
onChatFirstAppOpen={(app) =>
|
|
2313
|
+
onChatFirstAppOpen={(app) =>
|
|
2314
|
+
openChatFirstPane({ appId: app.id }, "main")
|
|
2315
|
+
}
|
|
2188
2316
|
onChatFirstAppsRetry={() => void chatFirstAppsQuery.refetch()}
|
|
2189
2317
|
collapsible
|
|
2190
2318
|
onCollapsedChange={setSidebarCollapsed}
|
|
@@ -2194,7 +2322,7 @@ export function Layout({
|
|
|
2194
2322
|
<Sheet open={mobileOpen} onOpenChange={setMobileOpen}>
|
|
2195
2323
|
<SheetContent
|
|
2196
2324
|
side="left"
|
|
2197
|
-
className="w-72 p-0
|
|
2325
|
+
className="w-72 bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden"
|
|
2198
2326
|
>
|
|
2199
2327
|
<SheetTitle className="sr-only">
|
|
2200
2328
|
{t("dispatch.nav.navigation")}
|
|
@@ -2223,7 +2351,7 @@ export function Layout({
|
|
|
2223
2351
|
: undefined
|
|
2224
2352
|
}
|
|
2225
2353
|
onChatFirstAppOpen={(app) =>
|
|
2226
|
-
openChatFirstPane({ appId: app.id })
|
|
2354
|
+
openChatFirstPane({ appId: app.id }, "main")
|
|
2227
2355
|
}
|
|
2228
2356
|
onChatFirstAppsRetry={() => void chatFirstAppsQuery.refetch()}
|
|
2229
2357
|
onNavigate={() => setMobileOpen(false)}
|