@agent-native/dispatch 0.14.3 → 0.14.4

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.
Files changed (127) hide show
  1. package/README.md +114 -128
  2. package/dist/actions/list_apps.d.ts +1 -0
  3. package/dist/actions/list_apps.js +16 -8
  4. package/dist/actions/list_apps.js.map +1 -1
  5. package/dist/actions/set-mcp-app-access.js +1 -4
  6. package/dist/actions/set-mcp-app-access.js.map +1 -1
  7. package/dist/components/action-query-error.d.ts +8 -0
  8. package/dist/components/action-query-error.d.ts.map +1 -0
  9. package/dist/components/action-query-error.js +10 -0
  10. package/dist/components/action-query-error.js.map +1 -0
  11. package/dist/components/app-keys-popover.d.ts +4 -0
  12. package/dist/components/app-keys-popover.d.ts.map +1 -1
  13. package/dist/components/app-keys-popover.js +26 -14
  14. package/dist/components/app-keys-popover.js.map +1 -1
  15. package/dist/components/dispatch-control-plane.d.ts.map +1 -1
  16. package/dist/components/dispatch-control-plane.js +31 -27
  17. package/dist/components/dispatch-control-plane.js.map +1 -1
  18. package/dist/components/index.d.ts +1 -0
  19. package/dist/components/index.d.ts.map +1 -1
  20. package/dist/components/index.js +1 -0
  21. package/dist/components/index.js.map +1 -1
  22. package/dist/components/layout/Layout.d.ts +1 -0
  23. package/dist/components/layout/Layout.d.ts.map +1 -1
  24. package/dist/components/layout/Layout.js +19 -21
  25. package/dist/components/layout/Layout.js.map +1 -1
  26. package/dist/components/ui/sheet.js +1 -1
  27. package/dist/components/ui/sheet.js.map +1 -1
  28. package/dist/components/ui/toast.js +1 -1
  29. package/dist/components/ui/toast.js.map +1 -1
  30. package/dist/components/workspace-app-card.d.ts.map +1 -1
  31. package/dist/components/workspace-app-card.js +8 -5
  32. package/dist/components/workspace-app-card.js.map +1 -1
  33. package/dist/components/workspace-resource-effective-stack.d.ts.map +1 -1
  34. package/dist/components/workspace-resource-effective-stack.js +6 -1
  35. package/dist/components/workspace-resource-effective-stack.js.map +1 -1
  36. package/dist/components/workspace-resource-impact-preview.d.ts.map +1 -1
  37. package/dist/components/workspace-resource-impact-preview.js +6 -1
  38. package/dist/components/workspace-resource-impact-preview.js.map +1 -1
  39. package/dist/routes/pages/$appId.d.ts.map +1 -1
  40. package/dist/routes/pages/$appId.js +6 -1
  41. package/dist/routes/pages/$appId.js.map +1 -1
  42. package/dist/routes/pages/agents.d.ts.map +1 -1
  43. package/dist/routes/pages/agents.js +5 -8
  44. package/dist/routes/pages/agents.js.map +1 -1
  45. package/dist/routes/pages/approval.d.ts.map +1 -1
  46. package/dist/routes/pages/approval.js +6 -1
  47. package/dist/routes/pages/approval.js.map +1 -1
  48. package/dist/routes/pages/approvals.d.ts.map +1 -1
  49. package/dist/routes/pages/approvals.js +8 -5
  50. package/dist/routes/pages/approvals.js.map +1 -1
  51. package/dist/routes/pages/apps.$appId.d.ts.map +1 -1
  52. package/dist/routes/pages/apps.$appId.js +4 -2
  53. package/dist/routes/pages/apps.$appId.js.map +1 -1
  54. package/dist/routes/pages/apps.d.ts.map +1 -1
  55. package/dist/routes/pages/apps.js +9 -3
  56. package/dist/routes/pages/apps.js.map +1 -1
  57. package/dist/routes/pages/audit.d.ts.map +1 -1
  58. package/dist/routes/pages/audit.js +4 -2
  59. package/dist/routes/pages/audit.js.map +1 -1
  60. package/dist/routes/pages/chat.d.ts.map +1 -1
  61. package/dist/routes/pages/chat.js +16 -2
  62. package/dist/routes/pages/chat.js.map +1 -1
  63. package/dist/routes/pages/destinations.d.ts.map +1 -1
  64. package/dist/routes/pages/destinations.js +5 -3
  65. package/dist/routes/pages/destinations.js.map +1 -1
  66. package/dist/routes/pages/identities.d.ts.map +1 -1
  67. package/dist/routes/pages/identities.js +5 -3
  68. package/dist/routes/pages/identities.js.map +1 -1
  69. package/dist/routes/pages/integrations.d.ts.map +1 -1
  70. package/dist/routes/pages/integrations.js +9 -3
  71. package/dist/routes/pages/integrations.js.map +1 -1
  72. package/dist/routes/pages/thread-debug.d.ts.map +1 -1
  73. package/dist/routes/pages/thread-debug.js +7 -6
  74. package/dist/routes/pages/thread-debug.js.map +1 -1
  75. package/dist/routes/pages/vault.d.ts.map +1 -1
  76. package/dist/routes/pages/vault.js +23 -7
  77. package/dist/routes/pages/vault.js.map +1 -1
  78. package/dist/routes/pages/workspace.d.ts.map +1 -1
  79. package/dist/routes/pages/workspace.js +9 -3
  80. package/dist/routes/pages/workspace.js.map +1 -1
  81. package/dist/server/lib/dispatch-store.d.ts.map +1 -1
  82. package/dist/server/lib/dispatch-store.js +2 -2
  83. package/dist/server/lib/dispatch-store.js.map +1 -1
  84. package/dist/server/lib/mcp-access-store.d.ts.map +1 -1
  85. package/dist/server/lib/mcp-access-store.js +30 -2
  86. package/dist/server/lib/mcp-access-store.js.map +1 -1
  87. package/dist/server/plugins/agent-chat.d.ts +1 -1
  88. package/package.json +2 -2
  89. package/src/actions/list_apps.spec.ts +52 -0
  90. package/src/actions/list_apps.ts +16 -8
  91. package/src/actions/set-mcp-app-access.spec.ts +73 -0
  92. package/src/actions/set-mcp-app-access.ts +1 -5
  93. package/src/components/action-query-error.spec.tsx +56 -0
  94. package/src/components/action-query-error.tsx +32 -0
  95. package/src/components/app-keys-popover.spec.tsx +85 -0
  96. package/src/components/app-keys-popover.tsx +76 -50
  97. package/src/components/dispatch-control-plane.spec.tsx +106 -0
  98. package/src/components/dispatch-control-plane.tsx +71 -115
  99. package/src/components/index.ts +1 -0
  100. package/src/components/layout/Layout.spec.tsx +42 -2
  101. package/src/components/layout/Layout.tsx +22 -27
  102. package/src/components/ui/sheet.tsx +1 -1
  103. package/src/components/ui/toast.tsx +1 -1
  104. package/src/components/workspace-app-card.spec.tsx +80 -0
  105. package/src/components/workspace-app-card.tsx +36 -25
  106. package/src/components/workspace-resource-effective-stack.tsx +13 -1
  107. package/src/components/workspace-resource-impact-preview.tsx +12 -1
  108. package/src/routes/pages/$appId.tsx +17 -1
  109. package/src/routes/pages/agents.tsx +24 -11
  110. package/src/routes/pages/approval.tsx +16 -4
  111. package/src/routes/pages/approvals.tsx +108 -89
  112. package/src/routes/pages/apps.$appId.tsx +9 -2
  113. package/src/routes/pages/apps.tsx +20 -7
  114. package/src/routes/pages/audit.tsx +29 -20
  115. package/src/routes/pages/chat.spec.tsx +94 -0
  116. package/src/routes/pages/chat.tsx +30 -10
  117. package/src/routes/pages/destinations.tsx +75 -62
  118. package/src/routes/pages/identities.tsx +74 -63
  119. package/src/routes/pages/integrations.tsx +17 -10
  120. package/src/routes/pages/thread-debug.tsx +18 -12
  121. package/src/routes/pages/vault.tsx +59 -26
  122. package/src/routes/pages/workspace.tsx +69 -55
  123. package/src/server/lib/approval-fencing.spec.ts +113 -2
  124. package/src/server/lib/dispatch-store.ts +2 -0
  125. package/src/server/lib/mcp-access-store.spec.ts +116 -4
  126. package/src/server/lib/mcp-access-store.ts +37 -2
  127. package/src/server/lib/mcp-gateway.spec.ts +79 -3
