@agent-native/dispatch 0.24.5 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -1
- package/dist/actions/connect-external-agent.d.ts +18 -0
- package/dist/actions/connect-external-agent.d.ts.map +1 -0
- package/dist/actions/connect-external-agent.js +68 -0
- package/dist/actions/connect-external-agent.js.map +1 -0
- package/dist/actions/create-workspace-resource.d.ts +14 -14
- package/dist/actions/create-workspace-resource.js +9 -2
- package/dist/actions/create-workspace-resource.js.map +1 -1
- package/dist/actions/create_workspace_app_embed_session.d.ts +13 -0
- package/dist/actions/create_workspace_app_embed_session.d.ts.map +1 -0
- package/dist/actions/create_workspace_app_embed_session.js +30 -0
- package/dist/actions/create_workspace_app_embed_session.js.map +1 -0
- package/dist/actions/import-agent-pack.d.ts +96 -0
- package/dist/actions/import-agent-pack.d.ts.map +1 -0
- package/dist/actions/import-agent-pack.js +116 -0
- package/dist/actions/import-agent-pack.js.map +1 -0
- package/dist/actions/import-agent.d.ts +60 -0
- package/dist/actions/import-agent.d.ts.map +1 -0
- package/dist/actions/import-agent.js +82 -0
- package/dist/actions/import-agent.js.map +1 -0
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +10 -0
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/list-agent-pack.d.ts +36 -0
- package/dist/actions/list-agent-pack.d.ts.map +1 -0
- package/dist/actions/list-agent-pack.js +32 -0
- package/dist/actions/list-agent-pack.js.map +1 -0
- package/dist/actions/list-workspace-resource-options.d.ts +1 -1
- package/dist/actions/list-workspace-resource-options.js +8 -1
- package/dist/actions/list-workspace-resource-options.js.map +1 -1
- package/dist/actions/list-workspace-resources.d.ts +1 -1
- package/dist/actions/list-workspace-resources.js +8 -1
- package/dist/actions/list-workspace-resources.js.map +1 -1
- package/dist/actions/navigate.js +1 -1
- package/dist/actions/navigate.js.map +1 -1
- package/dist/actions/provider-api-register.d.ts +10 -10
- package/dist/actions/update-workspace-resource.d.ts +13 -13
- package/dist/actions/view-screen.js +18 -1
- package/dist/actions/view-screen.js.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/layout/Layout.d.ts +1 -8
- package/dist/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +33 -106
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/simple-agents-panel.d.ts +9 -0
- package/dist/components/simple-agents-panel.d.ts.map +1 -0
- package/dist/components/simple-agents-panel.js +405 -0
- package/dist/components/simple-agents-panel.js.map +1 -0
- package/dist/components/workspace-app-host.d.ts +29 -0
- package/dist/components/workspace-app-host.d.ts.map +1 -0
- package/dist/components/workspace-app-host.js +145 -0
- package/dist/components/workspace-app-host.js.map +1 -0
- package/dist/db/migrations.d.ts +2 -4
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +25 -0
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/schema.js +1 -1
- package/dist/db/schema.js.map +1 -1
- package/dist/hooks/use-navigation-state.d.ts +1 -0
- package/dist/hooks/use-navigation-state.d.ts.map +1 -1
- package/dist/hooks/use-navigation-state.js +10 -0
- package/dist/hooks/use-navigation-state.js.map +1 -1
- package/dist/lib/agent-pack.d.ts +31 -0
- package/dist/lib/agent-pack.d.ts.map +1 -0
- package/dist/lib/agent-pack.js +149 -0
- package/dist/lib/agent-pack.js.map +1 -0
- package/dist/lib/simple-agent-profile.d.ts +36 -0
- package/dist/lib/simple-agent-profile.d.ts.map +1 -0
- package/dist/lib/simple-agent-profile.js +183 -0
- package/dist/lib/simple-agent-profile.js.map +1 -0
- package/dist/routes/pages/agents.d.ts.map +1 -1
- package/dist/routes/pages/agents.js +11 -1
- package/dist/routes/pages/agents.js.map +1 -1
- package/dist/routes/pages/apps.$appId.d.ts.map +1 -1
- package/dist/routes/pages/apps.$appId.js +4 -95
- package/dist/routes/pages/apps.$appId.js.map +1 -1
- package/dist/routes/pages/chat.d.ts.map +1 -1
- package/dist/routes/pages/chat.js +62 -10
- package/dist/routes/pages/chat.js.map +1 -1
- package/dist/server/lib/agent-pack-store.d.ts +24 -0
- package/dist/server/lib/agent-pack-store.d.ts.map +1 -0
- package/dist/server/lib/agent-pack-store.js +22 -0
- package/dist/server/lib/agent-pack-store.js.map +1 -0
- package/dist/server/lib/dispatch-store.d.ts.map +1 -1
- package/dist/server/lib/dispatch-store.js +4 -0
- package/dist/server/lib/dispatch-store.js.map +1 -1
- package/dist/server/lib/mcp-gateway.d.ts +11 -0
- package/dist/server/lib/mcp-gateway.d.ts.map +1 -1
- package/dist/server/lib/mcp-gateway.js +155 -9
- package/dist/server/lib/mcp-gateway.js.map +1 -1
- package/dist/server/lib/workspace-resources-store.d.ts +15 -1
- package/dist/server/lib/workspace-resources-store.d.ts.map +1 -1
- package/dist/server/lib/workspace-resources-store.js +11 -2
- package/dist/server/lib/workspace-resources-store.js.map +1 -1
- package/dist/server/plugins/agent-chat.js +13 -0
- package/dist/server/plugins/agent-chat.js.map +1 -1
- package/dist/shared/feature-flags.d.ts +7 -0
- package/dist/shared/feature-flags.d.ts.map +1 -0
- package/dist/shared/feature-flags.js +12 -0
- package/dist/shared/feature-flags.js.map +1 -0
- package/dist/shared/workspace-sso.d.ts +36 -0
- package/dist/shared/workspace-sso.d.ts.map +1 -0
- package/dist/shared/workspace-sso.js +99 -0
- package/dist/shared/workspace-sso.js.map +1 -0
- package/package.json +5 -3
- package/src/actions/connect-external-agent.ts +92 -0
- package/src/actions/create-workspace-resource.ts +9 -2
- package/src/actions/create_workspace_app_embed_session.ts +32 -0
- package/src/actions/import-agent-pack.ts +146 -0
- package/src/actions/import-agent.ts +102 -0
- package/src/actions/index.spec.ts +13 -0
- package/src/actions/index.ts +10 -0
- package/src/actions/list-agent-pack.ts +43 -0
- package/src/actions/list-workspace-resource-options.ts +8 -1
- package/src/actions/list-workspace-resources.ts +8 -1
- package/src/actions/navigate.ts +1 -1
- package/src/actions/view-screen.spec.ts +29 -1
- package/src/actions/view-screen.ts +19 -1
- package/src/components/app-icon.spec.tsx +10 -0
- package/src/components/index.ts +1 -0
- package/src/components/layout/Layout.spec.tsx +2 -0
- package/src/components/layout/Layout.tsx +59 -171
- package/src/components/simple-agents-panel.spec.tsx +73 -0
- package/src/components/simple-agents-panel.tsx +1226 -0
- package/src/components/workspace-app-host.spec.tsx +204 -0
- package/src/components/workspace-app-host.tsx +359 -0
- package/src/db/migrations.spec.ts +5 -1
- package/src/db/migrations.ts +28 -1
- package/src/db/schema.ts +1 -1
- package/src/hooks/use-navigation-state.spec.ts +25 -0
- package/src/hooks/use-navigation-state.ts +11 -0
- package/src/lib/agent-pack.spec.ts +47 -0
- package/src/lib/agent-pack.ts +226 -0
- package/src/lib/simple-agent-profile.spec.ts +77 -0
- package/src/lib/simple-agent-profile.ts +247 -0
- package/src/routes/index.spec.ts +1 -0
- package/src/routes/pages/agents.tsx +21 -1
- package/src/routes/pages/apps.$appId.tsx +3 -240
- package/src/routes/pages/chat.spec.tsx +62 -0
- package/src/routes/pages/chat.tsx +117 -9
- package/src/server/lib/agent-pack-store.ts +35 -0
- package/src/server/lib/dispatch-store.ts +8 -0
- package/src/server/lib/mcp-gateway.spec.ts +141 -0
- package/src/server/lib/mcp-gateway.ts +227 -15
- package/src/server/lib/workspace-resources-store.ts +9 -2
- package/src/server/plugins/agent-chat.ts +13 -0
- package/src/shared/feature-flags.ts +13 -0
- package/src/shared/workspace-sso.ts +118 -0
|
@@ -93,6 +93,19 @@ export default defineAction({
|
|
|
93
93
|
purpose:
|
|
94
94
|
"Create apps, manage workspace resources, route work to connected agents, and continue Dispatch conversations.",
|
|
95
95
|
};
|
|
96
|
+
const agentPath =
|
|
97
|
+
typeof navigation.agentPath === "string"
|
|
98
|
+
? navigation.agentPath.trim()
|
|
99
|
+
: "";
|
|
100
|
+
if (agentPath) {
|
|
101
|
+
const agents = await listWorkspaceResourceOptions({ kind: "agent" });
|
|
102
|
+
const agent = agents.find((resource) => resource.path === agentPath);
|
|
103
|
+
screen.chatSurface = {
|
|
104
|
+
...(screen.chatSurface as Record<string, unknown>),
|
|
105
|
+
agentPath,
|
|
106
|
+
...(agent ? { agent } : {}),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
96
109
|
}
|
|
97
110
|
if (navigation?.view === "overview") {
|
|
98
111
|
screen.recentAudit = overview.recentAudit.slice(0, 5);
|
|
@@ -101,7 +114,7 @@ export default defineAction({
|
|
|
101
114
|
if (navigation?.view === "destinations") {
|
|
102
115
|
screen.recentDestinations = overview.recentDestinations;
|
|
103
116
|
}
|
|
104
|
-
if (navigation?.view === "agents") {
|
|
117
|
+
if (navigation?.view === "connected-agents") {
|
|
105
118
|
const [connectedAgents, mcpAccess] = await Promise.all([
|
|
106
119
|
runLocalDispatchAction("list-connected-agents", {}),
|
|
107
120
|
runLocalDispatchAction("list-mcp-app-access", {}),
|
|
@@ -109,6 +122,11 @@ export default defineAction({
|
|
|
109
122
|
screen.connectedAgents = connectedAgents;
|
|
110
123
|
screen.mcpAppAccess = mcpAccess;
|
|
111
124
|
}
|
|
125
|
+
if (navigation?.view === "agents") {
|
|
126
|
+
screen.simpleAgents = await listWorkspaceResourceOptions({
|
|
127
|
+
kind: "agent",
|
|
128
|
+
});
|
|
129
|
+
}
|
|
112
130
|
if (navigation?.view === "operations") {
|
|
113
131
|
const nav = navigation as { operationsView?: string };
|
|
114
132
|
screen.operatorConsole = {
|
|
@@ -31,4 +31,14 @@ describe("AppIcon", () => {
|
|
|
31
31
|
);
|
|
32
32
|
expect(icon.style.color).toBe("rgb(var(--dispatch-app-icon-color-rgb))");
|
|
33
33
|
});
|
|
34
|
+
|
|
35
|
+
it("removes the colored background for monochrome rail icons", () => {
|
|
36
|
+
act(() => {
|
|
37
|
+
root.render(<AppIcon id="plan" name="Plan" monochrome />);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const icon = container.firstElementChild as HTMLElement;
|
|
41
|
+
expect(icon.className).toContain("bg-transparent");
|
|
42
|
+
expect(icon.style.cssText).not.toContain("background-color");
|
|
43
|
+
});
|
|
34
44
|
});
|
package/src/components/index.ts
CHANGED
|
@@ -17,3 +17,4 @@ export type {
|
|
|
17
17
|
export { CreateAppPopover, CreateAppFlow } from "./create-app-popover.js";
|
|
18
18
|
export { AppKeysPopover } from "./app-keys-popover.js";
|
|
19
19
|
export { ActionQueryError } from "./action-query-error.js";
|
|
20
|
+
export { SimpleAgentsPanel } from "./simple-agents-panel.js";
|
|
@@ -61,6 +61,7 @@ vi.mock("@agent-native/core/client/i18n", () => ({
|
|
|
61
61
|
"dispatch.nav.chat": "Chat",
|
|
62
62
|
"dispatch.nav.overview": "Overview",
|
|
63
63
|
"dispatch.nav.apps": "Apps",
|
|
64
|
+
"dispatch.nav.agents": "Agents",
|
|
64
65
|
"dispatch.pages.workspaceApps": "Workspace apps",
|
|
65
66
|
"dispatch.nav.operate": "Operate",
|
|
66
67
|
"dispatch.nav.advanced": "Advanced",
|
|
@@ -196,6 +197,7 @@ describe("Dispatch NavContent", () => {
|
|
|
196
197
|
expect(primaryLabels.indexOf("Overview")).toBeLessThan(
|
|
197
198
|
primaryLabels.indexOf("Chat"),
|
|
198
199
|
);
|
|
200
|
+
expect(primaryLabels).toContain("Agents");
|
|
199
201
|
});
|
|
200
202
|
|
|
201
203
|
it("keeps collapsed navigation compact and preserves section spacing", async () => {
|
|
@@ -77,6 +77,7 @@ import {
|
|
|
77
77
|
IconBrandTelegram,
|
|
78
78
|
IconCopy,
|
|
79
79
|
IconEye,
|
|
80
|
+
IconHierarchy2,
|
|
80
81
|
IconMessageQuestion,
|
|
81
82
|
IconBroadcast,
|
|
82
83
|
IconLayoutSidebarLeftCollapse,
|
|
@@ -102,13 +103,11 @@ import {
|
|
|
102
103
|
import { Link, useLocation, useNavigate } from "react-router";
|
|
103
104
|
import { toast } from "sonner";
|
|
104
105
|
|
|
105
|
-
import { isEmbedSessionExpiredMessage } from "../../lib/embed-session-recovery";
|
|
106
106
|
import { cn } from "../../lib/utils";
|
|
107
107
|
import {
|
|
108
108
|
isDispatchWorkspaceAppId,
|
|
109
109
|
isWorkspaceAppVisibleInDefaultLaunchers,
|
|
110
110
|
mergeChatFirstWorkspaceApps,
|
|
111
|
-
workspaceAppDirectHref,
|
|
112
111
|
workspaceAppIdFromRoute,
|
|
113
112
|
workspaceAppRoute,
|
|
114
113
|
type WorkspaceAppSummary,
|
|
@@ -124,9 +123,15 @@ import {
|
|
|
124
123
|
import { Sheet, SheetContent, SheetDescription, SheetTitle } from "../ui/sheet";
|
|
125
124
|
import { Skeleton } from "../ui/skeleton";
|
|
126
125
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
|
|
126
|
+
import {
|
|
127
|
+
WorkspaceAppFrame,
|
|
128
|
+
WorkspaceAppKeepAlive,
|
|
129
|
+
} from "../workspace-app-host";
|
|
127
130
|
import { Header } from "./Header";
|
|
128
131
|
import { HeaderActionsProvider } from "./HeaderActions";
|
|
129
132
|
|
|
133
|
+
export { buildChatFirstEmbedSessionInput } from "../workspace-app-host";
|
|
134
|
+
|
|
130
135
|
export type DispatchNavSection = "primary" | "operations";
|
|
131
136
|
|
|
132
137
|
export type DispatchNavIcon = ComponentType<{
|
|
@@ -180,6 +185,13 @@ const PRIMARY_NAV_ITEMS = [
|
|
|
180
185
|
icon: IconApps,
|
|
181
186
|
section: "primary",
|
|
182
187
|
},
|
|
188
|
+
{
|
|
189
|
+
id: "agents",
|
|
190
|
+
to: "/agents",
|
|
191
|
+
label: "Agents",
|
|
192
|
+
icon: IconHierarchy2,
|
|
193
|
+
section: "primary",
|
|
194
|
+
},
|
|
183
195
|
] as const satisfies readonly DispatchNavItem[];
|
|
184
196
|
|
|
185
197
|
const BOTTOM_NAV_ITEMS = [
|
|
@@ -212,17 +224,6 @@ interface DispatchChatFirstPane {
|
|
|
212
224
|
view?: string;
|
|
213
225
|
}
|
|
214
226
|
|
|
215
|
-
interface ChatFirstEmbedSessionResult {
|
|
216
|
-
startUrl: string;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
interface ChatFirstEmbedSessionInput {
|
|
220
|
-
app?: string;
|
|
221
|
-
path?: string;
|
|
222
|
-
url?: string;
|
|
223
|
-
chrome: "minimal";
|
|
224
|
-
}
|
|
225
|
-
|
|
226
227
|
interface ChatFirstGrantedAppSummary {
|
|
227
228
|
id: string;
|
|
228
229
|
name: string;
|
|
@@ -233,13 +234,6 @@ interface ChatFirstGrantedAppsResult {
|
|
|
233
234
|
apps: ChatFirstGrantedAppSummary[];
|
|
234
235
|
}
|
|
235
236
|
|
|
236
|
-
export function buildChatFirstEmbedSessionInput(
|
|
237
|
-
appId: string,
|
|
238
|
-
path: string,
|
|
239
|
-
): ChatFirstEmbedSessionInput {
|
|
240
|
-
return { app: appId, path, chrome: "minimal" };
|
|
241
|
-
}
|
|
242
|
-
|
|
243
237
|
interface DispatchAgentThreadSummary {
|
|
244
238
|
id: string;
|
|
245
239
|
title: string;
|
|
@@ -1088,11 +1082,12 @@ export function NavContent({
|
|
|
1088
1082
|
onNavigate?.();
|
|
1089
1083
|
}}
|
|
1090
1084
|
createAppTrigger={chatFirstCreateAppTrigger}
|
|
1091
|
-
renderIcon={(app) => (
|
|
1085
|
+
renderIcon={(app, options) => (
|
|
1092
1086
|
<AppIcon
|
|
1093
1087
|
id={app.id}
|
|
1094
1088
|
name={app.name}
|
|
1095
1089
|
size="sm"
|
|
1090
|
+
monochrome={options?.isInactive}
|
|
1096
1091
|
className="size-7 rounded-lg"
|
|
1097
1092
|
/>
|
|
1098
1093
|
)}
|
|
@@ -1369,6 +1364,10 @@ export function Layout({
|
|
|
1369
1364
|
const isWorkspaceAppRoute = shouldAutoCollapseDispatchSidebar(
|
|
1370
1365
|
location.pathname,
|
|
1371
1366
|
);
|
|
1367
|
+
const workspaceAppId = isWorkspaceAppRoute
|
|
1368
|
+
? workspaceAppIdFromRoute(localPathname)
|
|
1369
|
+
: null;
|
|
1370
|
+
const workspaceAppRouteActive = Boolean(workspaceAppId);
|
|
1372
1371
|
const isWorkspaceAppHostRoute =
|
|
1373
1372
|
isWorkspaceAppRoute &&
|
|
1374
1373
|
typeof window !== "undefined" &&
|
|
@@ -1446,20 +1445,8 @@ export function Layout({
|
|
|
1446
1445
|
[chatFirstAppRegistrations],
|
|
1447
1446
|
);
|
|
1448
1447
|
const chatFirstCopy = useMemo(() => createDispatchChatFirstCopy(t), [t]);
|
|
1449
|
-
const createChatFirstEmbedSession = useActionMutation<
|
|
1450
|
-
ChatFirstEmbedSessionResult,
|
|
1451
|
-
ChatFirstEmbedSessionInput
|
|
1452
|
-
>("create_embed_session", { skipActionQueryInvalidation: true });
|
|
1453
1448
|
const [chatFirstPane, setChatFirstPane] =
|
|
1454
1449
|
useState<DispatchChatFirstPane | null>(null);
|
|
1455
|
-
const [chatFirstEmbedUrl, setChatFirstEmbedUrl] = useState<string | null>(
|
|
1456
|
-
null,
|
|
1457
|
-
);
|
|
1458
|
-
const [chatFirstEmbedError, setChatFirstEmbedError] = useState<string | null>(
|
|
1459
|
-
null,
|
|
1460
|
-
);
|
|
1461
|
-
const [chatFirstEmbedAttempt, setChatFirstEmbedAttempt] = useState(0);
|
|
1462
|
-
const chatFirstAppFrameRef = useRef<HTMLIFrameElement>(null);
|
|
1463
1450
|
const [chatFirstNotice, setChatFirstNotice] = useState<string | null>(null);
|
|
1464
1451
|
const chatFirstSessionWatch = useChatFirstSessionWatch();
|
|
1465
1452
|
const chatFirstSurfaceTabs = useChatFirstSurfaceTabs(chatFirstSurfaceScope);
|
|
@@ -1512,28 +1499,6 @@ export function Layout({
|
|
|
1512
1499
|
: chatFirstAppSelected && activeChatFirstSurfaceTab?.kind === "app"
|
|
1513
1500
|
? activeChatFirstSurfaceTab.appId
|
|
1514
1501
|
: undefined;
|
|
1515
|
-
const activeChatFirstAppRegistration = useMemo(
|
|
1516
|
-
() =>
|
|
1517
|
-
activeChatFirstSurfaceTab?.kind === "app" &&
|
|
1518
|
-
activeChatFirstSurfaceTab.appId
|
|
1519
|
-
? (chatFirstAppRegistrations.find(
|
|
1520
|
-
(app) => app.id === activeChatFirstSurfaceTab.appId,
|
|
1521
|
-
) ?? null)
|
|
1522
|
-
: null,
|
|
1523
|
-
[activeChatFirstSurfaceTab, chatFirstAppRegistrations],
|
|
1524
|
-
);
|
|
1525
|
-
const activeChatFirstApp = useMemo(
|
|
1526
|
-
() =>
|
|
1527
|
-
activeChatFirstAppRegistration
|
|
1528
|
-
? {
|
|
1529
|
-
id: activeChatFirstAppRegistration.id,
|
|
1530
|
-
name:
|
|
1531
|
-
activeChatFirstAppRegistration.name ??
|
|
1532
|
-
activeChatFirstAppRegistration.id,
|
|
1533
|
-
}
|
|
1534
|
-
: null,
|
|
1535
|
-
[activeChatFirstAppRegistration],
|
|
1536
|
-
);
|
|
1537
1502
|
const chatFirstAgentActivities = useMemo<ChatFirstAgentActivity[]>(
|
|
1538
1503
|
() =>
|
|
1539
1504
|
(chatFirstAgentsQuery.data?.threads ?? []).map((thread) => ({
|
|
@@ -1546,82 +1511,6 @@ export function Layout({
|
|
|
1546
1511
|
})),
|
|
1547
1512
|
[chatFirstAgentsQuery.data, chatFirstCopy],
|
|
1548
1513
|
);
|
|
1549
|
-
const chatFirstEmbedPath =
|
|
1550
|
-
activeChatFirstSurfaceTab?.kind === "app"
|
|
1551
|
-
? (activeChatFirstSurfaceTab.path ??
|
|
1552
|
-
chatFirstPane?.path ??
|
|
1553
|
-
activeChatFirstAppRegistration?.path ??
|
|
1554
|
-
"/")
|
|
1555
|
-
: null;
|
|
1556
|
-
useEffect(() => {
|
|
1557
|
-
if (!chatFirstMode || !isChatRoute || !activeChatFirstApp) {
|
|
1558
|
-
setChatFirstEmbedUrl(null);
|
|
1559
|
-
setChatFirstEmbedError(null);
|
|
1560
|
-
return;
|
|
1561
|
-
}
|
|
1562
|
-
if (!chatFirstEmbedPath?.startsWith("/")) {
|
|
1563
|
-
setChatFirstEmbedUrl(null);
|
|
1564
|
-
setChatFirstEmbedError(chatFirstCopy("appUnavailable"));
|
|
1565
|
-
return;
|
|
1566
|
-
}
|
|
1567
|
-
let cancelled = false;
|
|
1568
|
-
setChatFirstEmbedUrl(null);
|
|
1569
|
-
setChatFirstEmbedError(null);
|
|
1570
|
-
void createChatFirstEmbedSession
|
|
1571
|
-
.mutateAsync(
|
|
1572
|
-
buildChatFirstEmbedSessionInput(
|
|
1573
|
-
activeChatFirstApp.id,
|
|
1574
|
-
chatFirstEmbedPath,
|
|
1575
|
-
),
|
|
1576
|
-
)
|
|
1577
|
-
.then((result) => {
|
|
1578
|
-
if (!cancelled) setChatFirstEmbedUrl(result.startUrl);
|
|
1579
|
-
})
|
|
1580
|
-
.catch((cause: unknown) => {
|
|
1581
|
-
if (!cancelled) {
|
|
1582
|
-
const directAppUrl = activeChatFirstAppRegistration
|
|
1583
|
-
? workspaceAppDirectHref(
|
|
1584
|
-
activeChatFirstAppRegistration,
|
|
1585
|
-
chatFirstEmbedPath,
|
|
1586
|
-
)
|
|
1587
|
-
: null;
|
|
1588
|
-
if (directAppUrl) setChatFirstEmbedUrl(directAppUrl);
|
|
1589
|
-
setChatFirstEmbedError(
|
|
1590
|
-
cause instanceof Error
|
|
1591
|
-
? cause.message
|
|
1592
|
-
: chatFirstCopy("appUnavailable"),
|
|
1593
|
-
);
|
|
1594
|
-
}
|
|
1595
|
-
});
|
|
1596
|
-
return () => {
|
|
1597
|
-
cancelled = true;
|
|
1598
|
-
};
|
|
1599
|
-
}, [
|
|
1600
|
-
activeChatFirstApp,
|
|
1601
|
-
chatFirstCopy,
|
|
1602
|
-
chatFirstEmbedAttempt,
|
|
1603
|
-
chatFirstEmbedPath,
|
|
1604
|
-
chatFirstMode,
|
|
1605
|
-
createChatFirstEmbedSession.mutateAsync,
|
|
1606
|
-
isChatRoute,
|
|
1607
|
-
]);
|
|
1608
|
-
|
|
1609
|
-
useEffect(() => {
|
|
1610
|
-
if (!chatFirstMode || !isChatRoute || !activeChatFirstApp) return;
|
|
1611
|
-
|
|
1612
|
-
const handleEmbedSessionExpired = (event: MessageEvent) => {
|
|
1613
|
-
if (
|
|
1614
|
-
!isEmbedSessionExpiredMessage(event, chatFirstAppFrameRef.current, null)
|
|
1615
|
-
)
|
|
1616
|
-
return;
|
|
1617
|
-
setChatFirstEmbedAttempt((attempt) => attempt + 1);
|
|
1618
|
-
};
|
|
1619
|
-
|
|
1620
|
-
window.addEventListener("message", handleEmbedSessionExpired);
|
|
1621
|
-
return () =>
|
|
1622
|
-
window.removeEventListener("message", handleEmbedSessionExpired);
|
|
1623
|
-
}, [activeChatFirstApp, chatFirstMode, isChatRoute]);
|
|
1624
|
-
|
|
1625
1514
|
const persistChatFirstPane = useCallback(
|
|
1626
1515
|
(pane: DispatchChatFirstPane | null) => {
|
|
1627
1516
|
setChatFirstPane(pane);
|
|
@@ -1962,8 +1851,6 @@ export function Layout({
|
|
|
1962
1851
|
}
|
|
1963
1852
|
previousChatFirstSurfaceScopeRef.current = chatFirstSurfaceScope;
|
|
1964
1853
|
persistChatFirstPane(null);
|
|
1965
|
-
setChatFirstEmbedUrl(null);
|
|
1966
|
-
setChatFirstEmbedError(null);
|
|
1967
1854
|
setChatFirstNotice(null);
|
|
1968
1855
|
pendingChatFirstOpenAppRef.current = null;
|
|
1969
1856
|
chatFirstPaneHydratedRef.current = true;
|
|
@@ -2151,47 +2038,45 @@ export function Layout({
|
|
|
2151
2038
|
const renderChatFirstSurfaceTab = useCallback(
|
|
2152
2039
|
(tab: ChatFirstSurfaceTab) => {
|
|
2153
2040
|
if (tab.kind === "app") {
|
|
2154
|
-
if (tab.id !== chatFirstSurfaceTabs.activeTabId) return null;
|
|
2155
2041
|
const registration = tab.appId
|
|
2156
2042
|
? (chatFirstAppRegistrations.find(
|
|
2157
2043
|
(candidate) => candidate.id === tab.appId,
|
|
2158
2044
|
) ?? null)
|
|
2159
2045
|
: null;
|
|
2160
|
-
|
|
2161
|
-
|
|
2046
|
+
if (!registration) {
|
|
2047
|
+
return (
|
|
2048
|
+
<ChatFirstAppPane
|
|
2049
|
+
app={null}
|
|
2050
|
+
status={chatFirstAppsQuery.isLoading ? "loading" : "unresolved"}
|
|
2051
|
+
renderEmbed={() => null}
|
|
2052
|
+
copy={chatFirstCopy}
|
|
2053
|
+
/>
|
|
2054
|
+
);
|
|
2055
|
+
}
|
|
2056
|
+
const embedPath = tab.path ?? registration.path ?? "/";
|
|
2057
|
+
if (!embedPath.startsWith("/")) {
|
|
2058
|
+
return (
|
|
2059
|
+
<ChatFirstAppPane
|
|
2060
|
+
app={{
|
|
2061
|
+
id: registration.id,
|
|
2062
|
+
name: registration.name ?? registration.id,
|
|
2063
|
+
}}
|
|
2064
|
+
status="error"
|
|
2065
|
+
errorMessage={chatFirstCopy("appUnavailable")}
|
|
2066
|
+
renderEmbed={() => null}
|
|
2067
|
+
copy={chatFirstCopy}
|
|
2068
|
+
/>
|
|
2069
|
+
);
|
|
2070
|
+
}
|
|
2071
|
+
return (
|
|
2072
|
+
<WorkspaceAppFrame
|
|
2073
|
+
app={{
|
|
2162
2074
|
id: registration.id,
|
|
2163
2075
|
name: registration.name ?? registration.id,
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
app={app}
|
|
2169
|
-
status={
|
|
2170
|
-
chatFirstEmbedUrl
|
|
2171
|
-
? "ready"
|
|
2172
|
-
: chatFirstEmbedError
|
|
2173
|
-
? "error"
|
|
2174
|
-
: chatFirstAppsQuery.isLoading
|
|
2175
|
-
? "loading"
|
|
2176
|
-
: app
|
|
2177
|
-
? "loading"
|
|
2178
|
-
: "unresolved"
|
|
2179
|
-
}
|
|
2180
|
-
embedUrl={chatFirstEmbedUrl}
|
|
2181
|
-
errorMessage={chatFirstEmbedError}
|
|
2182
|
-
onRetry={() => setChatFirstEmbedAttempt((value) => value + 1)}
|
|
2183
|
-
renderEmbed={({ url, title }: ChatFirstEmbedTarget) => (
|
|
2184
|
-
<iframe
|
|
2185
|
-
key={`${url}:${chatFirstEmbedAttempt}`}
|
|
2186
|
-
data-dispatch-chat-first-app-frame
|
|
2187
|
-
src={url}
|
|
2188
|
-
title={title ?? chatFirstCopy("appUnavailable")}
|
|
2189
|
-
ref={chatFirstAppFrameRef}
|
|
2190
|
-
referrerPolicy="no-referrer"
|
|
2191
|
-
allow="clipboard-read; clipboard-write"
|
|
2192
|
-
className="h-full w-full border-0 bg-background"
|
|
2193
|
-
/>
|
|
2194
|
-
)}
|
|
2076
|
+
path: registration.path,
|
|
2077
|
+
url: registration.url,
|
|
2078
|
+
}}
|
|
2079
|
+
embedPath={embedPath}
|
|
2195
2080
|
copy={chatFirstCopy}
|
|
2196
2081
|
/>
|
|
2197
2082
|
);
|
|
@@ -2263,8 +2148,6 @@ export function Layout({
|
|
|
2263
2148
|
chatFirstAgentsQuery.isLoading,
|
|
2264
2149
|
chatFirstAppsQuery.isLoading,
|
|
2265
2150
|
chatFirstCopy,
|
|
2266
|
-
chatFirstEmbedError,
|
|
2267
|
-
chatFirstEmbedUrl,
|
|
2268
2151
|
chatFirstSessionWatch.target,
|
|
2269
2152
|
chatFirstSurfaceTabs.activeTabId,
|
|
2270
2153
|
chatFirstAppRegistrations,
|
|
@@ -2449,7 +2332,7 @@ export function Layout({
|
|
|
2449
2332
|
</>
|
|
2450
2333
|
)}
|
|
2451
2334
|
</div>
|
|
2452
|
-
) : isWorkspaceAppRoute ? (
|
|
2335
|
+
) : workspaceAppRouteActive ? null : isWorkspaceAppRoute ? (
|
|
2453
2336
|
appContent
|
|
2454
2337
|
) : (
|
|
2455
2338
|
<AgentSidebar
|
|
@@ -2553,7 +2436,12 @@ export function Layout({
|
|
|
2553
2436
|
</SheetContent>
|
|
2554
2437
|
</Sheet>
|
|
2555
2438
|
|
|
2556
|
-
|
|
2439
|
+
<div className="relative min-w-0 flex-1 overflow-hidden">
|
|
2440
|
+
{content}
|
|
2441
|
+
<WorkspaceAppKeepAlive
|
|
2442
|
+
activeAppId={workspaceAppRouteActive ? workspaceAppId : null}
|
|
2443
|
+
/>
|
|
2444
|
+
</div>
|
|
2557
2445
|
</div>
|
|
2558
2446
|
</HeaderActionsProvider>
|
|
2559
2447
|
</DispatchExtensionsContext.Provider>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
handleAgentPackMutationSuccess,
|
|
5
|
+
isPendingWorkspaceResourceApproval,
|
|
6
|
+
} from "./simple-agents-panel";
|
|
7
|
+
|
|
8
|
+
describe("agent pack resource mutations", () => {
|
|
9
|
+
it("recognizes pending workspace-resource approvals", () => {
|
|
10
|
+
expect(
|
|
11
|
+
isPendingWorkspaceResourceApproval({
|
|
12
|
+
status: "pending",
|
|
13
|
+
changeType: "workspace-resource.update",
|
|
14
|
+
}),
|
|
15
|
+
).toBe(true);
|
|
16
|
+
expect(
|
|
17
|
+
isPendingWorkspaceResourceApproval({
|
|
18
|
+
status: "pending",
|
|
19
|
+
changeType: "workspace-resource.create",
|
|
20
|
+
}),
|
|
21
|
+
).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("does not treat applied resources or unrelated pending results as approvals", () => {
|
|
25
|
+
expect(
|
|
26
|
+
isPendingWorkspaceResourceApproval({
|
|
27
|
+
id: "resource_1",
|
|
28
|
+
status: "applied",
|
|
29
|
+
changeType: "workspace-resource.update",
|
|
30
|
+
}),
|
|
31
|
+
).toBe(false);
|
|
32
|
+
expect(
|
|
33
|
+
isPendingWorkspaceResourceApproval({
|
|
34
|
+
status: "pending",
|
|
35
|
+
changeType: "destination.upsert",
|
|
36
|
+
}),
|
|
37
|
+
).toBe(false);
|
|
38
|
+
expect(isPendingWorkspaceResourceApproval(null)).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("reports queued approval without running applied-only refresh work", () => {
|
|
42
|
+
const notifications: string[] = [];
|
|
43
|
+
const onApplied = () => notifications.push("refreshed");
|
|
44
|
+
|
|
45
|
+
handleAgentPackMutationSuccess(
|
|
46
|
+
{ status: "pending", changeType: "workspace-resource.update" },
|
|
47
|
+
{
|
|
48
|
+
appliedMessage: "Pack file updated",
|
|
49
|
+
approvalMessage: "Pack file update queued for approval",
|
|
50
|
+
onApplied,
|
|
51
|
+
notify: (message) => notifications.push(message),
|
|
52
|
+
},
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
expect(notifications).toEqual(["Pack file update queued for approval"]);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("reports applied and runs refresh work for an applied resource", () => {
|
|
59
|
+
const notifications: string[] = [];
|
|
60
|
+
|
|
61
|
+
handleAgentPackMutationSuccess(
|
|
62
|
+
{ id: "resource_1" },
|
|
63
|
+
{
|
|
64
|
+
appliedMessage: "Pack file added",
|
|
65
|
+
approvalMessage: "Pack file addition queued for approval",
|
|
66
|
+
onApplied: () => notifications.push("refreshed"),
|
|
67
|
+
notify: (message) => notifications.push(message),
|
|
68
|
+
},
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
expect(notifications).toEqual(["Pack file added", "refreshed"]);
|
|
72
|
+
});
|
|
73
|
+
});
|