@agent-native/dispatch 0.22.0 → 0.23.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/components/app-icon.d.ts +2 -1
- package/dist/components/app-icon.d.ts.map +1 -1
- package/dist/components/app-icon.js +4 -2
- 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 +91 -57
- 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/package.json +3 -3
- package/src/components/app-icon.tsx +6 -2
- 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 +43 -7
- package/src/components/dispatch-control-plane.tsx +56 -75
- package/src/components/layout/Layout.spec.tsx +121 -1
- package/src/components/layout/Layout.tsx +187 -114
- 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/styles/dispatch.css +2 -2
|
@@ -214,6 +214,16 @@ interface ChatFirstEmbedSessionInput {
|
|
|
214
214
|
chrome: "minimal";
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
+
interface ChatFirstGrantedAppSummary {
|
|
218
|
+
id: string;
|
|
219
|
+
name: string;
|
|
220
|
+
url?: string | null;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
interface ChatFirstGrantedAppsResult {
|
|
224
|
+
apps: ChatFirstGrantedAppSummary[];
|
|
225
|
+
}
|
|
226
|
+
|
|
217
227
|
export function buildChatFirstEmbedSessionInput(
|
|
218
228
|
appId: string,
|
|
219
229
|
path: string,
|
|
@@ -663,7 +673,7 @@ function DispatchChatsSection({
|
|
|
663
673
|
return (
|
|
664
674
|
<div
|
|
665
675
|
className={cn(
|
|
666
|
-
"
|
|
676
|
+
"min-w-0 space-y-0.5",
|
|
667
677
|
showNewChat && "dispatch-chat-first-chats",
|
|
668
678
|
)}
|
|
669
679
|
>
|
|
@@ -730,7 +740,7 @@ function DispatchChatsSection({
|
|
|
730
740
|
<Skeleton className="h-3 w-3/4 rounded" />
|
|
731
741
|
</div>
|
|
732
742
|
))}
|
|
733
|
-
{chatFirstMode ? (
|
|
743
|
+
{chatFirstMode && (chatsLoading || visibleThreads.length > 0) ? (
|
|
734
744
|
<ChatFirstChatHistory
|
|
735
745
|
items={chatItems}
|
|
736
746
|
activeId={displayedActiveThreadId}
|
|
@@ -1005,12 +1015,17 @@ export function NavContent({
|
|
|
1005
1015
|
onChatFirstAppOpen?.(app);
|
|
1006
1016
|
onNavigate?.();
|
|
1007
1017
|
}}
|
|
1018
|
+
onOpenAllApps={() => {
|
|
1019
|
+
navigate(dispatchNavLinkTarget("/apps"));
|
|
1020
|
+
onNavigate?.();
|
|
1021
|
+
}}
|
|
1008
1022
|
createAppTrigger={chatFirstCreateAppTrigger}
|
|
1009
1023
|
renderIcon={(app) => (
|
|
1010
1024
|
<AppIcon
|
|
1011
1025
|
id={app.id}
|
|
1012
1026
|
name={app.name}
|
|
1013
1027
|
size="sm"
|
|
1028
|
+
monochrome
|
|
1014
1029
|
className="size-5 rounded-md"
|
|
1015
1030
|
/>
|
|
1016
1031
|
)}
|
|
@@ -1115,6 +1130,33 @@ export function NavContent({
|
|
|
1115
1130
|
);
|
|
1116
1131
|
};
|
|
1117
1132
|
|
|
1133
|
+
const bottomNavigation = (
|
|
1134
|
+
<nav className={cn("py-1", collapsed ? "px-1.5" : "px-2")}>
|
|
1135
|
+
<ul
|
|
1136
|
+
className={cn(
|
|
1137
|
+
collapsed ? "flex flex-col items-center gap-1" : "space-y-0.5",
|
|
1138
|
+
)}
|
|
1139
|
+
>
|
|
1140
|
+
{BOTTOM_NAV_ITEMS.map(renderNavItem)}
|
|
1141
|
+
</ul>
|
|
1142
|
+
</nav>
|
|
1143
|
+
);
|
|
1144
|
+
const organizationPicker = (
|
|
1145
|
+
<div
|
|
1146
|
+
className={cn("py-2", collapsed ? "flex justify-center px-1" : "px-3")}
|
|
1147
|
+
>
|
|
1148
|
+
<OrgSwitcher compact={collapsed} reserveSpace />
|
|
1149
|
+
</div>
|
|
1150
|
+
);
|
|
1151
|
+
const sidebarFooterActions = (
|
|
1152
|
+
<SidebarFooterActions
|
|
1153
|
+
collapsed={collapsed}
|
|
1154
|
+
feedback={feedbackButton}
|
|
1155
|
+
search={searchButton}
|
|
1156
|
+
collapse={collapseButton}
|
|
1157
|
+
/>
|
|
1158
|
+
);
|
|
1159
|
+
|
|
1118
1160
|
return (
|
|
1119
1161
|
<>
|
|
1120
1162
|
<div
|
|
@@ -1206,39 +1248,16 @@ export function NavContent({
|
|
|
1206
1248
|
</nav>
|
|
1207
1249
|
|
|
1208
1250
|
<div className="mt-auto shrink-0">
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
className={cn(
|
|
1212
|
-
collapsed ? "flex flex-col items-center gap-1" : "space-y-0.5",
|
|
1213
|
-
)}
|
|
1214
|
-
>
|
|
1215
|
-
{BOTTOM_NAV_ITEMS.map(renderNavItem)}
|
|
1216
|
-
</ul>
|
|
1217
|
-
</nav>
|
|
1218
|
-
<div
|
|
1219
|
-
className={cn(
|
|
1220
|
-
"py-2",
|
|
1221
|
-
collapsed ? "flex justify-center px-1" : "px-3",
|
|
1222
|
-
)}
|
|
1223
|
-
>
|
|
1224
|
-
<OrgSwitcher compact={collapsed} reserveSpace />
|
|
1225
|
-
</div>
|
|
1251
|
+
{bottomNavigation}
|
|
1252
|
+
{organizationPicker}
|
|
1226
1253
|
</div>
|
|
1227
|
-
|
|
1228
|
-
collapsed={collapsed}
|
|
1229
|
-
feedback={feedbackButton}
|
|
1230
|
-
search={searchButton}
|
|
1231
|
-
collapse={collapseButton}
|
|
1232
|
-
/>
|
|
1254
|
+
{sidebarFooterActions}
|
|
1233
1255
|
</div>
|
|
1234
|
-
{chatFirstMode
|
|
1256
|
+
{chatFirstMode ? (
|
|
1235
1257
|
<div className="mt-auto shrink-0">
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
search={searchButton}
|
|
1240
|
-
collapse={collapseButton}
|
|
1241
|
-
/>
|
|
1258
|
+
{bottomNavigation}
|
|
1259
|
+
{organizationPicker}
|
|
1260
|
+
{collapsed ? sidebarFooterActions : null}
|
|
1242
1261
|
</div>
|
|
1243
1262
|
) : null}
|
|
1244
1263
|
</>
|
|
@@ -1270,7 +1289,11 @@ export function Layout({
|
|
|
1270
1289
|
const isChatRoute =
|
|
1271
1290
|
localPathname === "/chat" || localPathname.startsWith("/chat/");
|
|
1272
1291
|
const chatFirstSurfaceScope = threadIdFromPath(localPathname) ?? "new";
|
|
1273
|
-
const
|
|
1292
|
+
const isWorkspaceAppRoute = localPathname.startsWith("/apps/");
|
|
1293
|
+
const isWorkspaceAppHostRoute =
|
|
1294
|
+
isWorkspaceAppRoute &&
|
|
1295
|
+
typeof window !== "undefined" &&
|
|
1296
|
+
new URLSearchParams(window.location.search).get("embedded") === "1";
|
|
1274
1297
|
const [chatFirstPreference, setChatFirstPreference] = useState(() =>
|
|
1275
1298
|
readChatFirstMode(),
|
|
1276
1299
|
);
|
|
@@ -1285,23 +1308,40 @@ export function Layout({
|
|
|
1285
1308
|
const chatFirstAppsQuery = useActionQuery<WorkspaceAppSummary[]>(
|
|
1286
1309
|
"list-workspace-apps",
|
|
1287
1310
|
{ includeAgentCards: false },
|
|
1288
|
-
{ enabled: chatFirstMode
|
|
1311
|
+
{ enabled: chatFirstMode },
|
|
1312
|
+
);
|
|
1313
|
+
const chatFirstGrantedAppsQuery = useActionQuery<ChatFirstGrantedAppsResult>(
|
|
1314
|
+
"list_apps",
|
|
1315
|
+
{},
|
|
1316
|
+
{ enabled: chatFirstMode },
|
|
1289
1317
|
);
|
|
1290
1318
|
const chatFirstWorkspaceApps = useMemo(
|
|
1291
1319
|
() => mergeChatFirstWorkspaceApps(chatFirstAppsQuery.data),
|
|
1292
1320
|
[chatFirstAppsQuery.data],
|
|
1293
1321
|
);
|
|
1294
|
-
const chatFirstAppRegistrations = useMemo<ChatFirstAppRegistration[]>(
|
|
1295
|
-
()
|
|
1296
|
-
|
|
1322
|
+
const chatFirstAppRegistrations = useMemo<ChatFirstAppRegistration[]>(() => {
|
|
1323
|
+
const registrations = new Map<string, ChatFirstAppRegistration>();
|
|
1324
|
+
for (const app of chatFirstWorkspaceApps) {
|
|
1325
|
+
registrations.set(app.id.toLowerCase(), {
|
|
1297
1326
|
id: app.id,
|
|
1298
1327
|
name: app.name,
|
|
1299
1328
|
path: app.path,
|
|
1300
1329
|
url: app.url,
|
|
1301
1330
|
enabled: app.status !== "pending" && app.archived !== true,
|
|
1302
|
-
})
|
|
1303
|
-
|
|
1304
|
-
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
for (const app of chatFirstGrantedAppsQuery.data?.apps ?? []) {
|
|
1334
|
+
const id = app.id.trim();
|
|
1335
|
+
if (!id || registrations.has(id.toLowerCase())) continue;
|
|
1336
|
+
registrations.set(id.toLowerCase(), {
|
|
1337
|
+
id,
|
|
1338
|
+
name: app.name,
|
|
1339
|
+
url: app.url,
|
|
1340
|
+
enabled: true,
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
return [...registrations.values()];
|
|
1344
|
+
}, [chatFirstGrantedAppsQuery.data?.apps, chatFirstWorkspaceApps]);
|
|
1305
1345
|
const chatFirstAppItems = useMemo<ChatFirstAppItem[]>(
|
|
1306
1346
|
() =>
|
|
1307
1347
|
chatFirstWorkspaceApps.map((app) => ({
|
|
@@ -1358,15 +1398,29 @@ export function Layout({
|
|
|
1358
1398
|
) ?? null,
|
|
1359
1399
|
[chatFirstSurfaceTabs],
|
|
1360
1400
|
);
|
|
1361
|
-
const
|
|
1401
|
+
const chatFirstAppTakesMain =
|
|
1402
|
+
chatFirstMode && isChatRoute && activeChatFirstSurfaceTab?.kind === "app";
|
|
1403
|
+
const activeChatFirstAppRegistration = useMemo(
|
|
1362
1404
|
() =>
|
|
1363
1405
|
activeChatFirstSurfaceTab?.kind === "app" &&
|
|
1364
1406
|
activeChatFirstSurfaceTab.appId
|
|
1365
|
-
? (
|
|
1407
|
+
? (chatFirstAppRegistrations.find(
|
|
1366
1408
|
(app) => app.id === activeChatFirstSurfaceTab.appId,
|
|
1367
1409
|
) ?? null)
|
|
1368
1410
|
: null,
|
|
1369
|
-
[activeChatFirstSurfaceTab,
|
|
1411
|
+
[activeChatFirstSurfaceTab, chatFirstAppRegistrations],
|
|
1412
|
+
);
|
|
1413
|
+
const activeChatFirstApp = useMemo(
|
|
1414
|
+
() =>
|
|
1415
|
+
activeChatFirstAppRegistration
|
|
1416
|
+
? {
|
|
1417
|
+
id: activeChatFirstAppRegistration.id,
|
|
1418
|
+
name:
|
|
1419
|
+
activeChatFirstAppRegistration.name ??
|
|
1420
|
+
activeChatFirstAppRegistration.id,
|
|
1421
|
+
}
|
|
1422
|
+
: null,
|
|
1423
|
+
[activeChatFirstAppRegistration],
|
|
1370
1424
|
);
|
|
1371
1425
|
const chatFirstAgentActivities = useMemo<ChatFirstAgentActivity[]>(
|
|
1372
1426
|
() =>
|
|
@@ -1384,7 +1438,8 @@ export function Layout({
|
|
|
1384
1438
|
activeChatFirstSurfaceTab?.kind === "app"
|
|
1385
1439
|
? (activeChatFirstSurfaceTab.path ??
|
|
1386
1440
|
chatFirstPane?.path ??
|
|
1387
|
-
|
|
1441
|
+
activeChatFirstAppRegistration?.path ??
|
|
1442
|
+
"/")
|
|
1388
1443
|
: null;
|
|
1389
1444
|
useEffect(() => {
|
|
1390
1445
|
if (!chatFirstMode || !isChatRoute || !activeChatFirstApp) {
|
|
@@ -1446,6 +1501,12 @@ export function Layout({
|
|
|
1446
1501
|
(pane: DispatchChatFirstPane) => {
|
|
1447
1502
|
setChatFirstNotice(null);
|
|
1448
1503
|
closeChatFirstSessionWatch();
|
|
1504
|
+
if (!isChatRoute) {
|
|
1505
|
+
navigateWithAgentChatViewTransition(
|
|
1506
|
+
navigate,
|
|
1507
|
+
dispatchNavLinkTarget("/chat"),
|
|
1508
|
+
);
|
|
1509
|
+
}
|
|
1449
1510
|
const app = chatFirstAppRegistrations.find(
|
|
1450
1511
|
(candidate) => candidate.id === pane.appId,
|
|
1451
1512
|
);
|
|
@@ -1460,12 +1521,16 @@ export function Layout({
|
|
|
1460
1521
|
...(pane.path ? { path: pane.path } : {}),
|
|
1461
1522
|
...(pane.view ? { view: pane.view } : {}),
|
|
1462
1523
|
});
|
|
1524
|
+
setChatFirstSurfacePanelOpen(true);
|
|
1463
1525
|
persistChatFirstPane(pane);
|
|
1464
1526
|
},
|
|
1465
1527
|
[
|
|
1466
1528
|
chatFirstAppRegistrations,
|
|
1467
1529
|
chatFirstSurfaceTabsStore,
|
|
1468
1530
|
persistChatFirstPane,
|
|
1531
|
+
isChatRoute,
|
|
1532
|
+
navigate,
|
|
1533
|
+
setChatFirstSurfacePanelOpen,
|
|
1469
1534
|
],
|
|
1470
1535
|
);
|
|
1471
1536
|
const openChatFirstSurface = useCallback(
|
|
@@ -1504,7 +1569,7 @@ export function Layout({
|
|
|
1504
1569
|
);
|
|
1505
1570
|
const resolveChatFirstOpenApp = useCallback(
|
|
1506
1571
|
(detail: ChatFirstOpenAppDetail) => {
|
|
1507
|
-
if (chatFirstAppsQuery.isLoading) {
|
|
1572
|
+
if (chatFirstAppsQuery.isLoading || chatFirstGrantedAppsQuery.isLoading) {
|
|
1508
1573
|
pendingChatFirstOpenAppRef.current = detail;
|
|
1509
1574
|
return;
|
|
1510
1575
|
}
|
|
@@ -1535,11 +1600,10 @@ export function Layout({
|
|
|
1535
1600
|
chatFirstAppRegistrations,
|
|
1536
1601
|
chatFirstAppsQuery.isError,
|
|
1537
1602
|
chatFirstAppsQuery.isLoading,
|
|
1603
|
+
chatFirstGrantedAppsQuery.isLoading,
|
|
1538
1604
|
openChatFirstPane,
|
|
1539
1605
|
],
|
|
1540
1606
|
);
|
|
1541
|
-
const sidebarBeforeAppRef = useRef<boolean | null>(null);
|
|
1542
|
-
const sidebarAutoCollapsedRef = useRef(false);
|
|
1543
1607
|
const chatHomeHandoffActive = useAgentChatHomeHandoff({
|
|
1544
1608
|
storageKey: "dispatch",
|
|
1545
1609
|
activePath: localPathname,
|
|
@@ -1610,7 +1674,7 @@ export function Layout({
|
|
|
1610
1674
|
);
|
|
1611
1675
|
|
|
1612
1676
|
useEffect(() => {
|
|
1613
|
-
if (!chatFirstMode
|
|
1677
|
+
if (!chatFirstMode) {
|
|
1614
1678
|
setChatFirstPane(null);
|
|
1615
1679
|
closeChatFirstSessionWatch();
|
|
1616
1680
|
chatFirstSurfaceTabsStore.closeAll();
|
|
@@ -1713,7 +1777,7 @@ export function Layout({
|
|
|
1713
1777
|
useEffect(() => {
|
|
1714
1778
|
const tabCount = chatFirstSurfaceTabs.tabs.length;
|
|
1715
1779
|
const previousTabCount = previousChatFirstSurfaceTabCountRef.current;
|
|
1716
|
-
if (!chatFirstMode
|
|
1780
|
+
if (!chatFirstMode) {
|
|
1717
1781
|
setChatFirstSurfacePanelOpen(false);
|
|
1718
1782
|
} else if (
|
|
1719
1783
|
tabCount > 0 &&
|
|
@@ -1748,12 +1812,19 @@ export function Layout({
|
|
|
1748
1812
|
|
|
1749
1813
|
useEffect(() => {
|
|
1750
1814
|
const pending = pendingChatFirstOpenAppRef.current;
|
|
1751
|
-
if (
|
|
1815
|
+
if (
|
|
1816
|
+
!pending ||
|
|
1817
|
+
chatFirstAppsQuery.isLoading ||
|
|
1818
|
+
chatFirstGrantedAppsQuery.isLoading
|
|
1819
|
+
)
|
|
1820
|
+
return;
|
|
1752
1821
|
resolveChatFirstOpenApp(pending);
|
|
1753
1822
|
}, [
|
|
1754
1823
|
chatFirstAppsQuery.data,
|
|
1755
1824
|
chatFirstAppsQuery.isError,
|
|
1756
1825
|
chatFirstAppsQuery.isLoading,
|
|
1826
|
+
chatFirstGrantedAppsQuery.data,
|
|
1827
|
+
chatFirstGrantedAppsQuery.isLoading,
|
|
1757
1828
|
resolveChatFirstOpenApp,
|
|
1758
1829
|
]);
|
|
1759
1830
|
|
|
@@ -1774,28 +1845,6 @@ export function Layout({
|
|
|
1774
1845
|
isChatRoute,
|
|
1775
1846
|
]);
|
|
1776
1847
|
|
|
1777
|
-
useEffect(() => {
|
|
1778
|
-
if (isWorkspaceAppHostRoute) {
|
|
1779
|
-
if (!sidebarAutoCollapsedRef.current) {
|
|
1780
|
-
sidebarAutoCollapsedRef.current = true;
|
|
1781
|
-
sidebarBeforeAppRef.current = sidebarCollapsed;
|
|
1782
|
-
}
|
|
1783
|
-
if (!sidebarCollapsed) setSidebarCollapsed(true);
|
|
1784
|
-
return;
|
|
1785
|
-
}
|
|
1786
|
-
|
|
1787
|
-
if (!sidebarAutoCollapsedRef.current) return;
|
|
1788
|
-
sidebarAutoCollapsedRef.current = false;
|
|
1789
|
-
const previousSidebarState = sidebarBeforeAppRef.current;
|
|
1790
|
-
sidebarBeforeAppRef.current = null;
|
|
1791
|
-
if (
|
|
1792
|
-
previousSidebarState !== null &&
|
|
1793
|
-
previousSidebarState !== sidebarCollapsed
|
|
1794
|
-
) {
|
|
1795
|
-
setSidebarCollapsed(previousSidebarState);
|
|
1796
|
-
}
|
|
1797
|
-
}, [isWorkspaceAppHostRoute, sidebarCollapsed]);
|
|
1798
|
-
|
|
1799
1848
|
useEffect(() => {
|
|
1800
1849
|
if (typeof window === "undefined" || isWorkspaceAppHostRoute) return;
|
|
1801
1850
|
try {
|
|
@@ -1892,11 +1941,17 @@ export function Layout({
|
|
|
1892
1941
|
(tab: ChatFirstSurfaceTab) => {
|
|
1893
1942
|
if (tab.kind === "app") {
|
|
1894
1943
|
if (tab.id !== chatFirstSurfaceTabs.activeTabId) return null;
|
|
1895
|
-
const
|
|
1896
|
-
? (
|
|
1944
|
+
const registration = tab.appId
|
|
1945
|
+
? (chatFirstAppRegistrations.find(
|
|
1897
1946
|
(candidate) => candidate.id === tab.appId,
|
|
1898
1947
|
) ?? null)
|
|
1899
1948
|
: null;
|
|
1949
|
+
const app = registration
|
|
1950
|
+
? {
|
|
1951
|
+
id: registration.id,
|
|
1952
|
+
name: registration.name ?? registration.id,
|
|
1953
|
+
}
|
|
1954
|
+
: null;
|
|
1900
1955
|
return (
|
|
1901
1956
|
<ChatFirstAppPane
|
|
1902
1957
|
app={app}
|
|
@@ -1999,7 +2054,7 @@ export function Layout({
|
|
|
1999
2054
|
chatFirstEmbedUrl,
|
|
2000
2055
|
chatFirstSessionWatch.target,
|
|
2001
2056
|
chatFirstSurfaceTabs.activeTabId,
|
|
2002
|
-
|
|
2057
|
+
chatFirstAppRegistrations,
|
|
2003
2058
|
closeChatFirstSurfaceTab,
|
|
2004
2059
|
renderChatFirstWatchChat,
|
|
2005
2060
|
],
|
|
@@ -2067,7 +2122,7 @@ export function Layout({
|
|
|
2067
2122
|
<main
|
|
2068
2123
|
className={cn(
|
|
2069
2124
|
"flex-1",
|
|
2070
|
-
isChatRoute ||
|
|
2125
|
+
isChatRoute || isWorkspaceAppRoute
|
|
2071
2126
|
? "min-h-0 overflow-hidden"
|
|
2072
2127
|
: "overflow-y-auto",
|
|
2073
2128
|
)}
|
|
@@ -2082,6 +2137,40 @@ export function Layout({
|
|
|
2082
2137
|
</main>
|
|
2083
2138
|
</div>
|
|
2084
2139
|
);
|
|
2140
|
+
const chatFirstSurfaceTabsBar =
|
|
2141
|
+
activeChatFirstSurfaceTab?.kind === "app" ? null : (
|
|
2142
|
+
<ChatFirstSurfaceTabs
|
|
2143
|
+
tabs={chatFirstSurfaceTabs.tabs}
|
|
2144
|
+
activeTabId={chatFirstSurfaceTabs.activeTabId}
|
|
2145
|
+
onActivate={activateChatFirstSurfaceTab}
|
|
2146
|
+
onClose={closeChatFirstSurfaceTab}
|
|
2147
|
+
onCloseOthers={(tab) => {
|
|
2148
|
+
activateChatFirstSurfaceTab(tab);
|
|
2149
|
+
chatFirstSurfaceTabsStore.closeOthers(tab.id);
|
|
2150
|
+
}}
|
|
2151
|
+
onCloseToRight={(tab) => {
|
|
2152
|
+
const targetIndex = chatFirstSurfaceTabs.tabs.findIndex(
|
|
2153
|
+
(candidate) => candidate.id === tab.id,
|
|
2154
|
+
);
|
|
2155
|
+
const activeIndex = chatFirstSurfaceTabs.tabs.findIndex(
|
|
2156
|
+
(candidate) => candidate.id === chatFirstSurfaceTabs.activeTabId,
|
|
2157
|
+
);
|
|
2158
|
+
if (activeIndex > targetIndex) activateChatFirstSurfaceTab(tab);
|
|
2159
|
+
chatFirstSurfaceTabsStore.closeToRight(tab.id);
|
|
2160
|
+
}}
|
|
2161
|
+
onCloseAll={closeAllChatFirstSurfaceTabs}
|
|
2162
|
+
onOpenSurface={openChatFirstSurface}
|
|
2163
|
+
copy={chatFirstCopy}
|
|
2164
|
+
/>
|
|
2165
|
+
);
|
|
2166
|
+
const chatFirstSurfaceContent =
|
|
2167
|
+
chatFirstSurfaceTabs.tabs.length > 0 ? (
|
|
2168
|
+
<ChatFirstSurfaceContent
|
|
2169
|
+
tabs={chatFirstSurfaceTabs.tabs}
|
|
2170
|
+
activeTabId={chatFirstSurfaceTabs.activeTabId}
|
|
2171
|
+
renderTab={renderChatFirstSurfaceTab}
|
|
2172
|
+
/>
|
|
2173
|
+
) : null;
|
|
2085
2174
|
const content = isChatRoute ? (
|
|
2086
2175
|
<div
|
|
2087
2176
|
className={cn(
|
|
@@ -2089,47 +2178,31 @@ export function Layout({
|
|
|
2089
2178
|
chatFirstMode && "dispatch-chat-first-surface",
|
|
2090
2179
|
)}
|
|
2091
2180
|
>
|
|
2092
|
-
{
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
onResizePointerDown={chatFirstSurfaceResize.onPointerDown}
|
|
2097
|
-
copy={chatFirstCopy}
|
|
2181
|
+
{chatFirstAppTakesMain ? (
|
|
2182
|
+
<div
|
|
2183
|
+
className="flex min-w-0 flex-1 flex-col overflow-hidden"
|
|
2184
|
+
data-dispatch-chat-first-main-app
|
|
2098
2185
|
>
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
(candidate) =>
|
|
2114
|
-
candidate.id === chatFirstSurfaceTabs.activeTabId,
|
|
2115
|
-
);
|
|
2116
|
-
if (activeIndex > targetIndex) activateChatFirstSurfaceTab(tab);
|
|
2117
|
-
chatFirstSurfaceTabsStore.closeToRight(tab.id);
|
|
2118
|
-
}}
|
|
2119
|
-
onCloseAll={closeAllChatFirstSurfaceTabs}
|
|
2120
|
-
onOpenSurface={openChatFirstSurface}
|
|
2121
|
-
copy={chatFirstCopy}
|
|
2122
|
-
/>
|
|
2123
|
-
{chatFirstSurfaceTabs.tabs.length > 0 ? (
|
|
2124
|
-
<ChatFirstSurfaceContent
|
|
2125
|
-
tabs={chatFirstSurfaceTabs.tabs}
|
|
2126
|
-
activeTabId={chatFirstSurfaceTabs.activeTabId}
|
|
2127
|
-
renderTab={renderChatFirstSurfaceTab}
|
|
2128
|
-
/>
|
|
2186
|
+
{chatFirstSurfaceContent}
|
|
2187
|
+
</div>
|
|
2188
|
+
) : (
|
|
2189
|
+
<>
|
|
2190
|
+
{appContent}
|
|
2191
|
+
{chatFirstMode && chatFirstSurfacePanel.open ? (
|
|
2192
|
+
<ChatFirstSurfacePanel
|
|
2193
|
+
width={chatFirstSurfaceResize.width}
|
|
2194
|
+
onResizePointerDown={chatFirstSurfaceResize.onPointerDown}
|
|
2195
|
+
copy={chatFirstCopy}
|
|
2196
|
+
>
|
|
2197
|
+
{chatFirstSurfaceTabsBar}
|
|
2198
|
+
{chatFirstSurfaceContent}
|
|
2199
|
+
</ChatFirstSurfacePanel>
|
|
2129
2200
|
) : null}
|
|
2130
|
-
|
|
2131
|
-
)
|
|
2201
|
+
</>
|
|
2202
|
+
)}
|
|
2132
2203
|
</div>
|
|
2204
|
+
) : isWorkspaceAppRoute ? (
|
|
2205
|
+
appContent
|
|
2133
2206
|
) : (
|
|
2134
2207
|
<AgentSidebar
|
|
2135
2208
|
position="right"
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
-
import { IconStack2 } from "@tabler/icons-react";
|
|
3
2
|
|
|
4
3
|
import { filterOtherApps, type ConnectedAppSummary } from "../lib/other-apps";
|
|
5
4
|
import type { WorkspaceAppId } from "../lib/other-apps";
|
|
@@ -80,6 +79,8 @@ export function OtherAppsSection({
|
|
|
80
79
|
onRetryConnectedApps,
|
|
81
80
|
templateLabels,
|
|
82
81
|
onRemixSuccess,
|
|
82
|
+
heading = "Other apps",
|
|
83
|
+
embeddedInList = false,
|
|
83
84
|
className,
|
|
84
85
|
}: {
|
|
85
86
|
templates?: CuratedWorkspaceTemplatesResult;
|
|
@@ -96,6 +97,8 @@ export function OtherAppsSection({
|
|
|
96
97
|
result: unknown,
|
|
97
98
|
template: CuratedWorkspaceTemplate,
|
|
98
99
|
) => void;
|
|
100
|
+
heading?: string | null;
|
|
101
|
+
embeddedInList?: boolean;
|
|
99
102
|
className?: string;
|
|
100
103
|
}) {
|
|
101
104
|
const t = useT();
|
|
@@ -109,26 +112,15 @@ export function OtherAppsSection({
|
|
|
109
112
|
|
|
110
113
|
if (!isLoading && !hasError && entries.length === 0) return null;
|
|
111
114
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
<
|
|
116
|
-
size={16}
|
|
117
|
-
className="mt-0.5 shrink-0 text-muted-foreground"
|
|
118
|
-
/>
|
|
119
|
-
<div className="min-w-0">
|
|
115
|
+
const content = (
|
|
116
|
+
<>
|
|
117
|
+
{heading ? (
|
|
118
|
+
<div className="flex min-w-0 items-center">
|
|
120
119
|
<h2 className="truncate text-sm font-semibold text-foreground">
|
|
121
|
-
{t("dispatch.pages.otherApps", { defaultValue:
|
|
120
|
+
{t("dispatch.pages.otherApps", { defaultValue: heading })}
|
|
122
121
|
</h2>
|
|
123
|
-
{entries.length > 0 ? (
|
|
124
|
-
<p className="mt-0.5 text-xs text-muted-foreground">
|
|
125
|
-
{t("dispatch.pages.availableCount", {
|
|
126
|
-
count: entries.length,
|
|
127
|
-
})}
|
|
128
|
-
</p>
|
|
129
|
-
) : null}
|
|
130
122
|
</div>
|
|
131
|
-
|
|
123
|
+
) : null}
|
|
132
124
|
|
|
133
125
|
{templatesError ? (
|
|
134
126
|
<ActionQueryError
|
|
@@ -144,31 +136,37 @@ export function OtherAppsSection({
|
|
|
144
136
|
) : null}
|
|
145
137
|
|
|
146
138
|
{isLoading && entries.length === 0 ? (
|
|
147
|
-
|
|
139
|
+
embeddedInList ? (
|
|
140
|
+
<OtherAppsSkeletonRows />
|
|
141
|
+
) : (
|
|
142
|
+
<OtherAppsSkeletonList />
|
|
143
|
+
)
|
|
148
144
|
) : entries.length > 0 ? (
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
)}
|
|
168
|
-
</AppList>
|
|
145
|
+
entries.map((entry) =>
|
|
146
|
+
entry.kind === "template" ? (
|
|
147
|
+
<WorkspaceTemplateCard
|
|
148
|
+
key={`template:${templateKey(entry.template)}`}
|
|
149
|
+
template={entry.template}
|
|
150
|
+
labels={templateLabels}
|
|
151
|
+
catalog
|
|
152
|
+
className={APP_LIST_GRID_ROW_CLASS}
|
|
153
|
+
onRemixSuccess={onRemixSuccess}
|
|
154
|
+
/>
|
|
155
|
+
) : (
|
|
156
|
+
<ConnectedAppCard
|
|
157
|
+
key={`connected:${entry.app.id}`}
|
|
158
|
+
app={entry.app}
|
|
159
|
+
className={APP_LIST_GRID_ROW_CLASS}
|
|
160
|
+
/>
|
|
161
|
+
),
|
|
162
|
+
)
|
|
169
163
|
) : null}
|
|
170
|
-
|
|
164
|
+
</>
|
|
171
165
|
);
|
|
166
|
+
|
|
167
|
+
if (embeddedInList) return content;
|
|
168
|
+
|
|
169
|
+
return <section className={cn("space-y-3", className)}>{content}</section>;
|
|
172
170
|
}
|
|
173
171
|
|
|
174
172
|
function OtherAppsSkeletonList() {
|
|
@@ -193,3 +191,26 @@ function OtherAppsSkeletonList() {
|
|
|
193
191
|
</AppList>
|
|
194
192
|
);
|
|
195
193
|
}
|
|
194
|
+
|
|
195
|
+
function OtherAppsSkeletonRows() {
|
|
196
|
+
return (
|
|
197
|
+
<>
|
|
198
|
+
{Array.from({ length: 4 }).map((_, index) => (
|
|
199
|
+
<div
|
|
200
|
+
key={index}
|
|
201
|
+
className={cn(
|
|
202
|
+
"flex min-w-0 items-center gap-3 border-b px-4 py-3.5 last:border-b-0",
|
|
203
|
+
APP_LIST_GRID_ROW_CLASS,
|
|
204
|
+
)}
|
|
205
|
+
>
|
|
206
|
+
<Skeleton className="size-8 shrink-0 rounded-xl" />
|
|
207
|
+
<div className="min-w-0 flex-1 space-y-2">
|
|
208
|
+
<Skeleton className="h-4 w-32" />
|
|
209
|
+
<Skeleton className="h-3 w-2/3" />
|
|
210
|
+
</div>
|
|
211
|
+
<Skeleton className="h-9 w-24 shrink-0 rounded-md" />
|
|
212
|
+
</div>
|
|
213
|
+
))}
|
|
214
|
+
</>
|
|
215
|
+
);
|
|
216
|
+
}
|