@@ -1 +1 @@
1
- {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/agents.tsx"],"names":[],"mappings":"AAmBA,wBAAgB,IAAI;;IAEnB;AAgLD,MAAM,CAAC,OAAO,UAAU,WAAW,oDAkBlC"}
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/agents.tsx"],"names":[],"mappings":"AAoBA,wBAAgB,IAAI;;IAEnB;AAqLD,MAAM,CAAC,OAAO,UAAU,WAAW,oDAyBlC"}
@@ -3,6 +3,7 @@ import { agentNativePath, useActionMutation, useActionQuery, useT, } from "@agen
3
3
  import { IconCheck, IconCopy, IconPlugConnected } from "@tabler/icons-react";
4
4
  import { useMemo, useState } from "react";
5
5
  import { toast } from "sonner";
6
+ import { ActionQueryError } from "../../components/action-query-error.js";
6
7
  import { AgentsPanel, } from "../../components/agents-panel.js";
7
8
  import { DispatchShell } from "../../components/dispatch-shell.js";
8
9
  import { Button } from "../../components/ui/button.js";
@@ -19,7 +20,7 @@ function dispatchMcpUrl() {
19
20
  }
20
21
  function DispatchMcpAccessPanel() {
21
22
  const t = useT();
22
- const { data, isLoading } = useActionQuery("list-mcp-app-access", {});
23
+ const { data, isLoading, isError, error, refetch } = useActionQuery("list-mcp-app-access", {});
23
24
  const [optimistic, setOptimistic] = useState(null);
24
25
  const saveAccess = useActionMutation("set-mcp-app-access", {
25
26
  onSuccess: () => {
@@ -44,10 +45,6 @@ function DispatchMcpAccessPanel() {
44
45
  const grantedCount = access.mode === "all-apps" ? apps.length : access.selectedAppIds.length;
45
46
  const mcpUrl = dispatchMcpUrl();
46
47
  function persist(next) {
47
- if (next.mode === "selected-apps" && next.selectedAppIds.length === 0) {
48
- toast.error(t("dispatch.pages.selectAppForMcp"));
49
- return;
50
- }
51
48
  setOptimistic(next);
52
49
  saveAccess.mutate(next);
53
50
  }
@@ -75,7 +72,7 @@ function DispatchMcpAccessPanel() {
75
72
  selectedAppIds: checked
76
73
  ? access.selectedAppIds
77
74
  : apps.map((app) => app.id),
78
- }), "aria-label": t("dispatch.pages.exposeAllAppsMcp") })] })] }), _jsxs("div", { className: "mt-4 flex flex-col gap-2 sm:flex-row", children: [_jsx(Input, { readOnly: true, value: mcpUrl, className: "font-mono text-xs" }), _jsxs(Button, { type: "button", variant: "outline", onClick: copyUrl, children: [_jsx(IconCopy, { size: 15 }), t("dispatch.pages.copyUrl")] })] }), access.mode === "selected-apps" ? (_jsx("div", { className: "mt-4 grid gap-2 sm:grid-cols-2 xl:grid-cols-3", children: apps.map((app) => {
75
+ }), "aria-label": t("dispatch.pages.exposeAllAppsMcp") })] })] }), _jsxs("div", { className: "mt-4 flex flex-col gap-2 sm:flex-row", children: [_jsx(Input, { readOnly: true, value: mcpUrl, className: "font-mono text-xs" }), _jsxs(Button, { type: "button", variant: "outline", onClick: copyUrl, children: [_jsx(IconCopy, { size: 15 }), t("dispatch.pages.copyUrl")] })] }), isError ? (_jsx(ActionQueryError, { className: "mt-4", error: error, onRetry: () => void refetch() })) : access.mode === "selected-apps" ? (_jsx("div", { className: "mt-4 grid gap-2 sm:grid-cols-2 xl:grid-cols-3", children: apps.map((app) => {
79
76
  const isSelected = selected.has(app.id);
80
77
  return (_jsxs("button", { type: "button", disabled: saveAccess.isPending &&
81
78
  optimistic?.selectedAppIds.includes(app.id) !== isSelected, onClick: () => toggleApp(app.id), className: "flex min-h-[76px] items-start gap-3 rounded-xl border bg-muted/20 px-3 py-3 text-left transition hover:bg-muted/40 disabled:cursor-not-allowed disabled:opacity-60", "aria-pressed": isSelected, children: [_jsx("span", { className: "mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-xs font-bold text-white", style: { backgroundColor: app.color }, children: app.name.charAt(0).toUpperCase() }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsxs("span", { className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [app.name, isSelected ? (_jsx(IconCheck, { size: 14, className: "text-emerald-500" })) : null] }), _jsx("span", { className: "mt-1 line-clamp-2 block text-xs text-muted-foreground", children: app.description || app.url })] })] }, app.id));
@@ -83,7 +80,7 @@ function DispatchMcpAccessPanel() {
83
80
  }
84
81
  export default function AgentsRoute() {
85
82
  const t = useT();
86
- const { data, refetch } = useActionQuery("list-connected-agents", {});
87
- return (_jsx(DispatchShell, { title: t("dispatch.nav.agents"), description: t("dispatch.pages.agentsDescription"), children: _jsxs("div", { className: "space-y-4", children: [_jsx(DispatchMcpAccessPanel, {}), _jsx(AgentsPanel, { agents: (data || []), onRefresh: refetch })] }) }));
83
+ const agentsQuery = useActionQuery("list-connected-agents", {});
84
+ return (_jsx(DispatchShell, { title: t("dispatch.nav.agents"), description: t("dispatch.pages.agentsDescription"), children: _jsxs("div", { className: "space-y-4", children: [_jsx(DispatchMcpAccessPanel, {}), agentsQuery.isError ? (_jsx(ActionQueryError, { error: agentsQuery.error, onRetry: () => void agentsQuery.refetch() })) : (_jsx(AgentsPanel, { agents: (agentsQuery.data || []), onRefresh: agentsQuery.refetch }))] }) }));
88
85
  }
89
86
  //# sourceMappingURL=agents.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"agents.js","sourceRoot":"","sources":["../../../src/routes/pages/agents.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n agentNativePath,\n useActionMutation,\n useActionQuery,\n useT,\n} from \"@agent-native/core/client\";\nimport { IconCheck, IconCopy, IconPlugConnected } from \"@tabler/icons-react\";\nimport { useMemo, useState } from \"react\";\nimport { toast } from \"sonner\";\n\nimport {\n AgentsPanel,\n type ConnectedAgent,\n} from \"../../components/agents-panel\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport { Button } from \"../../components/ui/button\";\nimport { Input } from \"../../components/ui/input\";\nimport { Switch } from \"../../components/ui/switch\";\n\nexport function meta() {\n return [{ title: \"Agents — Dispatch\" }];\n}\n\ninterface McpAccessApp {\n id: string;\n name: string;\n description: string;\n url: string;\n color: string;\n granted: boolean;\n}\n\ntype McpAccessMode = \"all-apps\" | \"selected-apps\";\n\ninterface McpAccessState {\n mode: McpAccessMode;\n selectedAppIds: string[];\n}\n\nfunction dispatchMcpUrl(): string {\n const path = agentNativePath(\"/_agent-native/mcp\");\n if (typeof window === \"undefined\") return path;\n return new URL(path, window.location.origin).href;\n}\n\nfunction DispatchMcpAccessPanel() {\n const t = useT();\n const { data, isLoading } = useActionQuery(\"list-mcp-app-access\", {});\n const [optimistic, setOptimistic] = useState<McpAccessState | null>(null);\n const saveAccess = useActionMutation(\"set-mcp-app-access\", {\n onSuccess: () => {\n setOptimistic(null);\n toast.success(t(\"dispatch.pages.mcpAccessUpdated\"));\n },\n onError: (error) => {\n setOptimistic(null);\n toast.error(error.message);\n },\n });\n\n const apps = ((data as { apps?: McpAccessApp[] } | undefined)?.apps ??\n []) as McpAccessApp[];\n const access =\n optimistic ??\n ({\n mode: ((data as { mode?: McpAccessMode } | undefined)?.mode ??\n \"all-apps\") as McpAccessMode,\n selectedAppIds:\n (data as { selectedAppIds?: string[] } | undefined)?.selectedAppIds ??\n [],\n } satisfies McpAccessState);\n const selected = useMemo(\n () => new Set(access.selectedAppIds),\n [access.selectedAppIds],\n );\n const grantedCount =\n access.mode === \"all-apps\" ? apps.length : access.selectedAppIds.length;\n const mcpUrl = dispatchMcpUrl();\n\n function persist(next: McpAccessState) {\n if (next.mode === \"selected-apps\" && next.selectedAppIds.length === 0) {\n toast.error(t(\"dispatch.pages.selectAppForMcp\"));\n return;\n }\n setOptimistic(next);\n saveAccess.mutate(next);\n }\n\n function toggleApp(appId: string) {\n const next = selected.has(appId)\n ? access.selectedAppIds.filter((id) => id !== appId)\n : [...access.selectedAppIds, appId];\n persist({ mode: \"selected-apps\", selectedAppIds: next });\n }\n\n async function copyUrl() {\n try {\n await navigator.clipboard.writeText(mcpUrl);\n toast.success(t(\"dispatch.pages.mcpUrlCopied\"));\n } catch {\n toast.error(t(\"dispatch.pages.mcpUrlCopyFailed\"));\n }\n }\n\n return (\n <section className=\"rounded-2xl border bg-card p-5\">\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2 text-sm font-medium text-foreground\">\n <IconPlugConnected size={16} />\n {t(\"dispatch.pages.unifiedMcpGateway\")}\n </div>\n <div className=\"mt-1 max-w-2xl text-sm text-muted-foreground\">\n {t(\"dispatch.pages.unifiedMcpGatewayDescription\")}{\" \"}\n <code>list_apps</code>, <code>ask_app</code>, and{\" \"}\n <code>open_app</code>.\n </div>\n </div>\n <div className=\"flex items-center gap-3 rounded-xl border px-3 py-2\">\n <div>\n <div className=\"text-xs font-medium text-foreground\">\n {access.mode === \"all-apps\"\n ? t(\"dispatch.pages.allApps\")\n : t(\"dispatch.pages.selectedApps\")}\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {isLoading\n ? t(\"dispatch.pages.loading\")\n : t(\"dispatch.pages.grantedCount\", { count: grantedCount })}\n </div>\n </div>\n <Switch\n checked={access.mode === \"all-apps\"}\n disabled={saveAccess.isPending || apps.length === 0}\n onCheckedChange={(checked) =>\n persist({\n mode: checked ? \"all-apps\" : \"selected-apps\",\n selectedAppIds: checked\n ? access.selectedAppIds\n : apps.map((app) => app.id),\n })\n }\n aria-label={t(\"dispatch.pages.exposeAllAppsMcp\")}\n />\n </div>\n </div>\n\n <div className=\"mt-4 flex flex-col gap-2 sm:flex-row\">\n <Input readOnly value={mcpUrl} className=\"font-mono text-xs\" />\n <Button type=\"button\" variant=\"outline\" onClick={copyUrl}>\n <IconCopy size={15} />\n {t(\"dispatch.pages.copyUrl\")}\n </Button>\n </div>\n\n {access.mode === \"selected-apps\" ? (\n <div className=\"mt-4 grid gap-2 sm:grid-cols-2 xl:grid-cols-3\">\n {apps.map((app) => {\n const isSelected = selected.has(app.id);\n return (\n <button\n key={app.id}\n type=\"button\"\n disabled={\n saveAccess.isPending &&\n optimistic?.selectedAppIds.includes(app.id) !== isSelected\n }\n onClick={() => toggleApp(app.id)}\n className=\"flex min-h-[76px] items-start gap-3 rounded-xl border bg-muted/20 px-3 py-3 text-left transition hover:bg-muted/40 disabled:cursor-not-allowed disabled:opacity-60\"\n aria-pressed={isSelected}\n >\n <span\n className=\"mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-xs font-bold text-white\"\n style={{ backgroundColor: app.color }}\n >\n {app.name.charAt(0).toUpperCase()}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"flex items-center gap-2 text-sm font-medium text-foreground\">\n {app.name}\n {isSelected ? (\n <IconCheck size={14} className=\"text-emerald-500\" />\n ) : null}\n </span>\n <span className=\"mt-1 line-clamp-2 block text-xs text-muted-foreground\">\n {app.description || app.url}\n </span>\n </span>\n </button>\n );\n })}\n </div>\n ) : null}\n </section>\n );\n}\n\nexport default function AgentsRoute() {\n const t = useT();\n const { data, refetch } = useActionQuery(\"list-connected-agents\", {});\n\n return (\n <DispatchShell\n title={t(\"dispatch.nav.agents\")}\n description={t(\"dispatch.pages.agentsDescription\")}\n >\n <div className=\"space-y-4\">\n <DispatchMcpAccessPanel />\n <AgentsPanel\n agents={(data || []) as ConnectedAgent[]}\n onRefresh={refetch}\n />\n </div>\n </DispatchShell>\n );\n}\n"]}
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../../../src/routes/pages/agents.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n agentNativePath,\n useActionMutation,\n useActionQuery,\n useT,\n} from \"@agent-native/core/client\";\nimport { IconCheck, IconCopy, IconPlugConnected } from \"@tabler/icons-react\";\nimport { useMemo, useState } from \"react\";\nimport { toast } from \"sonner\";\n\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport {\n AgentsPanel,\n type ConnectedAgent,\n} from \"../../components/agents-panel\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport { Button } from \"../../components/ui/button\";\nimport { Input } from \"../../components/ui/input\";\nimport { Switch } from \"../../components/ui/switch\";\n\nexport function meta() {\n return [{ title: \"Agents — Dispatch\" }];\n}\n\ninterface McpAccessApp {\n id: string;\n name: string;\n description: string;\n url: string;\n color: string;\n granted: boolean;\n}\n\ntype McpAccessMode = \"all-apps\" | \"selected-apps\";\n\ninterface McpAccessState {\n mode: McpAccessMode;\n selectedAppIds: string[];\n}\n\nfunction dispatchMcpUrl(): string {\n const path = agentNativePath(\"/_agent-native/mcp\");\n if (typeof window === \"undefined\") return path;\n return new URL(path, window.location.origin).href;\n}\n\nfunction DispatchMcpAccessPanel() {\n const t = useT();\n const { data, isLoading, isError, error, refetch } = useActionQuery(\n \"list-mcp-app-access\",\n {},\n );\n const [optimistic, setOptimistic] = useState<McpAccessState | null>(null);\n const saveAccess = useActionMutation(\"set-mcp-app-access\", {\n onSuccess: () => {\n setOptimistic(null);\n toast.success(t(\"dispatch.pages.mcpAccessUpdated\"));\n },\n onError: (error) => {\n setOptimistic(null);\n toast.error(error.message);\n },\n });\n\n const apps = ((data as { apps?: McpAccessApp[] } | undefined)?.apps ??\n []) as McpAccessApp[];\n const access =\n optimistic ??\n ({\n mode: ((data as { mode?: McpAccessMode } | undefined)?.mode ??\n \"all-apps\") as McpAccessMode,\n selectedAppIds:\n (data as { selectedAppIds?: string[] } | undefined)?.selectedAppIds ??\n [],\n } satisfies McpAccessState);\n const selected = useMemo(\n () => new Set(access.selectedAppIds),\n [access.selectedAppIds],\n );\n const grantedCount =\n access.mode === \"all-apps\" ? apps.length : access.selectedAppIds.length;\n const mcpUrl = dispatchMcpUrl();\n\n function persist(next: McpAccessState) {\n setOptimistic(next);\n saveAccess.mutate(next);\n }\n\n function toggleApp(appId: string) {\n const next = selected.has(appId)\n ? access.selectedAppIds.filter((id) => id !== appId)\n : [...access.selectedAppIds, appId];\n persist({ mode: \"selected-apps\", selectedAppIds: next });\n }\n\n async function copyUrl() {\n try {\n await navigator.clipboard.writeText(mcpUrl);\n toast.success(t(\"dispatch.pages.mcpUrlCopied\"));\n } catch {\n toast.error(t(\"dispatch.pages.mcpUrlCopyFailed\"));\n }\n }\n\n return (\n <section className=\"rounded-2xl border bg-card p-5\">\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2 text-sm font-medium text-foreground\">\n <IconPlugConnected size={16} />\n {t(\"dispatch.pages.unifiedMcpGateway\")}\n </div>\n <div className=\"mt-1 max-w-2xl text-sm text-muted-foreground\">\n {t(\"dispatch.pages.unifiedMcpGatewayDescription\")}{\" \"}\n <code>list_apps</code>, <code>ask_app</code>, and{\" \"}\n <code>open_app</code>.\n </div>\n </div>\n <div className=\"flex items-center gap-3 rounded-xl border px-3 py-2\">\n <div>\n <div className=\"text-xs font-medium text-foreground\">\n {access.mode === \"all-apps\"\n ? t(\"dispatch.pages.allApps\")\n : t(\"dispatch.pages.selectedApps\")}\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {isLoading\n ? t(\"dispatch.pages.loading\")\n : t(\"dispatch.pages.grantedCount\", { count: grantedCount })}\n </div>\n </div>\n <Switch\n checked={access.mode === \"all-apps\"}\n disabled={saveAccess.isPending || apps.length === 0}\n onCheckedChange={(checked) =>\n persist({\n mode: checked ? \"all-apps\" : \"selected-apps\",\n selectedAppIds: checked\n ? access.selectedAppIds\n : apps.map((app) => app.id),\n })\n }\n aria-label={t(\"dispatch.pages.exposeAllAppsMcp\")}\n />\n </div>\n </div>\n\n <div className=\"mt-4 flex flex-col gap-2 sm:flex-row\">\n <Input readOnly value={mcpUrl} className=\"font-mono text-xs\" />\n <Button type=\"button\" variant=\"outline\" onClick={copyUrl}>\n <IconCopy size={15} />\n {t(\"dispatch.pages.copyUrl\")}\n </Button>\n </div>\n\n {isError ? (\n <ActionQueryError\n className=\"mt-4\"\n error={error}\n onRetry={() => void refetch()}\n />\n ) : access.mode === \"selected-apps\" ? (\n <div className=\"mt-4 grid gap-2 sm:grid-cols-2 xl:grid-cols-3\">\n {apps.map((app) => {\n const isSelected = selected.has(app.id);\n return (\n <button\n key={app.id}\n type=\"button\"\n disabled={\n saveAccess.isPending &&\n optimistic?.selectedAppIds.includes(app.id) !== isSelected\n }\n onClick={() => toggleApp(app.id)}\n className=\"flex min-h-[76px] items-start gap-3 rounded-xl border bg-muted/20 px-3 py-3 text-left transition hover:bg-muted/40 disabled:cursor-not-allowed disabled:opacity-60\"\n aria-pressed={isSelected}\n >\n <span\n className=\"mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-xs font-bold text-white\"\n style={{ backgroundColor: app.color }}\n >\n {app.name.charAt(0).toUpperCase()}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"flex items-center gap-2 text-sm font-medium text-foreground\">\n {app.name}\n {isSelected ? (\n <IconCheck size={14} className=\"text-emerald-500\" />\n ) : null}\n </span>\n <span className=\"mt-1 line-clamp-2 block text-xs text-muted-foreground\">\n {app.description || app.url}\n </span>\n </span>\n </button>\n );\n })}\n </div>\n ) : null}\n </section>\n );\n}\n\nexport default function AgentsRoute() {\n const t = useT();\n const agentsQuery = useActionQuery(\"list-connected-agents\", {});\n\n return (\n <DispatchShell\n title={t(\"dispatch.nav.agents\")}\n description={t(\"dispatch.pages.agentsDescription\")}\n >\n <div className=\"space-y-4\">\n <DispatchMcpAccessPanel />\n {agentsQuery.isError ? (\n <ActionQueryError\n error={agentsQuery.error}\n onRetry={() => void agentsQuery.refetch()}\n />\n ) : (\n <AgentsPanel\n agents={(agentsQuery.data || []) as ConnectedAgent[]}\n onRefresh={agentsQuery.refetch}\n />\n )}\n </div>\n </DispatchShell>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"approval.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/approval.tsx"],"names":[],"mappings":"AA0BA,wBAAgB,IAAI;;IAEnB;AAoCD,MAAM,CAAC,OAAO,UAAU,oBAAoB,oDA8N3C"}
1
+ {"version":3,"file":"approval.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/approval.tsx"],"names":[],"mappings":"AA2BA,wBAAgB,IAAI;;IAEnB;AAoCD,MAAM,CAAC,OAAO,UAAU,oBAAoB,oDAyO3C"}
@@ -3,6 +3,7 @@ import { useActionMutation, useActionQuery, isInAgentEmbed, postNavigate, appPat
3
3
  import { IconCheck, IconX, IconArrowUpRight, IconShieldCheck, IconClock, IconAlertCircle, } from "@tabler/icons-react";
4
4
  import { useSearchParams } from "react-router";
5
5
  import { toast } from "sonner";
6
+ import { ActionQueryError } from "../../components/action-query-error.js";
6
7
  import { ApprovalValueBlock, parseApprovalValue, } from "../../components/approval-value-block.js";
7
8
  import { Badge } from "../../components/ui/badge.js";
8
9
  import { Button } from "../../components/ui/button.js";
@@ -22,7 +23,8 @@ function StatusBadge({ status }) {
22
23
  export default function ApprovalPreviewRoute() {
23
24
  const [searchParams] = useSearchParams();
24
25
  const id = searchParams.get("id") ?? "";
25
- const { data: approvals, isLoading } = useActionQuery("list-dispatch-approvals", {});
26
+ const approvalsQuery = useActionQuery("list-dispatch-approvals", {});
27
+ const { data: approvals, isLoading } = approvalsQuery;
26
28
  const approve = useActionMutation("approve-dispatch-change", {
27
29
  onSuccess: () => toast.success("Change approved"),
28
30
  });
@@ -37,6 +39,9 @@ export default function ApprovalPreviewRoute() {
37
39
  if (isLoading) {
38
40
  return (_jsx("div", { className: "flex min-h-screen items-start justify-center bg-background p-6", children: _jsx("div", { className: "w-full max-w-md space-y-4", children: _jsxs("div", { className: "rounded-2xl border bg-card p-5", children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsx(Skeleton, { className: "h-9 w-9 shrink-0 rounded-xl" }), _jsxs("div", { className: "min-w-0 flex-1 space-y-2", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Skeleton, { className: "h-4 w-40" }), _jsx(Skeleton, { className: "h-5 w-20 rounded-full" })] }), _jsx(Skeleton, { className: "h-3 w-32" })] })] }), _jsxs("div", { className: "mt-4 space-y-2 rounded-xl border bg-muted/30 px-4 py-3", children: [_jsxs("div", { className: "flex justify-between gap-4", children: [_jsx(Skeleton, { className: "h-3 w-20" }), _jsx(Skeleton, { className: "h-3 w-24" })] }), _jsxs("div", { className: "flex justify-between gap-4", children: [_jsx(Skeleton, { className: "h-3 w-20" }), _jsx(Skeleton, { className: "h-3 w-28" })] }), _jsxs("div", { className: "flex justify-between gap-4", children: [_jsx(Skeleton, { className: "h-3 w-16" }), _jsx(Skeleton, { className: "h-3 w-32" })] })] }), _jsxs("div", { className: "mt-4 flex gap-2", children: [_jsx(Skeleton, { className: "h-8 flex-1 rounded-md" }), _jsx(Skeleton, { className: "h-8 flex-1 rounded-md" })] })] }) }) }));
