@agent-native/dispatch 0.24.0 → 0.24.2
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 +12 -12
- package/dist/components/admin-navigation.d.ts.map +1 -1
- package/dist/components/admin-navigation.js +21 -5
- package/dist/components/admin-navigation.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 +1 -17
- package/dist/components/app-open-actions.d.ts.map +1 -1
- package/dist/components/app-open-actions.js +1 -20
- package/dist/components/app-open-actions.js.map +1 -1
- package/dist/components/app-row-settings.d.ts +6 -0
- package/dist/components/app-row-settings.d.ts.map +1 -0
- package/dist/components/app-row-settings.js +11 -0
- package/dist/components/app-row-settings.js.map +1 -0
- package/dist/components/automation-run-history-dialog.d.ts.map +1 -1
- package/dist/components/automation-run-history-dialog.js +3 -2
- package/dist/components/automation-run-history-dialog.js.map +1 -1
- package/dist/components/connected-app-card.d.ts.map +1 -1
- package/dist/components/connected-app-card.js +1 -1
- package/dist/components/connected-app-card.js.map +1 -1
- package/dist/components/create-app-popover.js +2 -2
- package/dist/components/create-app-popover.js.map +1 -1
- package/dist/components/dispatch-control-plane.d.ts.map +1 -1
- package/dist/components/dispatch-control-plane.js +23 -7
- package/dist/components/dispatch-control-plane.js.map +1 -1
- package/dist/components/dispatch-shell.d.ts.map +1 -1
- package/dist/components/dispatch-shell.js +5 -1
- package/dist/components/dispatch-shell.js.map +1 -1
- package/dist/components/docs-link.d.ts +16 -0
- package/dist/components/docs-link.d.ts.map +1 -0
- package/dist/components/docs-link.js +34 -0
- package/dist/components/docs-link.js.map +1 -0
- package/dist/components/layout/Layout.d.ts +1 -0
- package/dist/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +37 -28
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/messaging-setup-panel.d.ts.map +1 -1
- package/dist/components/messaging-setup-panel.js +3 -2
- package/dist/components/messaging-setup-panel.js.map +1 -1
- package/dist/components/usage-alerts-panel.d.ts +11 -0
- package/dist/components/usage-alerts-panel.d.ts.map +1 -0
- package/dist/components/usage-alerts-panel.js +125 -0
- package/dist/components/usage-alerts-panel.js.map +1 -0
- package/dist/components/workspace-app-card.d.ts +3 -1
- package/dist/components/workspace-app-card.d.ts.map +1 -1
- package/dist/components/workspace-app-card.js +70 -29
- package/dist/components/workspace-app-card.js.map +1 -1
- package/dist/components/workspace-app-search.d.ts +10 -0
- package/dist/components/workspace-app-search.d.ts.map +1 -0
- package/dist/components/workspace-app-search.js +27 -0
- package/dist/components/workspace-app-search.js.map +1 -0
- package/dist/components/workspace-resource-effective-stack.d.ts.map +1 -1
- package/dist/components/workspace-resource-effective-stack.js +3 -2
- package/dist/components/workspace-resource-effective-stack.js.map +1 -1
- package/dist/components/workspace-template-card.d.ts.map +1 -1
- package/dist/components/workspace-template-card.js +2 -1
- package/dist/components/workspace-template-card.js.map +1 -1
- package/dist/lib/workspace-app-layout.d.ts +19 -0
- package/dist/lib/workspace-app-layout.d.ts.map +1 -0
- package/dist/lib/workspace-app-layout.js +75 -0
- package/dist/lib/workspace-app-layout.js.map +1 -0
- package/dist/lib/workspace-apps.d.ts +10 -0
- package/dist/lib/workspace-apps.d.ts.map +1 -1
- package/dist/lib/workspace-apps.js +59 -0
- package/dist/lib/workspace-apps.js.map +1 -1
- package/dist/lib/workspace-apps.test.js +18 -1
- package/dist/lib/workspace-apps.test.js.map +1 -1
- package/dist/routes/pages/$appId.d.ts.map +1 -1
- package/dist/routes/pages/$appId.js +4 -2
- package/dist/routes/pages/$appId.js.map +1 -1
- package/dist/routes/pages/agents.d.ts.map +1 -1
- package/dist/routes/pages/agents.js +2 -3
- 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 +8 -3
- package/dist/routes/pages/apps.$appId.js.map +1 -1
- package/dist/routes/pages/apps.d.ts.map +1 -1
- package/dist/routes/pages/apps.js +31 -16
- package/dist/routes/pages/apps.js.map +1 -1
- package/dist/routes/pages/audit.d.ts.map +1 -1
- package/dist/routes/pages/audit.js +2 -1
- package/dist/routes/pages/audit.js.map +1 -1
- package/dist/routes/pages/dreams.d.ts.map +1 -1
- package/dist/routes/pages/dreams.js +14 -18
- package/dist/routes/pages/dreams.js.map +1 -1
- package/dist/routes/pages/integrations.d.ts.map +1 -1
- package/dist/routes/pages/integrations.js +51 -14
- package/dist/routes/pages/integrations.js.map +1 -1
- package/dist/routes/pages/metrics.d.ts.map +1 -1
- package/dist/routes/pages/metrics.js +4 -1
- package/dist/routes/pages/metrics.js.map +1 -1
- package/dist/routes/pages/operations.js +1 -1
- package/dist/routes/pages/operations.js.map +1 -1
- package/dist/routes/pages/settings.d.ts.map +1 -1
- package/dist/routes/pages/settings.js +7 -2
- 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 +5 -8
- package/dist/routes/pages/thread-debug.js.map +1 -1
- package/dist/routes/pages/vault.d.ts.map +1 -1
- package/dist/routes/pages/vault.js +1 -1
- package/dist/routes/pages/vault.js.map +1 -1
- package/dist/routes/pages/workspace.d.ts.map +1 -1
- package/dist/routes/pages/workspace.js +13 -10
- package/dist/routes/pages/workspace.js.map +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/app-creation-store.d.ts.map +1 -1
- package/dist/server/lib/app-creation-store.js +12 -52
- package/dist/server/lib/app-creation-store.js.map +1 -1
- package/dist/shared/app-roles.d.ts +9 -0
- package/dist/shared/app-roles.d.ts.map +1 -0
- package/dist/shared/app-roles.js +7 -0
- package/dist/shared/app-roles.js.map +1 -0
- package/package.json +4 -3
- package/src/components/admin-navigation.tsx +57 -11
- package/src/components/app-list-row.tsx +1 -2
- package/src/components/app-open-actions.tsx +5 -114
- package/src/components/app-row-settings.tsx +54 -0
- package/src/components/automation-run-history-dialog.tsx +8 -4
- package/src/components/connected-app-card.tsx +0 -1
- package/src/components/create-app-popover.spec.tsx +1 -1
- package/src/components/create-app-popover.tsx +2 -2
- package/src/components/dispatch-control-plane.spec.tsx +36 -2
- package/src/components/dispatch-control-plane.tsx +83 -27
- package/src/components/dispatch-shell.tsx +7 -1
- package/src/components/docs-link.tsx +52 -0
- package/src/components/layout/Layout.spec.tsx +10 -0
- package/src/components/layout/Layout.tsx +50 -23
- package/src/components/messaging-setup-panel.tsx +10 -3
- package/src/components/usage-alerts-panel.tsx +445 -0
- package/src/components/workspace-app-card.spec.tsx +130 -9
- package/src/components/workspace-app-card.tsx +128 -71
- package/src/components/workspace-app-search.tsx +96 -0
- package/src/components/workspace-resource-effective-stack.tsx +10 -5
- package/src/components/workspace-template-card.spec.tsx +52 -23
- package/src/components/workspace-template-card.tsx +7 -10
- package/src/lib/workspace-app-layout.spec.ts +47 -0
- package/src/lib/workspace-app-layout.ts +121 -0
- package/src/lib/workspace-apps.test.ts +45 -1
- package/src/lib/workspace-apps.ts +72 -0
- package/src/routes/pages/$appId.tsx +3 -6
- package/src/routes/pages/agents.tsx +6 -3
- package/src/routes/pages/apps.$appId.tsx +6 -6
- package/src/routes/pages/apps.tsx +116 -62
- package/src/routes/pages/audit.tsx +28 -8
- package/src/routes/pages/dreams.tsx +92 -142
- package/src/routes/pages/integrations.tsx +147 -68
- package/src/routes/pages/metrics.tsx +8 -0
- package/src/routes/pages/operations.tsx +2 -2
- package/src/routes/pages/settings.tsx +14 -9
- package/src/routes/pages/thread-debug.tsx +18 -36
- package/src/routes/pages/vault.tsx +7 -2
- package/src/routes/pages/workspace.tsx +92 -56
- package/src/server/index.ts +4 -0
- package/src/server/lib/app-creation-store.spec.ts +90 -43
- package/src/server/lib/app-creation-store.ts +15 -61
- package/src/shared/app-roles.ts +8 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-roles.d.ts","sourceRoot":"","sources":["../../src/shared/app-roles.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,wBAAwB;;;;QAGrB,KAAK;;;CAEkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-roles.js","sourceRoot":"","sources":["../../src/shared/app-roles.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,KAAK,EAAE,UAAU;IACjB,KAAK,EAAE,CAAC,OAAO,CAAU;IACzB,UAAU,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE;IACvC,KAAK,EAAE,iBAAiB;CACa,CAAC","sourcesContent":["import type { AppRolesDescriptor } from \"@agent-native/core/client/org\";\n\nexport const dispatchAccessDescriptor = {\n appId: \"dispatch\",\n roles: [\"admin\"] as const,\n roleLabels: { admin: \"Dispatch admin\" },\n label: \"Dispatch access\",\n} satisfies AppRolesDescriptor<\"admin\">;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/dispatch",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.2",
|
|
4
4
|
"description": "Dispatch — workspace control plane for agent-native apps. Vault, integrations, destinations, scheduled jobs, and cross-app delegation, shipped as a single drop-in package.",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"./routes": "./dist/routes/index.js",
|
|
29
29
|
"./routes/pages/*": "./dist/routes/pages/*.js",
|
|
30
30
|
"./server": "./dist/server/index.js",
|
|
31
|
+
"./shared/app-roles": "./dist/shared/app-roles.js",
|
|
31
32
|
"./server/lib/thread-link-preview": "./dist/server/lib/thread-link-preview.js",
|
|
32
33
|
"./actions": "./dist/actions/index.js",
|
|
33
34
|
"./db": "./dist/db/index.js",
|
|
@@ -84,7 +85,7 @@
|
|
|
84
85
|
"tailwind-merge": "^3.5.0",
|
|
85
86
|
"vaul": "^1.1.2",
|
|
86
87
|
"zod": "^4.3.6",
|
|
87
|
-
"@agent-native/toolkit": "0.14.
|
|
88
|
+
"@agent-native/toolkit": "0.14.1"
|
|
88
89
|
},
|
|
89
90
|
"devDependencies": {
|
|
90
91
|
"@react-router/dev": "^8.1.0",
|
|
@@ -98,7 +99,7 @@
|
|
|
98
99
|
"typescript-7": "npm:typescript@^7.0.2",
|
|
99
100
|
"vite": "8.1.0",
|
|
100
101
|
"vitest": "^4.1.5",
|
|
101
|
-
"@agent-native/core": "0.
|
|
102
|
+
"@agent-native/core": "0.153.0"
|
|
102
103
|
},
|
|
103
104
|
"peerDependencies": {
|
|
104
105
|
"@agent-native/core": ">=0.8.0",
|
|
@@ -16,11 +16,14 @@ import {
|
|
|
16
16
|
IconSettingsAutomation,
|
|
17
17
|
IconShield,
|
|
18
18
|
IconShieldCheck,
|
|
19
|
+
IconSearch,
|
|
20
|
+
IconX,
|
|
19
21
|
} from "@tabler/icons-react";
|
|
20
|
-
import { type ReactNode } from "react";
|
|
22
|
+
import { useMemo, useState, type ReactNode } from "react";
|
|
21
23
|
import { NavLink } from "react-router";
|
|
22
24
|
|
|
23
25
|
import { cn } from "../lib/utils";
|
|
26
|
+
import { DISPATCH_DOCS, DocsLink } from "./docs-link";
|
|
24
27
|
import { useDispatchExtensions, type DispatchNavItem } from "./layout/Layout";
|
|
25
28
|
|
|
26
29
|
export interface AdminNavGroup {
|
|
@@ -211,22 +214,60 @@ export function AdminShell({
|
|
|
211
214
|
}) {
|
|
212
215
|
const t = useT();
|
|
213
216
|
const groups = useAdminNavGroups();
|
|
217
|
+
const [query, setQuery] = useState("");
|
|
218
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
219
|
+
const visibleGroups = useMemo(
|
|
220
|
+
() =>
|
|
221
|
+
groups
|
|
222
|
+
.map((group) => ({
|
|
223
|
+
...group,
|
|
224
|
+
items: group.items.filter((item) => {
|
|
225
|
+
if (!normalizedQuery) return true;
|
|
226
|
+
const label = itemLabel(t, item).toLowerCase();
|
|
227
|
+
return `${label} ${group.label.toLowerCase()}`.includes(
|
|
228
|
+
normalizedQuery,
|
|
229
|
+
);
|
|
230
|
+
}),
|
|
231
|
+
}))
|
|
232
|
+
.filter((group) => group.items.length > 0),
|
|
233
|
+
[groups, normalizedQuery, t],
|
|
234
|
+
);
|
|
214
235
|
|
|
215
236
|
return (
|
|
216
237
|
<div
|
|
217
238
|
className="grid min-w-0 gap-6 lg:grid-cols-[13rem_minmax(0,1fr)]"
|
|
218
239
|
data-dispatch-admin-shell
|
|
219
240
|
>
|
|
220
|
-
<aside className="min-w-0 border-b pb-5 lg:sticky lg:top-2 lg:self-start lg:border-b-0
|
|
221
|
-
<div className="px-2">
|
|
222
|
-
<div className="
|
|
223
|
-
|
|
241
|
+
<aside className="min-w-0 border-b pb-5 lg:sticky lg:top-2 lg:self-start lg:border-b-0">
|
|
242
|
+
<div className="flex items-center gap-1 px-2">
|
|
243
|
+
<div className="relative min-w-0 flex-1">
|
|
244
|
+
<IconSearch className="pointer-events-none absolute start-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground" />
|
|
245
|
+
<input
|
|
246
|
+
type="search"
|
|
247
|
+
value={query}
|
|
248
|
+
onChange={(event) => setQuery(event.target.value)}
|
|
249
|
+
onKeyDown={(event) => {
|
|
250
|
+
if (event.key === "Escape") setQuery("");
|
|
251
|
+
}}
|
|
252
|
+
placeholder="Search admin"
|
|
253
|
+
aria-label="Search admin"
|
|
254
|
+
className="h-8 w-full rounded-md border border-border bg-background ps-8 pe-7 text-[13px] text-foreground outline-none transition-colors placeholder:text-muted-foreground focus:border-foreground/30 focus:ring-2 focus:ring-accent/40"
|
|
255
|
+
/>
|
|
256
|
+
{query ? (
|
|
257
|
+
<button
|
|
258
|
+
type="button"
|
|
259
|
+
onClick={() => setQuery("")}
|
|
260
|
+
aria-label="Clear admin search"
|
|
261
|
+
className="absolute end-1.5 top-1/2 flex size-5 -translate-y-1/2 items-center justify-center rounded text-muted-foreground hover:bg-accent/60 hover:text-foreground"
|
|
262
|
+
>
|
|
263
|
+
<IconX className="size-3.5" />
|
|
264
|
+
</button>
|
|
265
|
+
) : null}
|
|
224
266
|
</div>
|
|
225
|
-
<
|
|
226
|
-
{
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
</p>
|
|
267
|
+
<DocsLink
|
|
268
|
+
href={DISPATCH_DOCS.dispatch}
|
|
269
|
+
label="Open Dispatch admin documentation"
|
|
270
|
+
/>
|
|
230
271
|
</div>
|
|
231
272
|
|
|
232
273
|
<nav
|
|
@@ -235,7 +276,7 @@ export function AdminShell({
|
|
|
235
276
|
})}
|
|
236
277
|
className="mt-5 space-y-5"
|
|
237
278
|
>
|
|
238
|
-
{
|
|
279
|
+
{visibleGroups.map((group) => (
|
|
239
280
|
<section key={group.id}>
|
|
240
281
|
<h2 className="px-2 text-[11px] font-medium uppercase tracking-wide text-muted-foreground/70">
|
|
241
282
|
{t(group.labelKey, { defaultValue: group.label })}
|
|
@@ -251,6 +292,11 @@ export function AdminShell({
|
|
|
251
292
|
</ul>
|
|
252
293
|
</section>
|
|
253
294
|
))}
|
|
295
|
+
{visibleGroups.length === 0 ? (
|
|
296
|
+
<p className="px-2 py-6 text-center text-xs text-muted-foreground">
|
|
297
|
+
No matching admin pages
|
|
298
|
+
</p>
|
|
299
|
+
) : null}
|
|
254
300
|
</nav>
|
|
255
301
|
</aside>
|
|
256
302
|
|
|
@@ -2,8 +2,7 @@ import type { ReactNode } from "react";
|
|
|
2
2
|
|
|
3
3
|
import { cn } from "../lib/utils";
|
|
4
4
|
|
|
5
|
-
export const APP_LIST_GRID_CLASS =
|
|
6
|
-
"mx-auto w-full max-w-[1000px] xl:grid xl:grid-cols-2 xl:gap-3 xl:overflow-visible xl:rounded-none xl:bg-transparent";
|
|
5
|
+
export const APP_LIST_GRID_CLASS = "w-full xl:grid xl:grid-cols-2 xl:gap-3";
|
|
7
6
|
export const APP_LIST_GRID_ROW_CLASS =
|
|
8
7
|
"xl:rounded-2xl xl:border xl:border-transparent xl:bg-card xl:transition-[background-color,border-color] xl:hover:border-border xl:focus-within:border-ring/50";
|
|
9
8
|
|
|
@@ -1,114 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
DropdownMenuContent,
|
|
7
|
-
DropdownMenuItem,
|
|
8
|
-
DropdownMenuTrigger,
|
|
9
|
-
} from "./ui/dropdown-menu";
|
|
10
|
-
|
|
11
|
-
export interface AppOpenActionLabels {
|
|
12
|
-
addApp: string;
|
|
13
|
-
openApp: string;
|
|
14
|
-
openInline: string;
|
|
15
|
-
openInNewTab: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const DEFAULT_LABELS: AppOpenActionLabels = {
|
|
19
|
-
addApp: "Add app",
|
|
20
|
-
openApp: "Open app",
|
|
21
|
-
openInline: "Open inline",
|
|
22
|
-
openInNewTab: "Open in new tab",
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export function AppOpenActions({
|
|
26
|
-
name,
|
|
27
|
-
href,
|
|
28
|
-
target,
|
|
29
|
-
rel,
|
|
30
|
-
labels: labelOverrides,
|
|
31
|
-
onAddApp,
|
|
32
|
-
onOpenInline,
|
|
33
|
-
showInlineOption = false,
|
|
34
|
-
showNewTabOption = false,
|
|
35
|
-
}: {
|
|
36
|
-
name: string;
|
|
37
|
-
href: string | null;
|
|
38
|
-
target?: "_blank";
|
|
39
|
-
rel?: string;
|
|
40
|
-
labels?: Partial<AppOpenActionLabels>;
|
|
41
|
-
onAddApp?: () => void;
|
|
42
|
-
onOpenInline?: () => void;
|
|
43
|
-
showInlineOption?: boolean;
|
|
44
|
-
showNewTabOption?: boolean;
|
|
45
|
-
}) {
|
|
46
|
-
const labels = { ...DEFAULT_LABELS, ...labelOverrides };
|
|
47
|
-
const canOfferNewTab = showNewTabOption && target !== "_blank";
|
|
48
|
-
const hasMenu =
|
|
49
|
-
Boolean(onAddApp) ||
|
|
50
|
-
(Boolean(href) && (showInlineOption || canOfferNewTab));
|
|
51
|
-
|
|
52
|
-
if (!href && !hasMenu) {
|
|
53
|
-
return (
|
|
54
|
-
<Button size="sm" variant="outline" disabled>
|
|
55
|
-
{labels.openApp}
|
|
56
|
-
</Button>
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return (
|
|
61
|
-
<div className="flex shrink-0 overflow-hidden rounded-md border border-border focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2">
|
|
62
|
-
<Button
|
|
63
|
-
asChild={Boolean(href)}
|
|
64
|
-
size="sm"
|
|
65
|
-
variant="outline"
|
|
66
|
-
className="rounded-none border-0 border-e border-border"
|
|
67
|
-
disabled={!href}
|
|
68
|
-
>
|
|
69
|
-
{href ? (
|
|
70
|
-
<a href={href} target={target} rel={rel}>
|
|
71
|
-
{labels.openApp}
|
|
72
|
-
</a>
|
|
73
|
-
) : (
|
|
74
|
-
<span>{labels.openApp}</span>
|
|
75
|
-
)}
|
|
76
|
-
</Button>
|
|
77
|
-
{hasMenu ? (
|
|
78
|
-
<DropdownMenu>
|
|
79
|
-
<DropdownMenuTrigger asChild>
|
|
80
|
-
<Button
|
|
81
|
-
type="button"
|
|
82
|
-
size="sm"
|
|
83
|
-
variant="outline"
|
|
84
|
-
className="size-9 rounded-none border-0 p-0"
|
|
85
|
-
aria-label={`Open options for ${name}`}
|
|
86
|
-
>
|
|
87
|
-
<IconChevronDown size={15} />
|
|
88
|
-
</Button>
|
|
89
|
-
</DropdownMenuTrigger>
|
|
90
|
-
<DropdownMenuContent align="end" className="min-w-40">
|
|
91
|
-
{onAddApp ? (
|
|
92
|
-
<DropdownMenuItem onSelect={onAddApp}>
|
|
93
|
-
<IconPlus size={14} className="mr-2" />
|
|
94
|
-
{labels.addApp}
|
|
95
|
-
</DropdownMenuItem>
|
|
96
|
-
) : null}
|
|
97
|
-
{showInlineOption && href ? (
|
|
98
|
-
<DropdownMenuItem onSelect={onOpenInline}>
|
|
99
|
-
{labels.openInline}
|
|
100
|
-
</DropdownMenuItem>
|
|
101
|
-
) : null}
|
|
102
|
-
{canOfferNewTab && href ? (
|
|
103
|
-
<DropdownMenuItem asChild>
|
|
104
|
-
<a href={href} target="_blank" rel="noreferrer">
|
|
105
|
-
{labels.openInNewTab}
|
|
106
|
-
</a>
|
|
107
|
-
</DropdownMenuItem>
|
|
108
|
-
) : null}
|
|
109
|
-
</DropdownMenuContent>
|
|
110
|
-
</DropdownMenu>
|
|
111
|
-
) : null}
|
|
112
|
-
</div>
|
|
113
|
-
);
|
|
114
|
-
}
|
|
1
|
+
export {
|
|
2
|
+
AppOpenActions,
|
|
3
|
+
type AppOpenActionLabels,
|
|
4
|
+
type AppOpenActionMenuItem,
|
|
5
|
+
} from "@agent-native/core/client/chat-first";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { APP_ACTION_MENU_CONTENT_CLASS } from "@agent-native/core/client/chat-first";
|
|
2
|
+
import { IconPlus, IconSettings } from "@tabler/icons-react";
|
|
3
|
+
|
|
4
|
+
import { Button } from "./ui/button";
|
|
5
|
+
import {
|
|
6
|
+
DropdownMenu,
|
|
7
|
+
DropdownMenuContent,
|
|
8
|
+
DropdownMenuItem,
|
|
9
|
+
DropdownMenuTrigger,
|
|
10
|
+
} from "./ui/dropdown-menu";
|
|
11
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
|
|
12
|
+
|
|
13
|
+
const APP_ROW_ACTION_CLASS =
|
|
14
|
+
"size-7 rounded-md p-0 text-muted-foreground transition-[background-color,color] hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring data-[state=open]:bg-accent data-[state=open]:text-foreground";
|
|
15
|
+
|
|
16
|
+
export function AppRowSettings({
|
|
17
|
+
name,
|
|
18
|
+
addAppLabel = "Add app",
|
|
19
|
+
onAddApp,
|
|
20
|
+
}: {
|
|
21
|
+
name: string;
|
|
22
|
+
addAppLabel?: string;
|
|
23
|
+
onAddApp: () => void;
|
|
24
|
+
}) {
|
|
25
|
+
return (
|
|
26
|
+
<DropdownMenu>
|
|
27
|
+
<Tooltip>
|
|
28
|
+
<TooltipTrigger asChild>
|
|
29
|
+
<DropdownMenuTrigger asChild>
|
|
30
|
+
<Button
|
|
31
|
+
type="button"
|
|
32
|
+
variant="ghost"
|
|
33
|
+
size="sm"
|
|
34
|
+
aria-label={`Settings for ${name}`}
|
|
35
|
+
className={APP_ROW_ACTION_CLASS}
|
|
36
|
+
>
|
|
37
|
+
<IconSettings size={15} />
|
|
38
|
+
</Button>
|
|
39
|
+
</DropdownMenuTrigger>
|
|
40
|
+
</TooltipTrigger>
|
|
41
|
+
<TooltipContent>App settings</TooltipContent>
|
|
42
|
+
</Tooltip>
|
|
43
|
+
<DropdownMenuContent
|
|
44
|
+
align="end"
|
|
45
|
+
className={APP_ACTION_MENU_CONTENT_CLASS}
|
|
46
|
+
>
|
|
47
|
+
<DropdownMenuItem onSelect={onAddApp}>
|
|
48
|
+
<IconPlus size={14} aria-hidden="true" />
|
|
49
|
+
{addAppLabel}
|
|
50
|
+
</DropdownMenuItem>
|
|
51
|
+
</DropdownMenuContent>
|
|
52
|
+
</DropdownMenu>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
IconAlertTriangle,
|
|
4
4
|
IconClock,
|
|
5
5
|
IconExternalLink,
|
|
6
|
-
IconLoader2,
|
|
7
6
|
} from "@tabler/icons-react";
|
|
8
7
|
import { Link } from "react-router";
|
|
9
8
|
|
|
@@ -21,6 +20,7 @@ import {
|
|
|
21
20
|
DialogHeader,
|
|
22
21
|
DialogTitle,
|
|
23
22
|
} from "./ui/dialog";
|
|
23
|
+
import { Skeleton } from "./ui/skeleton";
|
|
24
24
|
|
|
25
25
|
interface AutomationRun {
|
|
26
26
|
id: string;
|
|
@@ -178,9 +178,13 @@ export function AutomationRunHistoryDialog({
|
|
|
178
178
|
|
|
179
179
|
<div className="mt-3">
|
|
180
180
|
{runsQuery.isLoading ? (
|
|
181
|
-
<div className="
|
|
182
|
-
|
|
183
|
-
|
|
181
|
+
<div className="space-y-3 rounded-lg border p-4">
|
|
182
|
+
{Array.from({ length: 3 }).map((_, index) => (
|
|
183
|
+
<div key={index} className="space-y-2">
|
|
184
|
+
<Skeleton className="h-4 w-2/3" />
|
|
185
|
+
<Skeleton className="h-3 w-1/2" />
|
|
186
|
+
</div>
|
|
187
|
+
))}
|
|
184
188
|
</div>
|
|
185
189
|
) : runsQuery.isError ? (
|
|
186
190
|
<ActionQueryError
|
|
@@ -339,7 +339,7 @@ describe("CreateAppFlow", () => {
|
|
|
339
339
|
});
|
|
340
340
|
});
|
|
341
341
|
const branchLink = Array.from(container.querySelectorAll("a")).find(
|
|
342
|
-
(candidate) => candidate.textContent?.includes("Open Builder
|
|
342
|
+
(candidate) => candidate.textContent?.includes("Open in Builder"),
|
|
343
343
|
);
|
|
344
344
|
expect(branchLink?.getAttribute("href")).toBe(
|
|
345
345
|
"https://branch.example.test",
|
|
@@ -319,7 +319,7 @@ export function CreateAppFlow({
|
|
|
319
319
|
</div>
|
|
320
320
|
<Button asChild className="w-full sm:w-auto">
|
|
321
321
|
<a href={branchUrl} target="_blank" rel="noreferrer">
|
|
322
|
-
Open Builder
|
|
322
|
+
Open in Builder <IconArrowUpRight aria-hidden="true" />
|
|
323
323
|
</a>
|
|
324
324
|
</Button>
|
|
325
325
|
</div>
|
|
@@ -583,7 +583,7 @@ export function CreateAppFlow({
|
|
|
583
583
|
rel="noreferrer"
|
|
584
584
|
className="inline-flex items-center gap-1 font-medium text-foreground underline"
|
|
585
585
|
>
|
|
586
|
-
Open
|
|
586
|
+
Open in Builder <IconArrowUpRight className="h-3 w-3" />
|
|
587
587
|
</a>
|
|
588
588
|
) : null}
|
|
589
589
|
</div>
|
|
@@ -33,6 +33,9 @@ vi.mock("@agent-native/core/client/agent-chat", () => ({
|
|
|
33
33
|
path: string,
|
|
34
34
|
options?: unknown,
|
|
35
35
|
) => clientState.navigateWithTransition(navigate, path, options),
|
|
36
|
+
orderChatFirstAppIds: (appIds: string[]) => appIds,
|
|
37
|
+
readChatFirstAppLayout: () => ({ pinnedIds: [], orderedIds: [] }),
|
|
38
|
+
writeChatFirstAppLayout: () => ({ ok: true }),
|
|
36
39
|
useChatModels: clientState.useChatModels,
|
|
37
40
|
}));
|
|
38
41
|
|
|
@@ -53,6 +56,11 @@ vi.mock("@agent-native/core/client/composer", () => ({
|
|
|
53
56
|
},
|
|
54
57
|
}));
|
|
55
58
|
|
|
59
|
+
vi.mock("@agent-native/core/client/application-state", () => ({
|
|
60
|
+
readClientAppState: vi.fn(async () => null),
|
|
61
|
+
writeClientAppState: vi.fn(async () => null),
|
|
62
|
+
}));
|
|
63
|
+
|
|
56
64
|
vi.mock("@agent-native/core/client/hooks", () => ({
|
|
57
65
|
useActionQuery: (name: string) => ({
|
|
58
66
|
data:
|
|
@@ -129,6 +137,15 @@ describe("DispatchControlPlane", () => {
|
|
|
129
137
|
expect(container.textContent).not.toContain("Open chat");
|
|
130
138
|
expect(container.textContent).not.toContain("Also");
|
|
131
139
|
expect(container.textContent).not.toContain("active");
|
|
140
|
+
expect(container.textContent).not.toContain(
|
|
141
|
+
"Summarize the current workspace health",
|
|
142
|
+
);
|
|
143
|
+
expect(container.textContent).toContain(
|
|
144
|
+
"Create an app for onboarding requests",
|
|
145
|
+
);
|
|
146
|
+
expect(container.textContent).toContain(
|
|
147
|
+
"Check which agents can help with analytics",
|
|
148
|
+
);
|
|
132
149
|
expect(container.querySelector("nav")).toBeNull();
|
|
133
150
|
expect(
|
|
134
151
|
container.querySelector('[data-placeholder="Ask Dispatch anything..."]'),
|
|
@@ -274,16 +291,33 @@ describe("DispatchControlPlane", () => {
|
|
|
274
291
|
expect(container.textContent).toContain("Analytics");
|
|
275
292
|
expect(container.textContent).toContain("Apps");
|
|
276
293
|
expect(container.textContent).toContain("New");
|
|
294
|
+
const viewAllLink = Array.from(container.querySelectorAll("a")).find(
|
|
295
|
+
(link) => link.textContent?.trim() === "View all",
|
|
296
|
+
);
|
|
297
|
+
expect(viewAllLink?.className).toContain("text-muted-foreground");
|
|
277
298
|
expect(container.textContent).not.toContain("Other apps");
|
|
278
299
|
expect(container.textContent).not.toContain("available");
|
|
279
300
|
expect(container.textContent).not.toContain("Archived app");
|
|
280
301
|
expect(container.textContent).not.toContain("Duplicate onboarding");
|
|
281
302
|
expect(container.textContent).not.toContain("CRM");
|
|
282
303
|
expect(
|
|
283
|
-
|
|
284
|
-
|
|
304
|
+
container.querySelectorAll(
|
|
305
|
+
'button[aria-label="Open options for Onboarding"]',
|
|
285
306
|
),
|
|
286
307
|
).toHaveLength(1);
|
|
308
|
+
await act(async () => {
|
|
309
|
+
container
|
|
310
|
+
.querySelector<HTMLButtonElement>(
|
|
311
|
+
'button[aria-label="Open options for Onboarding"]',
|
|
312
|
+
)
|
|
313
|
+
?.dispatchEvent(
|
|
314
|
+
new MouseEvent("pointerdown", { bubbles: true, button: 0 }),
|
|
315
|
+
);
|
|
316
|
+
});
|
|
317
|
+
const onboardingNewTabLink = document.querySelector<HTMLAnchorElement>(
|
|
318
|
+
'a[href="/onboarding"][target="_blank"]',
|
|
319
|
+
);
|
|
320
|
+
expect(onboardingNewTabLink).not.toBeNull();
|
|
287
321
|
const clipsHref = Array.from(container.querySelectorAll("a"))
|
|
288
322
|
.map((anchor) => anchor.getAttribute("href"))
|
|
289
323
|
.find((href) => href?.includes("clips.agent-native.com"));
|