39
41
  }
42
+ if (approvalsQuery.isError) {
43
+ return (_jsx("div", { className: "flex min-h-screen items-start justify-center bg-background p-6", children: _jsx("div", { className: "w-full max-w-md", children: _jsx(ActionQueryError, { error: approvalsQuery.error, onRetry: () => void approvalsQuery.refetch() }) }) }));
44
+ }
40
45
  if (!approval) {
41
46
  return (_jsx("div", { className: "flex min-h-screen items-center justify-center bg-background p-6", children: _jsxs("div", { className: "w-full max-w-md rounded-2xl border bg-card p-6 text-center", children: [_jsx(IconAlertCircle, { size: 32, className: "mx-auto mb-3 text-muted-foreground" }), _jsx("p", { className: "text-sm font-medium text-foreground", children: "Approval not found" }), _jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: ["The approval with id", " ", _jsx("code", { className: "rounded bg-muted px-1", children: id }), " does not exist."] }), inEmbed && (_jsxs(Button, { size: "sm", variant: "outline", className: "mt-4 gap-1.5", onClick: () => postNavigate(appPath("/approvals")), children: [_jsx(IconArrowUpRight, { size: 14 }), "View all approvals"] }))] }) }));
42
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"approval.js","sourceRoot":"","sources":["../../../src/routes/pages/approval.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useActionMutation,\n useActionQuery,\n isInAgentEmbed,\n postNavigate,\n appPath,\n} from \"@agent-native/core/client\";\nimport {\n IconCheck,\n IconX,\n IconArrowUpRight,\n IconShieldCheck,\n IconClock,\n IconAlertCircle,\n} from \"@tabler/icons-react\";\nimport { useSearchParams } from \"react-router\";\nimport { toast } from \"sonner\";\n\nimport {\n ApprovalValueBlock,\n parseApprovalValue,\n} from \"../../components/approval-value-block\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { Skeleton } from \"../../components/ui/skeleton\";\n\nexport function meta() {\n return [{ title: \"Approval — Dispatch\" }];\n}\n\nfunction StatusBadge({ status }: { status: string }) {\n if (status === \"pending\") {\n return (\n <Badge\n variant=\"outline\"\n className=\"gap-1.5 border-amber-500/40 bg-amber-500/10 text-amber-600 dark:text-amber-400\"\n >\n <IconClock size={11} />\n Pending\n </Badge>\n );\n }\n if (status === \"approved\") {\n return (\n <Badge\n variant=\"outline\"\n className=\"gap-1.5 border-emerald-500/40 bg-emerald-500/10 text-emerald-600 dark:text-emerald-400\"\n >\n <IconCheck size={11} />\n Approved\n </Badge>\n );\n }\n return (\n <Badge\n variant=\"outline\"\n className=\"gap-1.5 border-red-500/40 bg-red-500/10 text-red-600 dark:text-red-400\"\n >\n <IconX size={11} />\n Rejected\n </Badge>\n );\n}\n\nexport default function ApprovalPreviewRoute() {\n const [searchParams] = useSearchParams();\n const id = searchParams.get(\"id\") ?? \"\";\n\n const { data: approvals, isLoading } = useActionQuery(\n \"list-dispatch-approvals\",\n {},\n );\n\n const approve = useActionMutation(\"approve-dispatch-change\", {\n onSuccess: () => toast.success(\"Change approved\"),\n });\n const reject = useActionMutation(\"reject-dispatch-change\", {\n onSuccess: () => toast.success(\"Change rejected\"),\n });\n\n const inEmbed = isInAgentEmbed();\n\n const approval = approvals?.find((item: any) => item.id === id) ?? null;\n\n if (!id) {\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-background p-6\">\n <div className=\"w-full max-w-md rounded-2xl border bg-card p-6 text-center\">\n <IconAlertCircle\n size={32}\n className=\"mx-auto mb-3 text-muted-foreground\"\n />\n <p className=\"text-sm font-medium text-foreground\">\n No approval id provided\n </p>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n Add <code className=\"rounded bg-muted px-1\">?id=&lt;id&gt;</code> to\n the URL.\n </p>\n </div>\n </div>\n );\n }\n\n if (isLoading) {\n return (\n <div className=\"flex min-h-screen items-start justify-center bg-background p-6\">\n <div className=\"w-full max-w-md space-y-4\">\n <div className=\"rounded-2xl border bg-card p-5\">\n <div className=\"flex items-start gap-3\">\n <Skeleton className=\"h-9 w-9 shrink-0 rounded-xl\" />\n <div className=\"min-w-0 flex-1 space-y-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <Skeleton className=\"h-4 w-40\" />\n <Skeleton className=\"h-5 w-20 rounded-full\" />\n </div>\n <Skeleton className=\"h-3 w-32\" />\n </div>\n </div>\n <div className=\"mt-4 space-y-2 rounded-xl border bg-muted/30 px-4 py-3\">\n <div className=\"flex justify-between gap-4\">\n <Skeleton className=\"h-3 w-20\" />\n <Skeleton className=\"h-3 w-24\" />\n </div>\n <div className=\"flex justify-between gap-4\">\n <Skeleton className=\"h-3 w-20\" />\n <Skeleton className=\"h-3 w-28\" />\n </div>\n <div className=\"flex justify-between gap-4\">\n <Skeleton className=\"h-3 w-16\" />\n <Skeleton className=\"h-3 w-32\" />\n </div>\n </div>\n <div className=\"mt-4 flex gap-2\">\n <Skeleton className=\"h-8 flex-1 rounded-md\" />\n <Skeleton className=\"h-8 flex-1 rounded-md\" />\n </div>\n </div>\n </div>\n </div>\n );\n }\n\n if (!approval) {\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-background p-6\">\n <div className=\"w-full max-w-md rounded-2xl border bg-card p-6 text-center\">\n <IconAlertCircle\n size={32}\n className=\"mx-auto mb-3 text-muted-foreground\"\n />\n <p className=\"text-sm font-medium text-foreground\">\n Approval not found\n </p>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n The approval with id{\" \"}\n <code className=\"rounded bg-muted px-1\">{id}</code> does not exist.\n </p>\n {inEmbed && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"mt-4 gap-1.5\"\n onClick={() => postNavigate(appPath(\"/approvals\"))}\n >\n <IconArrowUpRight size={14} />\n View all approvals\n </Button>\n )}\n </div>\n </div>\n );\n }\n\n const isPending = approval.status === \"pending\";\n const beforeValue = parseApprovalValue(approval.beforeValue);\n const afterValue = parseApprovalValue(approval.afterValue);\n\n return (\n <div className=\"flex min-h-screen items-start justify-center bg-background p-6\">\n <div className=\"w-full max-w-2xl space-y-4\">\n <div className=\"rounded-2xl border bg-card p-5\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-xl border bg-muted text-foreground\">\n <IconShieldCheck size={17} />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-sm font-semibold text-foreground\">\n {approval.summary}\n </span>\n <StatusBadge status={approval.status} />\n </div>\n <div className=\"mt-1 text-xs text-muted-foreground\">\n Requested by{\" \"}\n <span className=\"font-medium text-foreground\">\n {approval.requestedBy}\n </span>\n </div>\n </div>\n </div>\n\n <div className=\"mt-4 space-y-2 rounded-xl border bg-muted/30 px-4 py-3 text-xs\">\n <div className=\"flex justify-between gap-4\">\n <span className=\"text-muted-foreground\">Change type</span>\n <span className=\"font-mono font-medium text-foreground\">\n {approval.changeType}\n </span>\n </div>\n <div className=\"flex justify-between gap-4\">\n <span className=\"text-muted-foreground\">Target type</span>\n <span className=\"font-mono font-medium text-foreground\">\n {approval.targetType}\n </span>\n </div>\n {approval.targetId && (\n <div className=\"flex justify-between gap-4\">\n <span className=\"text-muted-foreground\">Target id</span>\n <span className=\"truncate font-mono font-medium text-foreground\">\n {approval.targetId}\n </span>\n </div>\n )}\n {approval.reviewedBy && (\n <div className=\"flex justify-between gap-4\">\n <span className=\"text-muted-foreground\">Reviewed by</span>\n <span className=\"font-medium text-foreground\">\n {approval.reviewedBy}\n </span>\n </div>\n )}\n </div>\n\n {(beforeValue !== null || afterValue !== null) && (\n <div className=\"mt-4 grid gap-3 md:grid-cols-2\">\n <ApprovalValueBlock label=\"Before\" value={beforeValue} />\n <ApprovalValueBlock label=\"After\" value={afterValue} />\n </div>\n )}\n\n {isPending && (\n <div className=\"mt-4 flex gap-2\">\n <Button\n size=\"sm\"\n className=\"flex-1\"\n disabled={approve.isPending || reject.isPending}\n onClick={() => approve.mutate({ id: approval.id })}\n >\n <IconCheck size={14} className=\"mr-1.5\" />\n Approve\n </Button>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"flex-1\"\n disabled={approve.isPending || reject.isPending}\n onClick={() =>\n reject.mutate({\n id: approval.id,\n reason: \"Rejected in dispatch UI\",\n })\n }\n >\n <IconX size={14} className=\"mr-1.5\" />\n Reject\n </Button>\n </div>\n )}\n </div>\n\n {inEmbed && (\n <div className=\"flex justify-end\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"gap-1.5 text-muted-foreground\"\n onClick={() => postNavigate(appPath(\"/approvals\"))}\n >\n <IconArrowUpRight size={14} />\n Open in app\n </Button>\n </div>\n )}\n </div>\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"approval.js","sourceRoot":"","sources":["../../../src/routes/pages/approval.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useActionMutation,\n useActionQuery,\n isInAgentEmbed,\n postNavigate,\n appPath,\n} from \"@agent-native/core/client\";\nimport {\n IconCheck,\n IconX,\n IconArrowUpRight,\n IconShieldCheck,\n IconClock,\n IconAlertCircle,\n} from \"@tabler/icons-react\";\nimport { useSearchParams } from \"react-router\";\nimport { toast } from \"sonner\";\n\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport {\n ApprovalValueBlock,\n parseApprovalValue,\n} from \"../../components/approval-value-block\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { Skeleton } from \"../../components/ui/skeleton\";\n\nexport function meta() {\n return [{ title: \"Approval — Dispatch\" }];\n}\n\nfunction StatusBadge({ status }: { status: string }) {\n if (status === \"pending\") {\n return (\n <Badge\n variant=\"outline\"\n className=\"gap-1.5 border-amber-500/40 bg-amber-500/10 text-amber-600 dark:text-amber-400\"\n >\n <IconClock size={11} />\n Pending\n </Badge>\n );\n }\n if (status === \"approved\") {\n return (\n <Badge\n variant=\"outline\"\n className=\"gap-1.5 border-emerald-500/40 bg-emerald-500/10 text-emerald-600 dark:text-emerald-400\"\n >\n <IconCheck size={11} />\n Approved\n </Badge>\n );\n }\n return (\n <Badge\n variant=\"outline\"\n className=\"gap-1.5 border-red-500/40 bg-red-500/10 text-red-600 dark:text-red-400\"\n >\n <IconX size={11} />\n Rejected\n </Badge>\n );\n}\n\nexport default function ApprovalPreviewRoute() {\n const [searchParams] = useSearchParams();\n const id = searchParams.get(\"id\") ?? \"\";\n\n const approvalsQuery = useActionQuery(\"list-dispatch-approvals\", {});\n const { data: approvals, isLoading } = approvalsQuery;\n\n const approve = useActionMutation(\"approve-dispatch-change\", {\n onSuccess: () => toast.success(\"Change approved\"),\n });\n const reject = useActionMutation(\"reject-dispatch-change\", {\n onSuccess: () => toast.success(\"Change rejected\"),\n });\n\n const inEmbed = isInAgentEmbed();\n\n const approval = approvals?.find((item: any) => item.id === id) ?? null;\n\n if (!id) {\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-background p-6\">\n <div className=\"w-full max-w-md rounded-2xl border bg-card p-6 text-center\">\n <IconAlertCircle\n size={32}\n className=\"mx-auto mb-3 text-muted-foreground\"\n />\n <p className=\"text-sm font-medium text-foreground\">\n No approval id provided\n </p>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n Add <code className=\"rounded bg-muted px-1\">?id=&lt;id&gt;</code> to\n the URL.\n </p>\n </div>\n </div>\n );\n }\n\n if (isLoading) {\n return (\n <div className=\"flex min-h-screen items-start justify-center bg-background p-6\">\n <div className=\"w-full max-w-md space-y-4\">\n <div className=\"rounded-2xl border bg-card p-5\">\n <div className=\"flex items-start gap-3\">\n <Skeleton className=\"h-9 w-9 shrink-0 rounded-xl\" />\n <div className=\"min-w-0 flex-1 space-y-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <Skeleton className=\"h-4 w-40\" />\n <Skeleton className=\"h-5 w-20 rounded-full\" />\n </div>\n <Skeleton className=\"h-3 w-32\" />\n </div>\n </div>\n <div className=\"mt-4 space-y-2 rounded-xl border bg-muted/30 px-4 py-3\">\n <div className=\"flex justify-between gap-4\">\n <Skeleton className=\"h-3 w-20\" />\n <Skeleton className=\"h-3 w-24\" />\n </div>\n <div className=\"flex justify-between gap-4\">\n <Skeleton className=\"h-3 w-20\" />\n <Skeleton className=\"h-3 w-28\" />\n </div>\n <div className=\"flex justify-between gap-4\">\n <Skeleton className=\"h-3 w-16\" />\n <Skeleton className=\"h-3 w-32\" />\n </div>\n </div>\n <div className=\"mt-4 flex gap-2\">\n <Skeleton className=\"h-8 flex-1 rounded-md\" />\n <Skeleton className=\"h-8 flex-1 rounded-md\" />\n </div>\n </div>\n </div>\n </div>\n );\n }\n\n if (approvalsQuery.isError) {\n return (\n <div className=\"flex min-h-screen items-start justify-center bg-background p-6\">\n <div className=\"w-full max-w-md\">\n <ActionQueryError\n error={approvalsQuery.error}\n onRetry={() => void approvalsQuery.refetch()}\n />\n </div>\n </div>\n );\n }\n\n if (!approval) {\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-background p-6\">\n <div className=\"w-full max-w-md rounded-2xl border bg-card p-6 text-center\">\n <IconAlertCircle\n size={32}\n className=\"mx-auto mb-3 text-muted-foreground\"\n />\n <p className=\"text-sm font-medium text-foreground\">\n Approval not found\n </p>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n The approval with id{\" \"}\n <code className=\"rounded bg-muted px-1\">{id}</code> does not exist.\n </p>\n {inEmbed && (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"mt-4 gap-1.5\"\n onClick={() => postNavigate(appPath(\"/approvals\"))}\n >\n <IconArrowUpRight size={14} />\n View all approvals\n </Button>\n )}\n </div>\n </div>\n );\n }\n\n const isPending = approval.status === \"pending\";\n const beforeValue = parseApprovalValue(approval.beforeValue);\n const afterValue = parseApprovalValue(approval.afterValue);\n\n return (\n <div className=\"flex min-h-screen items-start justify-center bg-background p-6\">\n <div className=\"w-full max-w-2xl space-y-4\">\n <div className=\"rounded-2xl border bg-card p-5\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-xl border bg-muted text-foreground\">\n <IconShieldCheck size={17} />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-sm font-semibold text-foreground\">\n {approval.summary}\n </span>\n <StatusBadge status={approval.status} />\n </div>\n <div className=\"mt-1 text-xs text-muted-foreground\">\n Requested by{\" \"}\n <span className=\"font-medium text-foreground\">\n {approval.requestedBy}\n </span>\n </div>\n </div>\n </div>\n\n <div className=\"mt-4 space-y-2 rounded-xl border bg-muted/30 px-4 py-3 text-xs\">\n <div className=\"flex justify-between gap-4\">\n <span className=\"text-muted-foreground\">Change type</span>\n <span className=\"font-mono font-medium text-foreground\">\n {approval.changeType}\n </span>\n </div>\n <div className=\"flex justify-between gap-4\">\n <span className=\"text-muted-foreground\">Target type</span>\n <span className=\"font-mono font-medium text-foreground\">\n {approval.targetType}\n </span>\n </div>\n {approval.targetId && (\n <div className=\"flex justify-between gap-4\">\n <span className=\"text-muted-foreground\">Target id</span>\n <span className=\"truncate font-mono font-medium text-foreground\">\n {approval.targetId}\n </span>\n </div>\n )}\n {approval.reviewedBy && (\n <div className=\"flex justify-between gap-4\">\n <span className=\"text-muted-foreground\">Reviewed by</span>\n <span className=\"font-medium text-foreground\">\n {approval.reviewedBy}\n </span>\n </div>\n )}\n </div>\n\n {(beforeValue !== null || afterValue !== null) && (\n <div className=\"mt-4 grid gap-3 md:grid-cols-2\">\n <ApprovalValueBlock label=\"Before\" value={beforeValue} />\n <ApprovalValueBlock label=\"After\" value={afterValue} />\n </div>\n )}\n\n {isPending && (\n <div className=\"mt-4 flex gap-2\">\n <Button\n size=\"sm\"\n className=\"flex-1\"\n disabled={approve.isPending || reject.isPending}\n onClick={() => approve.mutate({ id: approval.id })}\n >\n <IconCheck size={14} className=\"mr-1.5\" />\n Approve\n </Button>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"flex-1\"\n disabled={approve.isPending || reject.isPending}\n onClick={() =>\n reject.mutate({\n id: approval.id,\n reason: \"Rejected in dispatch UI\",\n })\n }\n >\n <IconX size={14} className=\"mr-1.5\" />\n Reject\n </Button>\n </div>\n )}\n </div>\n\n {inEmbed && (\n <div className=\"flex justify-end\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"gap-1.5 text-muted-foreground\"\n onClick={() => postNavigate(appPath(\"/approvals\"))}\n >\n <IconArrowUpRight size={14} />\n Open in app\n </Button>\n </div>\n )}\n </div>\n </div>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"approvals.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/approvals.tsx"],"names":[],"mappings":"AAUA,wBAAgB,IAAI;;IAEnB;AAED,MAAM,CAAC,OAAO,UAAU,cAAc,oDA+IrC"}
1
+ {"version":3,"file":"approvals.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/approvals.tsx"],"names":[],"mappings":"AAWA,wBAAgB,IAAI;;IAEnB;AAED,MAAM,CAAC,OAAO,UAAU,cAAc,oDAiKrC"}
@@ -3,6 +3,7 @@ import { useActionMutation, useActionQuery } from "@agent-native/core/client";
3
3
  import { useOrg } from "@agent-native/core/client/org";
4
4
  import { useMemo, useState } from "react";
5
5
  import { toast } from "sonner";
6
+ import { ActionQueryError } from "../../components/action-query-error.js";
6
7
  import { DispatchShell } from "../../components/dispatch-shell.js";
7
8
  import { Button } from "../../components/ui/button.js";
8
9
  import { Input } from "../../components/ui/input.js";
@@ -11,8 +12,10 @@ export function meta() {
11
12
  return [{ title: "Approvals — Dispatch" }];
12
13
  }
13
14
  export default function ApprovalsRoute() {
14
- const { data: settings } = useActionQuery("get-dispatch-settings", {});
15
- const { data: approvals } = useActionQuery("list-dispatch-approvals", {});
15
+ const settingsQuery = useActionQuery("get-dispatch-settings", {});
16
+ const approvalsQuery = useActionQuery("list-dispatch-approvals", {});
17
+ const { data: settings } = settingsQuery;
18
+ const { data: approvals } = approvalsQuery;
16
19
  const { data: org } = useOrg();
17
20
  const hasOrg = !!org?.orgId;
18
21
  const [emails, setEmails] = useState("");
@@ -32,7 +35,7 @@ export default function ApprovalsRoute() {
32
35
  onSuccess: () => toast.success("Change rejected"),
33
36
  onError: (err) => toast.error(String(err)),
34
37
  });
35
- return (_jsx(DispatchShell, { title: "Approvals", description: "Review durable dispatch changes before they apply.", children: _jsxs("div", { className: "grid gap-4 xl:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)]", children: [_jsxs("section", { className: "rounded-2xl border bg-card p-5", children: [_jsx("h2", { className: "text-lg font-semibold text-foreground", children: "Approval policy" }), _jsxs("div", { className: "mt-4 space-y-4", children: [_jsxs("label", { className: "flex items-center justify-between rounded-xl border px-4 py-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: "Require approval for durable changes" }), _jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: hasOrg
38
+ return (_jsx(DispatchShell, { title: "Approvals", description: "Review durable dispatch changes before they apply.", children: _jsxs("div", { className: "grid gap-4 xl:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)]", children: [_jsxs("section", { className: "rounded-2xl border bg-card p-5", children: [_jsx("h2", { className: "text-lg font-semibold text-foreground", children: "Approval policy" }), settingsQuery.isError ? (_jsx(ActionQueryError, { className: "mt-4", error: settingsQuery.error, onRetry: () => void settingsQuery.refetch() })) : (_jsxs("div", { className: "mt-4 space-y-4", children: [_jsxs("label", { className: "flex items-center justify-between rounded-xl border px-4 py-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: "Require approval for durable changes" }), _jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: hasOrg
36
39
  ? "Applies to saved destinations, shared dream proposals, All-app workspace resources, and dispatch settings."
37
40
  : "Requires a team workspace. Set one up on the Team page." })] }), _jsx(Switch, { checked: settings?.enabled || false, disabled: !hasOrg || savePolicy.isPending, onCheckedChange: (checked) => savePolicy.mutate({
38
41
  enabled: checked,
@@ -40,9 +43,9 @@ export default function ApprovalsRoute() {
40
43
  }) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: "Approver emails" }), _jsx(Input, { value: emails, onChange: (event) => setEmails(event.target.value), placeholder: (settings?.approverEmails || []).join(", "), disabled: !hasOrg }), _jsx(Button, { className: "w-full", variant: "outline", disabled: !hasOrg || savePolicy.isPending, onClick: () => savePolicy.mutate({
41
44
  enabled: settings?.enabled || false,
42
45
  approverEmails: approverList,
43
- }), children: "Save approvers" })] })] })] }), _jsxs("section", { className: "rounded-2xl border bg-card p-5", children: [_jsx("h2", { className: "text-lg font-semibold text-foreground", children: "Pending and recent requests" }), _jsxs("div", { className: "mt-4 space-y-3", children: [(approvals || []).map((approval) => (_jsx("div", { className: "rounded-xl border bg-muted/30 px-4 py-3", children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: approval.summary }), _jsxs("div", { className: "mt-1 text-xs text-muted-foreground", children: [approval.status, " \u00B7 requested by ", approval.requestedBy] })] }), approval.status === "pending" && (_jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { size: "sm", onClick: () => approve.mutate({ id: approval.id }), children: "Approve" }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => reject.mutate({
46
+ }), children: "Save approvers" })] })] }))] }), _jsxs("section", { className: "rounded-2xl border bg-card p-5", children: [_jsx("h2", { className: "text-lg font-semibold text-foreground", children: "Pending and recent requests" }), approvalsQuery.isError ? (_jsx(ActionQueryError, { className: "mt-4", error: approvalsQuery.error, onRetry: () => void approvalsQuery.refetch() })) : (_jsxs("div", { className: "mt-4 space-y-3", children: [(approvals || []).map((approval) => (_jsx("div", { className: "rounded-xl border bg-muted/30 px-4 py-3", children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: approval.summary }), _jsxs("div", { className: "mt-1 text-xs text-muted-foreground", children: [approval.status, " \u00B7 requested by ", approval.requestedBy] })] }), approval.status === "pending" && (_jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { size: "sm", onClick: () => approve.mutate({ id: approval.id }), children: "Approve" }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => reject.mutate({
44
47
  id: approval.id,
45
48
  reason: "Rejected in dispatch UI",
46
- }), children: "Reject" })] }))] }) }, approval.id))), (approvals?.length || 0) === 0 && (_jsx("div", { className: "rounded-xl border border-dashed px-4 py-8 text-sm text-muted-foreground", children: "No approval requests yet." }))] })] })] }) }));
49
+ }), children: "Reject" })] }))] }) }, approval.id))), (approvals?.length || 0) === 0 && (_jsx("div", { className: "rounded-xl border border-dashed px-4 py-8 text-sm text-muted-foreground", children: "No approval requests yet." }))] }))] })] }) }));
47
50
  }
48
51
  //# sourceMappingURL=approvals.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"approvals.js","sourceRoot":"","sources":["../../../src/routes/pages/approvals.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useActionMutation, useActionQuery } from \"@agent-native/core/client\";\nimport { useOrg } from \"@agent-native/core/client/org\";\nimport { useMemo, useState } from \"react\";\nimport { toast } from \"sonner\";\n\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport { Button } from \"../../components/ui/button\";\nimport { Input } from \"../../components/ui/input\";\nimport { Switch } from \"../../components/ui/switch\";\n\nexport function meta() {\n return [{ title: \"Approvals — Dispatch\" }];\n}\n\nexport default function ApprovalsRoute() {\n const { data: settings } = useActionQuery(\"get-dispatch-settings\", {});\n const { data: approvals } = useActionQuery(\"list-dispatch-approvals\", {});\n const { data: org } = useOrg();\n const hasOrg = !!org?.orgId;\n const [emails, setEmails] = useState(\"\");\n\n const approverList = useMemo(\n () =>\n emails\n .split(\",\")\n .map((value) => value.trim())\n .filter(Boolean),\n [emails],\n );\n\n const savePolicy = useActionMutation(\"set-dispatch-approval-policy\", {\n onSuccess: () => toast.success(\"Approval policy updated\"),\n onError: (err) => toast.error(String(err)),\n });\n const approve = useActionMutation(\"approve-dispatch-change\", {\n onSuccess: () => toast.success(\"Change approved\"),\n onError: (err) => toast.error(String(err)),\n });\n const reject = useActionMutation(\"reject-dispatch-change\", {\n onSuccess: () => toast.success(\"Change rejected\"),\n onError: (err) => toast.error(String(err)),\n });\n\n return (\n <DispatchShell\n title=\"Approvals\"\n description=\"Review durable dispatch changes before they apply.\"\n >\n <div className=\"grid gap-4 xl:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)]\">\n <section className=\"rounded-2xl border bg-card p-5\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n Approval policy\n </h2>\n <div className=\"mt-4 space-y-4\">\n <label className=\"flex items-center justify-between rounded-xl border px-4 py-3\">\n <div>\n <div className=\"text-sm font-medium text-foreground\">\n Require approval for durable changes\n </div>\n <div className=\"mt-1 text-xs text-muted-foreground\">\n {hasOrg\n ? \"Applies to saved destinations, shared dream proposals, All-app workspace resources, and dispatch settings.\"\n : \"Requires a team workspace. Set one up on the Team page.\"}\n </div>\n </div>\n <Switch\n checked={settings?.enabled || false}\n disabled={!hasOrg || savePolicy.isPending}\n onCheckedChange={(checked) =>\n savePolicy.mutate({\n enabled: checked,\n approverEmails: settings?.approverEmails || approverList,\n })\n }\n />\n </label>\n <div className=\"space-y-2\">\n <div className=\"text-sm font-medium text-foreground\">\n Approver emails\n </div>\n <Input\n value={emails}\n onChange={(event) => setEmails(event.target.value)}\n placeholder={(settings?.approverEmails || []).join(\", \")}\n disabled={!hasOrg}\n />\n <Button\n className=\"w-full\"\n variant=\"outline\"\n disabled={!hasOrg || savePolicy.isPending}\n onClick={() =>\n savePolicy.mutate({\n enabled: settings?.enabled || false,\n approverEmails: approverList,\n })\n }\n >\n Save approvers\n </Button>\n </div>\n </div>\n </section>\n\n <section className=\"rounded-2xl border bg-card p-5\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n Pending and recent requests\n </h2>\n <div className=\"mt-4 space-y-3\">\n {(approvals || []).map((approval: any) => (\n <div\n key={approval.id}\n className=\"rounded-xl border bg-muted/30 px-4 py-3\"\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <div className=\"text-sm font-medium text-foreground\">\n {approval.summary}\n </div>\n <div className=\"mt-1 text-xs text-muted-foreground\">\n {approval.status} · requested by {approval.requestedBy}\n </div>\n </div>\n {approval.status === \"pending\" && (\n <div className=\"flex gap-2\">\n <Button\n size=\"sm\"\n onClick={() => approve.mutate({ id: approval.id })}\n >\n Approve\n </Button>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() =>\n reject.mutate({\n id: approval.id,\n reason: \"Rejected in dispatch UI\",\n })\n }\n >\n Reject\n </Button>\n </div>\n )}\n </div>\n </div>\n ))}\n {(approvals?.length || 0) === 0 && (\n <div className=\"rounded-xl border border-dashed px-4 py-8 text-sm text-muted-foreground\">\n No approval requests yet.\n </div>\n )}\n </div>\n </section>\n </div>\n </DispatchShell>\n );\n}\n"]}
1
+ {"version":3,"file":"approvals.js","sourceRoot":"","sources":["../../../src/routes/pages/approvals.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useActionMutation, useActionQuery } from \"@agent-native/core/client\";\nimport { useOrg } from \"@agent-native/core/client/org\";\nimport { useMemo, useState } from \"react\";\nimport { toast } from \"sonner\";\n\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport { Button } from \"../../components/ui/button\";\nimport { Input } from \"../../components/ui/input\";\nimport { Switch } from \"../../components/ui/switch\";\n\nexport function meta() {\n return [{ title: \"Approvals — Dispatch\" }];\n}\n\nexport default function ApprovalsRoute() {\n const settingsQuery = useActionQuery(\"get-dispatch-settings\", {});\n const approvalsQuery = useActionQuery(\"list-dispatch-approvals\", {});\n const { data: settings } = settingsQuery;\n const { data: approvals } = approvalsQuery;\n const { data: org } = useOrg();\n const hasOrg = !!org?.orgId;\n const [emails, setEmails] = useState(\"\");\n\n const approverList = useMemo(\n () =>\n emails\n .split(\",\")\n .map((value) => value.trim())\n .filter(Boolean),\n [emails],\n );\n\n const savePolicy = useActionMutation(\"set-dispatch-approval-policy\", {\n onSuccess: () => toast.success(\"Approval policy updated\"),\n onError: (err) => toast.error(String(err)),\n });\n const approve = useActionMutation(\"approve-dispatch-change\", {\n onSuccess: () => toast.success(\"Change approved\"),\n onError: (err) => toast.error(String(err)),\n });\n const reject = useActionMutation(\"reject-dispatch-change\", {\n onSuccess: () => toast.success(\"Change rejected\"),\n onError: (err) => toast.error(String(err)),\n });\n\n return (\n <DispatchShell\n title=\"Approvals\"\n description=\"Review durable dispatch changes before they apply.\"\n >\n <div className=\"grid gap-4 xl:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)]\">\n <section className=\"rounded-2xl border bg-card p-5\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n Approval policy\n </h2>\n {settingsQuery.isError ? (\n <ActionQueryError\n className=\"mt-4\"\n error={settingsQuery.error}\n onRetry={() => void settingsQuery.refetch()}\n />\n ) : (\n <div className=\"mt-4 space-y-4\">\n <label className=\"flex items-center justify-between rounded-xl border px-4 py-3\">\n <div>\n <div className=\"text-sm font-medium text-foreground\">\n Require approval for durable changes\n </div>\n <div className=\"mt-1 text-xs text-muted-foreground\">\n {hasOrg\n ? \"Applies to saved destinations, shared dream proposals, All-app workspace resources, and dispatch settings.\"\n : \"Requires a team workspace. Set one up on the Team page.\"}\n </div>\n </div>\n <Switch\n checked={settings?.enabled || false}\n disabled={!hasOrg || savePolicy.isPending}\n onCheckedChange={(checked) =>\n savePolicy.mutate({\n enabled: checked,\n approverEmails: settings?.approverEmails || approverList,\n })\n }\n />\n </label>\n <div className=\"space-y-2\">\n <div className=\"text-sm font-medium text-foreground\">\n Approver emails\n </div>\n <Input\n value={emails}\n onChange={(event) => setEmails(event.target.value)}\n placeholder={(settings?.approverEmails || []).join(\", \")}\n disabled={!hasOrg}\n />\n <Button\n className=\"w-full\"\n variant=\"outline\"\n disabled={!hasOrg || savePolicy.isPending}\n onClick={() =>\n savePolicy.mutate({\n enabled: settings?.enabled || false,\n approverEmails: approverList,\n })\n }\n >\n Save approvers\n </Button>\n </div>\n </div>\n )}\n </section>\n\n <section className=\"rounded-2xl border bg-card p-5\">\n <h2 className=\"text-lg font-semibold text-foreground\">\n Pending and recent requests\n </h2>\n {approvalsQuery.isError ? (\n <ActionQueryError\n className=\"mt-4\"\n error={approvalsQuery.error}\n onRetry={() => void approvalsQuery.refetch()}\n />\n ) : (\n <div className=\"mt-4 space-y-3\">\n {(approvals || []).map((approval: any) => (\n <div\n key={approval.id}\n className=\"rounded-xl border bg-muted/30 px-4 py-3\"\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <div className=\"text-sm font-medium text-foreground\">\n {approval.summary}\n </div>\n <div className=\"mt-1 text-xs text-muted-foreground\">\n {approval.status} · requested by {approval.requestedBy}\n </div>\n </div>\n {approval.status === \"pending\" && (\n <div className=\"flex gap-2\">\n <Button\n size=\"sm\"\n onClick={() => approve.mutate({ id: approval.id })}\n >\n Approve\n </Button>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() =>\n reject.mutate({\n id: approval.id,\n reason: \"Rejected in dispatch UI\",\n })\n }\n >\n Reject\n </Button>\n </div>\n )}\n </div>\n </div>\n ))}\n {(approvals?.length || 0) === 0 && (\n <div className=\"rounded-xl border border-dashed px-4 py-8 text-sm text-muted-foreground\">\n No approval requests yet.\n </div>\n )}\n </div>\n )}\n </section>\n </div>\n </DispatchShell>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"apps.$appId.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/apps.$appId.tsx"],"names":[],"mappings":"AAkBA,wBAAgB,IAAI;;IAEnB;AAED,MAAM,CAAC,OAAO,UAAU,iBAAiB,oDAqGxC"}
1
+ {"version":3,"file":"apps.$appId.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/apps.$appId.tsx"],"names":[],"mappings":"AAmBA,wBAAgB,IAAI;;IAEnB;AAED,MAAM,CAAC,OAAO,UAAU,iBAAiB,oDA2GxC"}
@@ -3,6 +3,7 @@ import { useActionQuery, useT } from "@agent-native/core/client";
3
3
  import { IconArrowLeft, IconArrowUpRight, IconClockHour4, } from "@tabler/icons-react";
4
4
  import { useEffect, useMemo } from "react";
5
5
  import { Link, useParams } from "react-router";
6
+ import { ActionQueryError } from "../../components/action-query-error.js";
6
7
  import { DispatchShell } from "../../components/dispatch-shell.js";
7
8
  import { Badge } from "../../components/ui/badge.js";
8
9
  import { Button } from "../../components/ui/button.js";
@@ -14,9 +15,10 @@ export function meta() {
14
15
  export default function WorkspaceAppRoute() {
15
16
  const t = useT();
16
17
  const { appId } = useParams();
17
- const { data: apps = [], isLoading } = useActionQuery("list-workspace-apps", {
18
+ const appsQuery = useActionQuery("list-workspace-apps", {
18
19
  includeAgentCards: false,
19
20
  });
21
+ const { data: apps = [], isLoading } = appsQuery;
20
22
  const app = useMemo(() => apps.find((item) => item.id === appId) ?? null, [appId, apps]);
21
23
  const href = app ? workspaceAppHref(app) : null;
22
24
  useEffect(() => {
@@ -24,6 +26,6 @@ export default function WorkspaceAppRoute() {
24
26
  return;
25
27
  window.location.assign(href);
26
28
  }, [app, href]);
27
- return (_jsx(DispatchShell, { title: app?.name || t("dispatch.pages.workspaceAppFallback"), description: t("dispatch.pages.workspaceAppDescription"), children: _jsxs("div", { className: "max-w-2xl rounded-lg border bg-card p-5", children: [_jsx(Button, { asChild: true, size: "sm", variant: "ghost", className: "-ml-2 mb-4", children: _jsxs(Link, { to: "/apps", children: [_jsx(IconArrowLeft, { size: 15, className: "mr-1.5" }), t("dispatch.nav.apps")] }) }), isLoading && !app ? (_jsxs("div", { className: "space-y-3", children: [_jsx(Skeleton, { className: "h-5 w-48" }), _jsx(Skeleton, { className: "h-4 w-full" }), _jsx(Skeleton, { className: "h-4 w-2/3" })] })) : !app ? (_jsxs("div", { className: "space-y-3", children: [_jsx("h2", { className: "text-base font-semibold text-foreground", children: t("dispatch.pages.appNotFound") }), _jsx("p", { className: "text-sm text-muted-foreground", children: t("dispatch.pages.pageNotFoundDescription") })] })) : app.status === "pending" ? (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("h2", { className: "text-base font-semibold text-foreground", children: app.name }), _jsxs(Badge, { variant: "outline", className: "gap-1 border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300", children: [_jsx(IconClockHour4, { size: 12 }), t("dispatch.pages.building")] })] }), _jsxs("p", { className: "text-sm text-muted-foreground", children: [t("dispatch.pages.appBuildingPrefix"), " ", _jsx("span", { className: "font-mono text-foreground", children: app.path }), " ", t("dispatch.pages.appBuildingSuffix")] }), app.branchName ? (_jsx("p", { className: "text-xs text-muted-foreground", children: t("dispatch.pages.branch", { branch: app.branchName }) })) : null, app.builderUrl ? (_jsx(Button, { asChild: true, children: _jsxs("a", { href: app.builderUrl, target: "_blank", rel: "noreferrer", children: [t("dispatch.pages.openBuilderBranch"), _jsx(IconArrowUpRight, { size: 15, className: "ml-1.5" })] }) })) : null] })) : (_jsxs("div", { className: "space-y-3", children: [_jsx("h2", { className: "text-base font-semibold text-foreground", children: t("dispatch.pages.openingApp", { name: app.name }) }), _jsxs("p", { className: "text-sm text-muted-foreground", children: [t("dispatch.pages.redirectingTo"), " ", _jsx("span", { className: "font-mono text-foreground", children: app.path }), "."] }), href ? (_jsx(Button, { asChild: true, children: _jsxs("a", { href: href, children: [t("dispatch.pages.openApp"), _jsx(IconArrowUpRight, { size: 15, className: "ml-1.5" })] }) })) : null] }))] }) }));
29
+ return (_jsx(DispatchShell, { title: app?.name || t("dispatch.pages.workspaceAppFallback"), description: t("dispatch.pages.workspaceAppDescription"), children: _jsxs("div", { className: "max-w-2xl rounded-lg border bg-card p-5", children: [_jsx(Button, { asChild: true, size: "sm", variant: "ghost", className: "-ml-2 mb-4", children: _jsxs(Link, { to: "/apps", children: [_jsx(IconArrowLeft, { size: 15, className: "mr-1.5" }), t("dispatch.nav.apps")] }) }), appsQuery.isError ? (_jsx(ActionQueryError, { error: appsQuery.error, onRetry: () => void appsQuery.refetch() })) : isLoading && !app ? (_jsxs("div", { className: "space-y-3", children: [_jsx(Skeleton, { className: "h-5 w-48" }), _jsx(Skeleton, { className: "h-4 w-full" }), _jsx(Skeleton, { className: "h-4 w-2/3" })] })) : !app ? (_jsxs("div", { className: "space-y-3", children: [_jsx("h2", { className: "text-base font-semibold text-foreground", children: t("dispatch.pages.appNotFound") }), _jsx("p", { className: "text-sm text-muted-foreground", children: t("dispatch.pages.pageNotFoundDescription") })] })) : app.status === "pending" ? (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("h2", { className: "text-base font-semibold text-foreground", children: app.name }), _jsxs(Badge, { variant: "outline", className: "gap-1 border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300", children: [_jsx(IconClockHour4, { size: 12 }), t("dispatch.pages.building")] })] }), _jsxs("p", { className: "text-sm text-muted-foreground", children: [t("dispatch.pages.appBuildingPrefix"), " ", _jsx("span", { className: "font-mono text-foreground", children: app.path }), " ", t("dispatch.pages.appBuildingSuffix")] }), app.branchName ? (_jsx("p", { className: "text-xs text-muted-foreground", children: t("dispatch.pages.branch", { branch: app.branchName }) })) : null, app.builderUrl ? (_jsx(Button, { asChild: true, children: _jsxs("a", { href: app.builderUrl, target: "_blank", rel: "noreferrer", children: [t("dispatch.pages.openBuilderBranch"), _jsx(IconArrowUpRight, { size: 15, className: "ml-1.5" })] }) })) : null] })) : (_jsxs("div", { className: "space-y-3", children: [_jsx("h2", { className: "text-base font-semibold text-foreground", children: t("dispatch.pages.openingApp", { name: app.name }) }), _jsxs("p", { className: "text-sm text-muted-foreground", children: [t("dispatch.pages.redirectingTo"), " ", _jsx("span", { className: "font-mono text-foreground", children: app.path }), "."] }), href ? (_jsx(Button, { asChild: true, children: _jsxs("a", { href: href, children: [t("dispatch.pages.openApp"), _jsx(IconArrowUpRight, { size: 15, className: "ml-1.5" })] }) })) : null] }))] }) }));
28
30
  }
29
31
  //# sourceMappingURL=apps.$appId.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"apps.$appId.js","sourceRoot":"","sources":["../../../src/routes/pages/apps.$appId.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useActionQuery, useT } from \"@agent-native/core/client\";\nimport {\n IconArrowLeft,\n IconArrowUpRight,\n IconClockHour4,\n} from \"@tabler/icons-react\";\nimport { useEffect, useMemo } from \"react\";\nimport { Link, useParams } from \"react-router\";\n\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { Skeleton } from \"../../components/ui/skeleton\";\nimport {\n workspaceAppHref,\n type WorkspaceAppSummary,\n} from \"../../lib/workspace-apps\";\n\nexport function meta() {\n return [{ title: \"Workspace app - Dispatch\" }];\n}\n\nexport default function WorkspaceAppRoute() {\n const t = useT();\n const { appId } = useParams();\n const { data: apps = [], isLoading } = useActionQuery(\"list-workspace-apps\", {\n includeAgentCards: false,\n });\n const app = useMemo(\n () =>\n (apps as WorkspaceAppSummary[]).find((item) => item.id === appId) ?? null,\n [appId, apps],\n );\n const href = app ? workspaceAppHref(app) : null;\n\n useEffect(() => {\n if (!app || app.status === \"pending\" || !href) return;\n window.location.assign(href);\n }, [app, href]);\n\n return (\n <DispatchShell\n title={app?.name || t(\"dispatch.pages.workspaceAppFallback\")}\n description={t(\"dispatch.pages.workspaceAppDescription\")}\n >\n <div className=\"max-w-2xl rounded-lg border bg-card p-5\">\n <Button asChild size=\"sm\" variant=\"ghost\" className=\"-ml-2 mb-4\">\n <Link to=\"/apps\">\n <IconArrowLeft size={15} className=\"mr-1.5\" />\n {t(\"dispatch.nav.apps\")}\n </Link>\n </Button>\n\n {isLoading && !app ? (\n <div className=\"space-y-3\">\n <Skeleton className=\"h-5 w-48\" />\n <Skeleton className=\"h-4 w-full\" />\n <Skeleton className=\"h-4 w-2/3\" />\n </div>\n ) : !app ? (\n <div className=\"space-y-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(\"dispatch.pages.appNotFound\")}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"dispatch.pages.pageNotFoundDescription\")}\n </p>\n </div>\n ) : app.status === \"pending\" ? (\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {app.name}\n </h2>\n <Badge\n variant=\"outline\"\n className=\"gap-1 border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300\"\n >\n <IconClockHour4 size={12} />\n {t(\"dispatch.pages.building\")}\n </Badge>\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"dispatch.pages.appBuildingPrefix\")}{\" \"}\n <span className=\"font-mono text-foreground\">{app.path}</span>{\" \"}\n {t(\"dispatch.pages.appBuildingSuffix\")}\n </p>\n {app.branchName ? (\n <p className=\"text-xs text-muted-foreground\">\n {t(\"dispatch.pages.branch\", { branch: app.branchName })}\n </p>\n ) : null}\n {app.builderUrl ? (\n <Button asChild>\n <a href={app.builderUrl} target=\"_blank\" rel=\"noreferrer\">\n {t(\"dispatch.pages.openBuilderBranch\")}\n <IconArrowUpRight size={15} className=\"ml-1.5\" />\n </a>\n </Button>\n ) : null}\n </div>\n ) : (\n <div className=\"space-y-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(\"dispatch.pages.openingApp\", { name: app.name })}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"dispatch.pages.redirectingTo\")}{\" \"}\n <span className=\"font-mono text-foreground\">{app.path}</span>.\n </p>\n {href ? (\n <Button asChild>\n <a href={href}>\n {t(\"dispatch.pages.openApp\")}\n <IconArrowUpRight size={15} className=\"ml-1.5\" />\n </a>\n </Button>\n ) : null}\n </div>\n )}\n </div>\n </DispatchShell>\n );\n}\n"]}
1
+ {"version":3,"file":"apps.$appId.js","sourceRoot":"","sources":["../../../src/routes/pages/apps.$appId.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useActionQuery, useT } from \"@agent-native/core/client\";\nimport {\n IconArrowLeft,\n IconArrowUpRight,\n IconClockHour4,\n} from \"@tabler/icons-react\";\nimport { useEffect, useMemo } from \"react\";\nimport { Link, useParams } from \"react-router\";\n\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { Skeleton } from \"../../components/ui/skeleton\";\nimport {\n workspaceAppHref,\n type WorkspaceAppSummary,\n} from \"../../lib/workspace-apps\";\n\nexport function meta() {\n return [{ title: \"Workspace app - Dispatch\" }];\n}\n\nexport default function WorkspaceAppRoute() {\n const t = useT();\n const { appId } = useParams();\n const appsQuery = useActionQuery(\"list-workspace-apps\", {\n includeAgentCards: false,\n });\n const { data: apps = [], isLoading } = appsQuery;\n const app = useMemo(\n () =>\n (apps as WorkspaceAppSummary[]).find((item) => item.id === appId) ?? null,\n [appId, apps],\n );\n const href = app ? workspaceAppHref(app) : null;\n\n useEffect(() => {\n if (!app || app.status === \"pending\" || !href) return;\n window.location.assign(href);\n }, [app, href]);\n\n return (\n <DispatchShell\n title={app?.name || t(\"dispatch.pages.workspaceAppFallback\")}\n description={t(\"dispatch.pages.workspaceAppDescription\")}\n >\n <div className=\"max-w-2xl rounded-lg border bg-card p-5\">\n <Button asChild size=\"sm\" variant=\"ghost\" className=\"-ml-2 mb-4\">\n <Link to=\"/apps\">\n <IconArrowLeft size={15} className=\"mr-1.5\" />\n {t(\"dispatch.nav.apps\")}\n </Link>\n </Button>\n\n {appsQuery.isError ? (\n <ActionQueryError\n error={appsQuery.error}\n onRetry={() => void appsQuery.refetch()}\n />\n ) : isLoading && !app ? (\n <div className=\"space-y-3\">\n <Skeleton className=\"h-5 w-48\" />\n <Skeleton className=\"h-4 w-full\" />\n <Skeleton className=\"h-4 w-2/3\" />\n </div>\n ) : !app ? (\n <div className=\"space-y-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(\"dispatch.pages.appNotFound\")}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"dispatch.pages.pageNotFoundDescription\")}\n </p>\n </div>\n ) : app.status === \"pending\" ? (\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {app.name}\n </h2>\n <Badge\n variant=\"outline\"\n className=\"gap-1 border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300\"\n >\n <IconClockHour4 size={12} />\n {t(\"dispatch.pages.building\")}\n </Badge>\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"dispatch.pages.appBuildingPrefix\")}{\" \"}\n <span className=\"font-mono text-foreground\">{app.path}</span>{\" \"}\n {t(\"dispatch.pages.appBuildingSuffix\")}\n </p>\n {app.branchName ? (\n <p className=\"text-xs text-muted-foreground\">\n {t(\"dispatch.pages.branch\", { branch: app.branchName })}\n </p>\n ) : null}\n {app.builderUrl ? (\n <Button asChild>\n <a href={app.builderUrl} target=\"_blank\" rel=\"noreferrer\">\n {t(\"dispatch.pages.openBuilderBranch\")}\n <IconArrowUpRight size={15} className=\"ml-1.5\" />\n </a>\n </Button>\n ) : null}\n </div>\n ) : (\n <div className=\"space-y-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(\"dispatch.pages.openingApp\", { name: app.name })}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"dispatch.pages.redirectingTo\")}{\" \"}\n <span className=\"font-mono text-foreground\">{app.path}</span>.\n </p>\n {href ? (\n <Button asChild>\n <a href={href}>\n {t(\"dispatch.pages.openApp\")}\n <IconArrowUpRight size={15} className=\"ml-1.5\" />\n </a>\n </Button>\n ) : null}\n </div>\n )}\n </div>\n </DispatchShell>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/apps.tsx"],"names":[],"mappings":"AAwCA,wBAAgB,IAAI;;IAEnB;AA+BD,MAAM,CAAC,OAAO,UAAU,SAAS,oDAmNhC"}
1
+ {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/apps.tsx"],"names":[],"mappings":"AAyCA,wBAAgB,IAAI;;IAEnB;AA+BD,MAAM,CAAC,OAAO,UAAU,SAAS,oDA+NhC"}
@@ -3,6 +3,7 @@ import { useActionMutation, useActionQuery, useT, } from "@agent-native/core/cli
3
3
  import { IconApps, IconBrain, IconBrush, IconCalendarMonth, IconChartBar, IconChevronDown, IconClipboardList, IconEyeOff, IconFileText, IconLoader2, IconMail, IconPhoto, IconPlus, IconPresentation, IconScreenShare, IconSparkles, IconStack3, } from "@tabler/icons-react";
4
4
  import { useState } from "react";
5
5
  import { toast } from "sonner";
6
+ import { ActionQueryError } from "../../components/action-query-error.js";
6
7
  import { CreateAppPopover } from "../../components/create-app-popover.js";
7
8
  import { DispatchShell } from "../../components/dispatch-shell.js";
8
9
  import { Button } from "../../components/ui/button.js";
@@ -29,9 +30,14 @@ export default function AppsRoute() {
29
30
  const t = useT();
30
31
  const [showHidden, setShowHidden] = useState(false);
31
32
  const [templatesOpen, setTemplatesOpen] = useState(false);
32
- const { data: apps = [], isLoading: appsLoading } = useActionQuery("list-workspace-apps", { includeAgentCards: false, includeArchived: true });
33
+ const appsQuery = useActionQuery("list-workspace-apps", {
34
+ includeAgentCards: false,
35
+ includeArchived: true,
36
+ });
37
+ const { data: apps = [], isLoading: appsLoading } = appsQuery;
33
38
  const { data: workspace } = useActionQuery("get-workspace-info", {}, { staleTime: 60_000 });
34
- const { data: templates = [], isLoading: templatesLoading } = useActionQuery("list-available-workspace-templates", {}, { refetchInterval: 5_000 });
39
+ const templatesQuery = useActionQuery("list-available-workspace-templates", {}, { refetchInterval: 5_000 });
40
+ const { data: templates = [], isLoading: templatesLoading } = templatesQuery;
35
41
  const ws = workspace;
36
42
  const workspaceLabel = ws?.displayName ?? ws?.name ?? null;
37
43
  const allApps = apps.filter((app) => !app.isDispatch);
@@ -53,7 +59,7 @@ export default function AppsRoute() {
53
59
  ? ` · ${t("dispatch.pages.hiddenCount", {
54
60
  count: archivedApps.length,
55
61
  })}`
56
- : ""] })] })] }), visibleApps.length > 0 ? (_jsx(CreateAppPopover, { align: "end", trigger: _jsxs(Button, { size: "sm", children: [_jsx(IconPlus, { size: 15, className: "mr-1.5" }), t("dispatch.pages.createApp")] }) })) : null] }), showAppSkeletons ? (_jsx(AppsSkeletonGrid, {})) : visibleApps.length > 0 ? (_jsx("div", { className: "grid auto-rows-fr gap-3 md:grid-cols-2 xl:grid-cols-3", children: visibleApps.map((app) => (_jsx(WorkspaceAppCard, { app: app, className: "h-full" }, app.id))) })) : (_jsx(EmptyAppsState, {}))] }), typedTemplates.length > 0 || templatesLoading ? (_jsx(Collapsible, { open: templatesOpen, onOpenChange: setTemplatesOpen, children: _jsxs("section", { className: "space-y-3", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 border-t pt-4", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(IconStack3, { size: 16, className: "shrink-0 text-muted-foreground" }), _jsxs("div", { className: "min-w-0", children: [_jsx("h2", { className: "text-sm font-semibold text-foreground", children: t("dispatch.pages.templates") }), _jsx("p", { className: "text-xs text-muted-foreground", children: templatesLoading
62
+ : ""] })] })] }), visibleApps.length > 0 ? (_jsx(CreateAppPopover, { align: "end", trigger: _jsxs(Button, { size: "sm", children: [_jsx(IconPlus, { size: 15, className: "mr-1.5" }), t("dispatch.pages.createApp")] }) })) : null] }), appsQuery.isError ? (_jsx(ActionQueryError, { error: appsQuery.error, onRetry: () => void appsQuery.refetch() })) : showAppSkeletons ? (_jsx(AppsSkeletonGrid, {})) : visibleApps.length > 0 ? (_jsx("div", { className: "grid auto-rows-fr gap-3 md:grid-cols-2 xl:grid-cols-3", children: visibleApps.map((app) => (_jsx(WorkspaceAppCard, { app: app, className: "h-full" }, app.id))) })) : (_jsx(EmptyAppsState, {}))] }), templatesQuery.isError ? (_jsx(ActionQueryError, { error: templatesQuery.error, onRetry: () => void templatesQuery.refetch() })) : typedTemplates.length > 0 || templatesLoading ? (_jsx(Collapsible, { open: templatesOpen, onOpenChange: setTemplatesOpen, children: _jsxs("section", { className: "space-y-3", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 border-t pt-4", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(IconStack3, { size: 16, className: "shrink-0 text-muted-foreground" }), _jsxs("div", { className: "min-w-0", children: [_jsx("h2", { className: "text-sm font-semibold text-foreground", children: t("dispatch.pages.templates") }), _jsx("p", { className: "text-xs text-muted-foreground", children: templatesLoading
57
63
  ? t("dispatch.pages.checkingTemplates")
58
64
  : t("dispatch.pages.templatesAvailable", {
59
65
  count: typedTemplates.length,