@agent-native/dispatch 0.12.1 → 0.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/dispatch-shell.d.ts.map +1 -1
- package/dist/components/dispatch-shell.js +3 -1
- package/dist/components/dispatch-shell.js.map +1 -1
- package/dist/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +39 -20
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/routes/pages/$appId.d.ts.map +1 -1
- package/dist/routes/pages/$appId.js +3 -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 +14 -8
- 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 +3 -2
- 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 +29 -11
- package/dist/routes/pages/apps.js.map +1 -1
- package/dist/routes/pages/destinations.d.ts.map +1 -1
- package/dist/routes/pages/destinations.js +18 -12
- package/dist/routes/pages/destinations.js.map +1 -1
- package/dist/routes/pages/metrics.d.ts.map +1 -1
- package/dist/routes/pages/metrics.js +8 -5
- package/dist/routes/pages/metrics.js.map +1 -1
- package/dist/routes/pages/new-app.d.ts.map +1 -1
- package/dist/routes/pages/new-app.js +3 -2
- package/dist/routes/pages/new-app.js.map +1 -1
- package/package.json +2 -2
- package/src/components/dispatch-shell.tsx +3 -1
- package/src/components/layout/Layout.tsx +63 -28
- package/src/routes/pages/$appId.tsx +15 -12
- package/src/routes/pages/agents.tsx +21 -14
- package/src/routes/pages/apps.$appId.tsx +15 -14
- package/src/routes/pages/apps.tsx +41 -20
- package/src/routes/pages/destinations.tsx +35 -24
- package/src/routes/pages/metrics.tsx +13 -10
- package/src/routes/pages/new-app.tsx +4 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo, useState } from "react";
|
|
3
|
-
import { agentNativePath, useActionMutation, useActionQuery, } from "@agent-native/core/client";
|
|
3
|
+
import { agentNativePath, useActionMutation, useActionQuery, useT, } from "@agent-native/core/client";
|
|
4
4
|
import { AgentsPanel } from "../../components/agents-panel.js";
|
|
5
5
|
import { DispatchShell } from "../../components/dispatch-shell.js";
|
|
6
6
|
import { Button } from "../../components/ui/button.js";
|
|
@@ -18,12 +18,13 @@ function dispatchMcpUrl() {
|
|
|
18
18
|
return new URL(path, window.location.origin).href;
|
|
19
19
|
}
|
|
20
20
|
function DispatchMcpAccessPanel() {
|
|
21
|
+
const t = useT();
|
|
21
22
|
const { data, isLoading } = useActionQuery("list-mcp-app-access", {});
|
|
22
23
|
const [optimistic, setOptimistic] = useState(null);
|
|
23
24
|
const saveAccess = useActionMutation("set-mcp-app-access", {
|
|
24
25
|
onSuccess: () => {
|
|
25
26
|
setOptimistic(null);
|
|
26
|
-
toast.success("
|
|
27
|
+
toast.success(t("dispatch.pages.mcpAccessUpdated"));
|
|
27
28
|
},
|
|
28
29
|
onError: (error) => {
|
|
29
30
|
setOptimistic(null);
|
|
@@ -44,7 +45,7 @@ function DispatchMcpAccessPanel() {
|
|
|
44
45
|
const mcpUrl = dispatchMcpUrl();
|
|
45
46
|
function persist(next) {
|
|
46
47
|
if (next.mode === "selected-apps" && next.selectedAppIds.length === 0) {
|
|
47
|
-
toast.error("
|
|
48
|
+
toast.error(t("dispatch.pages.selectAppForMcp"));
|
|
48
49
|
return;
|
|
49
50
|
}
|
|
50
51
|
setOptimistic(next);
|
|
@@ -59,25 +60,30 @@ function DispatchMcpAccessPanel() {
|
|
|
59
60
|
async function copyUrl() {
|
|
60
61
|
try {
|
|
61
62
|
await navigator.clipboard.writeText(mcpUrl);
|
|
62
|
-
toast.success("
|
|
63
|
+
toast.success(t("dispatch.pages.mcpUrlCopied"));
|
|
63
64
|
}
|
|
64
65
|
catch {
|
|
65
|
-
toast.error("
|
|
66
|
+
toast.error(t("dispatch.pages.mcpUrlCopyFailed"));
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
|
-
return (_jsxs("section", { className: "rounded-2xl border bg-card p-5", children: [_jsxs("div", { className: "flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [_jsx(IconPlugConnected, { size: 16 }), "
|
|
69
|
+
return (_jsxs("section", { className: "rounded-2xl border bg-card p-5", children: [_jsxs("div", { className: "flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [_jsx(IconPlugConnected, { size: 16 }), t("dispatch.pages.unifiedMcpGateway")] }), _jsxs("div", { className: "mt-1 max-w-2xl text-sm text-muted-foreground", children: [t("dispatch.pages.unifiedMcpGatewayDescription"), " ", _jsx("code", { children: "list_apps" }), ", ", _jsx("code", { children: "ask_app" }), ", and", " ", _jsx("code", { children: "open_app" }), "."] })] }), _jsxs("div", { className: "flex items-center gap-3 rounded-xl border px-3 py-2", children: [_jsxs("div", { children: [_jsx("div", { className: "text-xs font-medium text-foreground", children: access.mode === "all-apps"
|
|
70
|
+
? t("dispatch.pages.allApps")
|
|
71
|
+
: t("dispatch.pages.selectedApps") }), _jsx("div", { className: "text-xs text-muted-foreground", children: isLoading
|
|
72
|
+
? t("dispatch.pages.loading")
|
|
73
|
+
: t("dispatch.pages.grantedCount", { count: grantedCount }) })] }), _jsx(Switch, { checked: access.mode === "all-apps", disabled: saveAccess.isPending || apps.length === 0, onCheckedChange: (checked) => persist({
|
|
69
74
|
mode: checked ? "all-apps" : "selected-apps",
|
|
70
75
|
selectedAppIds: checked
|
|
71
76
|
? access.selectedAppIds
|
|
72
77
|
: apps.map((app) => app.id),
|
|
73
|
-
}), "aria-label": "
|
|
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) => {
|
|
74
79
|
const isSelected = selected.has(app.id);
|
|
75
80
|
return (_jsxs("button", { type: "button", disabled: saveAccess.isPending &&
|
|
76
81
|
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));
|
|
77
82
|
}) })) : null] }));
|
|
78
83
|
}
|
|
79
84
|
export default function AgentsRoute() {
|
|
85
|
+
const t = useT();
|
|
80
86
|
const { data, refetch } = useActionQuery("list-connected-agents", {});
|
|
81
|
-
return (_jsx(DispatchShell, { title: "
|
|
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 })] }) }));
|
|
82
88
|
}
|
|
83
89
|
//# 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 { useMemo, useState } from \"react\";\nimport {\n agentNativePath,\n useActionMutation,\n useActionQuery,\n} from \"@agent-native/core/client\";\nimport { AgentsPanel, type ConnectedAgent } 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\";\nimport { IconCheck, IconCopy, IconPlugConnected } from \"@tabler/icons-react\";\nimport { toast } from \"sonner\";\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 { 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(\"MCP app access updated\");\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(\"Select at least one app, or expose all apps.\");\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(\"MCP URL copied\");\n } catch {\n toast.error(\"Could not copy MCP URL\");\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 Unified MCP gateway\n </div>\n <div className=\"mt-1 max-w-2xl text-sm text-muted-foreground\">\n Connect external agents to Dispatch once, then route to granted\n workspace apps through <code>list_apps</code>, <code>ask_app</code>,\n and <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\" ? \"All apps\" : \"Selected apps\"}\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {isLoading ? \"Loading\" : `${grantedCount} granted`}\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=\"Expose all apps through Dispatch MCP\"\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 Copy URL\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 { data, refetch } = useActionQuery(\"list-connected-agents\", {});\n\n return (\n <DispatchShell\n title=\"Agents\"\n description=\"Dispatch can delegate to the built-in app suite over A2A by default. Add extra agents here only if you want to route work to apps outside that built-in set.\"\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":";AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,IAAI,GACL,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,WAAW,EAAuB,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAE/B,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;AAC1C,CAAC;AAkBD,SAAS,cAAc;IACrB,MAAM,IAAI,GAAG,eAAe,CAAC,oBAAoB,CAAC,CAAC;IACnD,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IAC/C,OAAO,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;AACpD,CAAC;AAED,SAAS,sBAAsB;IAC7B,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IACjB,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,cAAc,CAAC,qBAAqB,EAAE,EAAE,CAAC,CAAC;IACtE,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAwB,IAAI,CAAC,CAAC;IAC1E,MAAM,UAAU,GAAG,iBAAiB,CAAC,oBAAoB,EAAE;QACzD,SAAS,EAAE,GAAG,EAAE;YACd,aAAa,CAAC,IAAI,CAAC,CAAC;YACpB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACjB,aAAa,CAAC,IAAI,CAAC,CAAC;YACpB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,CAAE,IAA8C,EAAE,IAAI;QACjE,EAAE,CAAmB,CAAC;IACxB,MAAM,MAAM,GACV,UAAU;QACT;YACC,IAAI,EAAE,CAAE,IAA6C,EAAE,IAAI;gBACzD,UAAU,CAAkB;YAC9B,cAAc,EACX,IAAkD,EAAE,cAAc;gBACnE,EAAE;SACqB,CAAC;IAC9B,MAAM,QAAQ,GAAG,OAAO,CACtB,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,EACpC,CAAC,MAAM,CAAC,cAAc,CAAC,CACxB,CAAC;IACF,MAAM,YAAY,GAChB,MAAM,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC;IAC1E,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;IAEhC,SAAS,OAAO,CAAC,IAAoB;QACnC,IAAI,IAAI,CAAC,IAAI,KAAK,eAAe,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC;YACjD,OAAO;QACT,CAAC;QACD,aAAa,CAAC,IAAI,CAAC,CAAC;QACpB,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,SAAS,SAAS,CAAC,KAAa;QAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;YAC9B,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,KAAK,CAAC;YACpD,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;QACtC,OAAO,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,UAAU,OAAO;QACpB,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAC5C,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC;QAClD,CAAC;QAAC,MAAM,CAAC;YACP,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,OAAO,CACL,mBAAS,SAAS,EAAC,gCAAgC,aACjD,eAAK,SAAS,EAAC,mEAAmE,aAChF,eAAK,SAAS,EAAC,SAAS,aACtB,eAAK,SAAS,EAAC,6DAA6D,aAC1E,KAAC,iBAAiB,IAAC,IAAI,EAAE,EAAE,GAAI,EAC9B,CAAC,CAAC,kCAAkC,CAAC,IAClC,EACN,eAAK,SAAS,EAAC,8CAA8C,aAC1D,CAAC,CAAC,6CAA6C,CAAC,EAAE,GAAG,EACtD,uCAAsB,QAAE,qCAAoB,WAAM,GAAG,EACrD,sCAAqB,SACjB,IACF,EACN,eAAK,SAAS,EAAC,qDAAqD,aAClE,0BACE,cAAK,SAAS,EAAC,qCAAqC,YACjD,MAAM,CAAC,IAAI,KAAK,UAAU;4CACzB,CAAC,CAAC,CAAC,CAAC,wBAAwB,CAAC;4CAC7B,CAAC,CAAC,CAAC,CAAC,6BAA6B,CAAC,GAChC,EACN,cAAK,SAAS,EAAC,+BAA+B,YAC3C,SAAS;4CACR,CAAC,CAAC,CAAC,CAAC,wBAAwB,CAAC;4CAC7B,CAAC,CAAC,CAAC,CAAC,6BAA6B,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,GACzD,IACF,EACN,KAAC,MAAM,IACL,OAAO,EAAE,MAAM,CAAC,IAAI,KAAK,UAAU,EACnC,QAAQ,EAAE,UAAU,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EACnD,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE,CAC3B,OAAO,CAAC;oCACN,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,eAAe;oCAC5C,cAAc,EAAE,OAAO;wCACrB,CAAC,CAAC,MAAM,CAAC,cAAc;wCACvB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;iCAC9B,CAAC,gBAEQ,CAAC,CAAC,iCAAiC,CAAC,GAChD,IACE,IACF,EAEN,eAAK,SAAS,EAAC,sCAAsC,aACnD,KAAC,KAAK,IAAC,QAAQ,QAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAC,mBAAmB,GAAG,EAC/D,MAAC,MAAM,IAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,OAAO,aACtD,KAAC,QAAQ,IAAC,IAAI,EAAE,EAAE,GAAI,EACrB,CAAC,CAAC,wBAAwB,CAAC,IACrB,IACL,EAEL,MAAM,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,CACjC,cAAK,SAAS,EAAC,+CAA+C,YAC3D,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;oBAChB,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBACxC,OAAO,CACL,kBAEE,IAAI,EAAC,QAAQ,EACb,QAAQ,EACN,UAAU,CAAC,SAAS;4BACpB,UAAU,EAAE,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,UAAU,EAE5D,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAChC,SAAS,EAAC,oKAAoK,kBAChK,UAAU,aAExB,eACE,SAAS,EAAC,kGAAkG,EAC5G,KAAK,EAAE,EAAE,eAAe,EAAE,GAAG,CAAC,KAAK,EAAE,YAEpC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAC5B,EACP,gBAAM,SAAS,EAAC,gBAAgB,aAC9B,gBAAM,SAAS,EAAC,6DAA6D,aAC1E,GAAG,CAAC,IAAI,EACR,UAAU,CAAC,CAAC,CAAC,CACZ,KAAC,SAAS,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,kBAAkB,GAAG,CACrD,CAAC,CAAC,CAAC,IAAI,IACH,EACP,eAAM,SAAS,EAAC,uDAAuD,YACpE,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,GAAG,GACtB,IACF,KA1BF,GAAG,CAAC,EAAE,CA2BJ,CACV,CAAC;gBACJ,CAAC,CAAC,GACE,CACP,CAAC,CAAC,CAAC,IAAI,IACA,CACX,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,WAAW;IACjC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IACjB,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;IAEtE,OAAO,CACL,KAAC,aAAa,IACZ,KAAK,EAAE,CAAC,CAAC,qBAAqB,CAAC,EAC/B,WAAW,EAAE,CAAC,CAAC,kCAAkC,CAAC,YAElD,eAAK,SAAS,EAAC,WAAW,aACxB,KAAC,sBAAsB,KAAG,EAC1B,KAAC,WAAW,IACV,MAAM,EAAE,CAAC,IAAI,IAAI,EAAE,CAAqB,EACxC,SAAS,EAAE,OAAO,GAClB,IACE,GACQ,CACjB,CAAC;AACJ,CAAC","sourcesContent":["import { useMemo, useState } from \"react\";\nimport {\n agentNativePath,\n useActionMutation,\n useActionQuery,\n useT,\n} from \"@agent-native/core/client\";\nimport { AgentsPanel, type ConnectedAgent } 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\";\nimport { IconCheck, IconCopy, IconPlugConnected } from \"@tabler/icons-react\";\nimport { toast } from \"sonner\";\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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.$appId.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/apps.$appId.tsx"],"names":[],"mappings":"AAiBA,wBAAgB,IAAI;;IAEnB;AAED,MAAM,CAAC,OAAO,UAAU,iBAAiB,
|
|
1
|
+
{"version":3,"file":"apps.$appId.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/apps.$appId.tsx"],"names":[],"mappings":"AAiBA,wBAAgB,IAAI;;IAEnB;AAED,MAAM,CAAC,OAAO,UAAU,iBAAiB,4CAyGxC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useMemo } from "react";
|
|
3
3
|
import { Link, useParams } from "react-router";
|
|
4
|
-
import { useActionQuery } from "@agent-native/core/client";
|
|
4
|
+
import { useActionQuery, useT } from "@agent-native/core/client";
|
|
5
5
|
import { IconArrowLeft, IconArrowUpRight, IconClockHour4, } from "@tabler/icons-react";
|
|
6
6
|
import { DispatchShell } from "../../components/dispatch-shell.js";
|
|
7
7
|
import { Badge } from "../../components/ui/badge.js";
|
|
@@ -12,6 +12,7 @@ export function meta() {
|
|
|
12
12
|
return [{ title: "Workspace app - Dispatch" }];
|
|
13
13
|
}
|
|
14
14
|
export default function WorkspaceAppRoute() {
|
|
15
|
+
const t = useT();
|
|
15
16
|
const { appId } = useParams();
|
|
16
17
|
const { data: apps = [], isLoading } = useActionQuery("list-workspace-apps", { includeAgentCards: false }, {
|
|
17
18
|
refetchInterval: 2_000,
|
|
@@ -23,6 +24,6 @@ export default function WorkspaceAppRoute() {
|
|
|
23
24
|
return;
|
|
24
25
|
window.location.assign(href);
|
|
25
26
|
}, [app, href]);
|
|
26
|
-
return (_jsx(DispatchShell, { title: app?.name || "
|
|
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] }))] }) }));
|
|
27
28
|
}
|
|
28
29
|
//# sourceMappingURL=apps.$appId.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.$appId.js","sourceRoot":"","sources":["../../../src/routes/pages/apps.$appId.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"apps.$appId.js","sourceRoot":"","sources":["../../../src/routes/pages/apps.$appId.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useMemo } from \"react\";\nimport { Link, useParams } from \"react-router\";\nimport { useActionQuery, useT } from \"@agent-native/core/client\";\nimport {\n IconArrowLeft,\n IconArrowUpRight,\n IconClockHour4,\n} from \"@tabler/icons-react\";\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(\n \"list-workspace-apps\",\n { includeAgentCards: false },\n {\n refetchInterval: 2_000,\n },\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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/apps.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/apps.tsx"],"names":[],"mappings":"AAyCA,wBAAgB,IAAI;;IAEnB;AAiCD,MAAM,CAAC,OAAO,UAAU,SAAS,4CAsNhC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from "react";
|
|
3
|
-
import { useActionMutation, useActionQuery } from "@agent-native/core/client";
|
|
3
|
+
import { useActionMutation, useActionQuery, useT, } from "@agent-native/core/client";
|
|
4
4
|
import { IconApps, IconBrain, IconBrush, IconCalendarMonth, IconChartBar, IconChevronDown, IconClipboardList, IconContract, IconEyeOff, IconFileText, IconLoader2, IconMail, IconPhoto, IconPlus, IconPresentation, IconScreenShare, IconSparkles, IconStack3, IconVideo, } from "@tabler/icons-react";
|
|
5
5
|
import { toast } from "sonner";
|
|
6
6
|
import { CreateAppPopover } from "../../components/create-app-popover.js";
|
|
@@ -28,6 +28,7 @@ const TEMPLATE_ICONS = {
|
|
|
28
28
|
Video: IconVideo,
|
|
29
29
|
};
|
|
30
30
|
export default function AppsRoute() {
|
|
31
|
+
const t = useT();
|
|
31
32
|
const [showHidden, setShowHidden] = useState(false);
|
|
32
33
|
const [templatesOpen, setTemplatesOpen] = useState(false);
|
|
33
34
|
const { data: apps = [], isLoading: appsLoading } = useActionQuery("list-workspace-apps", { includeAgentCards: false, includeArchived: true }, {
|
|
@@ -42,21 +43,38 @@ export default function AppsRoute() {
|
|
|
42
43
|
const archivedApps = allApps.filter((app) => app.archived);
|
|
43
44
|
const typedTemplates = templates;
|
|
44
45
|
const showAppSkeletons = appsLoading && allApps.length === 0;
|
|
45
|
-
return (_jsx(DispatchShell, { title: "
|
|
46
|
-
?
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
:
|
|
52
|
-
|
|
53
|
-
|
|
46
|
+
return (_jsx(DispatchShell, { title: t("dispatch.nav.apps"), description: workspaceLabel
|
|
47
|
+
? t("dispatch.pages.appsDescriptionWithWorkspace", {
|
|
48
|
+
workspace: workspaceLabel,
|
|
49
|
+
})
|
|
50
|
+
: t("dispatch.pages.appsDescription"), children: _jsxs("div", { className: "space-y-8", children: [_jsxs("section", { className: "space-y-3", children: [_jsxs("div", { className: "flex flex-wrap items-end justify-between gap-3", children: [_jsxs("div", { className: "flex min-w-0 items-start gap-2", children: [_jsx(IconApps, { size: 16, className: "mt-0.5 shrink-0 text-muted-foreground" }), _jsxs("div", { className: "min-w-0", children: [_jsx("h2", { className: "truncate text-sm font-semibold text-foreground", children: workspaceLabel
|
|
51
|
+
? t("dispatch.pages.appsInWorkspace", {
|
|
52
|
+
workspace: workspaceLabel,
|
|
53
|
+
})
|
|
54
|
+
: t("dispatch.pages.workspaceApps") }), _jsxs("p", { className: "mt-0.5 text-xs text-muted-foreground", children: [t("dispatch.pages.activeCount", {
|
|
55
|
+
count: visibleApps.length,
|
|
56
|
+
}), archivedApps.length > 0
|
|
57
|
+
? ` · ${t("dispatch.pages.hiddenCount", {
|
|
58
|
+
count: archivedApps.length,
|
|
59
|
+
})}`
|
|
60
|
+
: ""] })] })] }), 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
|
|
61
|
+
? t("dispatch.pages.checkingTemplates")
|
|
62
|
+
: t("dispatch.pages.templatesAvailable", {
|
|
63
|
+
count: typedTemplates.length,
|
|
64
|
+
}) })] })] }), _jsx(CollapsibleTrigger, { asChild: true, children: _jsxs(Button, { type: "button", variant: "outline", size: "sm", className: "gap-1.5", children: [templatesOpen
|
|
65
|
+
? t("dispatch.pages.hide")
|
|
66
|
+
: t("dispatch.pages.show"), _jsx(IconChevronDown, { size: 14, className: cn("transition-transform", templatesOpen && "rotate-180") })] }) })] }), _jsx(CollapsibleContent, { children: templatesLoading && typedTemplates.length === 0 ? (_jsx(AppsSkeletonGrid, {})) : (_jsx("div", { className: "grid auto-rows-fr gap-3 md:grid-cols-2 xl:grid-cols-3", children: typedTemplates.map((template) => (_jsx(AddTemplateCard, { template: template }, template.name))) })) })] }) })) : null, archivedApps.length > 0 ? (_jsx(Collapsible, { open: showHidden, onOpenChange: setShowHidden, 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(IconEyeOff, { 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.hiddenApps") }), _jsx("p", { className: "text-xs text-muted-foreground", children: t("dispatch.pages.hiddenAppCount", {
|
|
67
|
+
count: archivedApps.length,
|
|
68
|
+
}) })] })] }), _jsx(CollapsibleTrigger, { asChild: true, children: _jsxs(Button, { type: "button", variant: "outline", size: "sm", className: "gap-1.5", children: [showHidden
|
|
69
|
+
? t("dispatch.pages.hide")
|
|
70
|
+
: t("dispatch.pages.show"), _jsx(IconChevronDown, { size: 14, className: cn("transition-transform", showHidden && "rotate-180") })] }) })] }), _jsx(CollapsibleContent, { children: _jsx("div", { className: "grid auto-rows-fr gap-3 md:grid-cols-2 xl:grid-cols-3", children: archivedApps.map((app) => (_jsx(WorkspaceAppCard, { app: app, className: "h-full" }, app.id))) }) })] }) })) : null] }) }));
|
|
54
71
|
}
|
|
55
72
|
function AppsSkeletonGrid() {
|
|
56
73
|
return (_jsx("div", { className: "grid gap-3 md:grid-cols-2 xl:grid-cols-3", children: Array.from({ length: 3 }).map((_, index) => (_jsx("div", { className: "rounded-lg border bg-card p-4", children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0 flex-1 space-y-3", children: [_jsx(Skeleton, { className: "h-4 w-32" }), _jsx(Skeleton, { className: "h-3 w-24" }), _jsxs("div", { className: "space-y-2 pt-1", children: [_jsx(Skeleton, { className: "h-3 w-full" }), _jsx(Skeleton, { className: "h-3 w-2/3" })] })] }), _jsx(Skeleton, { className: "h-7 w-7 rounded-md" })] }) }, index))) }));
|
|
57
74
|
}
|
|
58
75
|
function EmptyAppsState() {
|
|
59
|
-
|
|
76
|
+
const t = useT();
|
|
77
|
+
return (_jsxs("div", { className: "rounded-lg border border-dashed bg-card px-4 py-10 text-center", children: [_jsx("div", { className: "mx-auto flex size-10 items-center justify-center rounded-lg bg-muted text-muted-foreground", children: _jsx(IconApps, { size: 18 }) }), _jsx("h3", { className: "mt-3 text-sm font-semibold text-foreground", children: t("dispatch.pages.noWorkspaceApps") }), _jsx("p", { className: "mx-auto mt-1 max-w-sm text-sm text-muted-foreground", children: t("dispatch.pages.noWorkspaceAppsDescription") }), _jsx("div", { className: "mt-4", children: _jsx(CreateAppPopover, { trigger: _jsxs(Button, { size: "sm", children: [_jsx(IconPlus, { size: 15, className: "mr-1.5" }), t("dispatch.pages.createApp")] }) }) })] }));
|
|
60
78
|
}
|
|
61
79
|
function AddTemplateCard({ template }) {
|
|
62
80
|
const Icon = TEMPLATE_ICONS[template.icon] ?? IconSparkles;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.js","sourceRoot":"","sources":["../../../src/routes/pages/apps.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EACL,QAAQ,EACR,SAAS,EACT,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,UAAU,EACV,SAAS,GACV,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAGjC,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC;AACxC,CAAC;AAkBD,MAAM,cAAc,GAAoC;IACtD,IAAI,EAAE,QAAQ;IACd,aAAa,EAAE,iBAAiB;IAChC,QAAQ,EAAE,YAAY;IACtB,YAAY,EAAE,gBAAgB;IAC9B,WAAW,EAAE,eAAe;IAC5B,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,SAAS;IAChB,QAAQ,EAAE,YAAY;IACtB,aAAa,EAAE,iBAAiB;IAChC,QAAQ,EAAE,YAAY;IACtB,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,SAAS;CACjB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,SAAS;IAC/B,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1D,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,cAAc,CAChE,qBAAqB,EACrB,EAAE,iBAAiB,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,EACnD;QACE,eAAe,EAAE,KAAK;KACvB,CACF,CAAC;IACF,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,cAAc,CACxC,oBAAoB,EACpB,EAAE,EACF,EAAE,SAAS,EAAE,MAAM,EAAE,CACtB,CAAC;IACF,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,EAAE,EAAE,SAAS,EAAE,gBAAgB,EAAE,GAAG,cAAc,CAC1E,oCAAoC,EACpC,EAAE,EACF,EAAE,eAAe,EAAE,KAAK,EAAE,CAC3B,CAAC;IAEF,MAAM,EAAE,GAAG,SAAsC,CAAC;IAClD,MAAM,cAAc,GAAG,EAAE,EAAE,WAAW,IAAI,EAAE,EAAE,IAAI,IAAI,IAAI,CAAC;IAC3D,MAAM,OAAO,GAAI,IAA8B,CAAC,MAAM,CACpD,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CACzB,CAAC;IACF,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC3D,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC3D,MAAM,cAAc,GAAG,SAAgC,CAAC;IACxD,MAAM,gBAAgB,GAAG,WAAW,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC;IAE7D,OAAO,CACL,KAAC,aAAa,IACZ,KAAK,EAAC,MAAM,EACZ,WAAW,EACT,cAAc;YACZ,CAAC,CAAC,gBAAgB,cAAc,8GAA8G;YAC9I,CAAC,CAAC,+DAA+D,YAGrE,eAAK,SAAS,EAAC,WAAW,aACxB,mBAAS,SAAS,EAAC,WAAW,aAC5B,eAAK,SAAS,EAAC,gDAAgD,aAC7D,eAAK,SAAS,EAAC,gCAAgC,aAC7C,KAAC,QAAQ,IACP,IAAI,EAAE,EAAE,EACR,SAAS,EAAC,uCAAuC,GACjD,EACF,eAAK,SAAS,EAAC,SAAS,aACtB,aAAI,SAAS,EAAC,gDAAgD,YAC3D,cAAc;wDACb,CAAC,CAAC,WAAW,cAAc,EAAE;wDAC7B,CAAC,CAAC,gBAAgB,GACjB,EACL,aAAG,SAAS,EAAC,sCAAsC,aAChD,WAAW,CAAC,MAAM,aAClB,YAAY,CAAC,MAAM,GAAG,CAAC;4DACtB,CAAC,CAAC,MAAM,YAAY,CAAC,MAAM,SAAS;4DACpC,CAAC,CAAC,EAAE,IACJ,IACA,IACF,EACL,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CACxB,KAAC,gBAAgB,IACf,KAAK,EAAC,KAAK,EACX,OAAO,EACL,MAAC,MAAM,IAAC,IAAI,EAAC,IAAI,aACf,KAAC,QAAQ,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,QAAQ,GAAG,kBAElC,GAEX,CACH,CAAC,CAAC,CAAC,IAAI,IACJ,EAEL,gBAAgB,CAAC,CAAC,CAAC,CAClB,KAAC,gBAAgB,KAAG,CACrB,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAC3B,cAAK,SAAS,EAAC,uDAAuD,YACnE,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACxB,KAAC,gBAAgB,IAAc,GAAG,EAAE,GAAG,EAAE,SAAS,EAAC,QAAQ,IAApC,GAAG,CAAC,EAAE,CAAiC,CAC/D,CAAC,GACE,CACP,CAAC,CAAC,CAAC,CACF,KAAC,cAAc,KAAG,CACnB,IACO,EAET,cAAc,CAAC,MAAM,GAAG,CAAC,IAAI,gBAAgB,CAAC,CAAC,CAAC,CAC/C,KAAC,WAAW,IAAC,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,gBAAgB,YAC9D,mBAAS,SAAS,EAAC,WAAW,aAC5B,eAAK,SAAS,EAAC,iEAAiE,aAC9E,eAAK,SAAS,EAAC,iCAAiC,aAC9C,KAAC,UAAU,IACT,IAAI,EAAE,EAAE,EACR,SAAS,EAAC,gCAAgC,GAC1C,EACF,eAAK,SAAS,EAAC,SAAS,aACtB,aAAI,SAAS,EAAC,uCAAuC,0BAEhD,EACL,YAAG,SAAS,EAAC,+BAA+B,YACzC,gBAAgB;4DACf,CAAC,CAAC,8BAA8B;4DAChC,CAAC,CAAC,GAAG,cAAc,CAAC,MAAM,wBAAwB,GAClD,IACA,IACF,EACN,KAAC,kBAAkB,IAAC,OAAO,kBACzB,MAAC,MAAM,IACL,IAAI,EAAC,QAAQ,EACb,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,IAAI,EACT,SAAS,EAAC,SAAS,aAElB,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAChC,KAAC,eAAe,IACd,IAAI,EAAE,EAAE,EACR,SAAS,EAAE,EAAE,CACX,sBAAsB,EACtB,aAAa,IAAI,YAAY,CAC9B,GACD,IACK,GACU,IACjB,EACN,KAAC,kBAAkB,cAChB,gBAAgB,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACjD,KAAC,gBAAgB,KAAG,CACrB,CAAC,CAAC,CAAC,CACF,cAAK,SAAS,EAAC,uDAAuD,YACnE,cAAc,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAChC,KAAC,eAAe,IAEd,QAAQ,EAAE,QAAQ,IADb,QAAQ,CAAC,IAAI,CAElB,CACH,CAAC,GACE,CACP,GACkB,IACb,GACE,CACf,CAAC,CAAC,CAAC,IAAI,EAEP,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CACzB,KAAC,WAAW,IAAC,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,YACxD,mBAAS,SAAS,EAAC,WAAW,aAC5B,eAAK,SAAS,EAAC,iEAAiE,aAC9E,eAAK,SAAS,EAAC,iCAAiC,aAC9C,KAAC,UAAU,IACT,IAAI,EAAE,EAAE,EACR,SAAS,EAAC,gCAAgC,GAC1C,EACF,eAAK,SAAS,EAAC,SAAS,aACtB,aAAI,SAAS,EAAC,uCAAuC,4BAEhD,EACL,aAAG,SAAS,EAAC,+BAA+B,aACzC,YAAY,CAAC,MAAM,aAAS,GAAG,EAC/B,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,IACzC,IACA,IACF,EACN,KAAC,kBAAkB,IAAC,OAAO,kBACzB,MAAC,MAAM,IACL,IAAI,EAAC,QAAQ,EACb,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,IAAI,EACT,SAAS,EAAC,SAAS,aAElB,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAC7B,KAAC,eAAe,IACd,IAAI,EAAE,EAAE,EACR,SAAS,EAAE,EAAE,CACX,sBAAsB,EACtB,UAAU,IAAI,YAAY,CAC3B,GACD,IACK,GACU,IACjB,EACN,KAAC,kBAAkB,cACjB,cAAK,SAAS,EAAC,uDAAuD,YACnE,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACzB,KAAC,gBAAgB,IAEf,GAAG,EAAE,GAAG,EACR,SAAS,EAAC,QAAQ,IAFb,GAAG,CAAC,EAAE,CAGX,CACH,CAAC,GACE,GACa,IACb,GACE,CACf,CAAC,CAAC,CAAC,IAAI,IACJ,GACQ,CACjB,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB;IACvB,OAAO,CACL,cAAK,SAAS,EAAC,0CAA0C,YACtD,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAC3C,cAAiB,SAAS,EAAC,+BAA+B,YACxD,eAAK,SAAS,EAAC,wCAAwC,aACrD,eAAK,SAAS,EAAC,0BAA0B,aACvC,KAAC,QAAQ,IAAC,SAAS,EAAC,UAAU,GAAG,EACjC,KAAC,QAAQ,IAAC,SAAS,EAAC,UAAU,GAAG,EACjC,eAAK,SAAS,EAAC,gBAAgB,aAC7B,KAAC,QAAQ,IAAC,SAAS,EAAC,YAAY,GAAG,EACnC,KAAC,QAAQ,IAAC,SAAS,EAAC,WAAW,GAAG,IAC9B,IACF,EACN,KAAC,QAAQ,IAAC,SAAS,EAAC,oBAAoB,GAAG,IACvC,IAXE,KAAK,CAYT,CACP,CAAC,GACE,CACP,CAAC;AACJ,CAAC;AAED,SAAS,cAAc;IACrB,OAAO,CACL,eAAK,SAAS,EAAC,gEAAgE,aAC7E,cAAK,SAAS,EAAC,4FAA4F,YACzG,KAAC,QAAQ,IAAC,IAAI,EAAE,EAAE,GAAI,GAClB,EACN,aAAI,SAAS,EAAC,4CAA4C,sCAErD,EACL,YAAG,SAAS,EAAC,qDAAqD,mFAE9D,EACJ,cAAK,SAAS,EAAC,MAAM,YACnB,KAAC,gBAAgB,IACf,OAAO,EACL,MAAC,MAAM,IAAC,IAAI,EAAC,IAAI,aACf,KAAC,QAAQ,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,QAAQ,GAAG,kBAElC,GAEX,GACE,IACF,CACP,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,EAAE,QAAQ,EAAmC;IACpE,MAAM,IAAI,GAAG,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC;IAC3D,MAAM,QAAQ,GAAG,iBAAiB,CAAC,wBAAwB,EAAE;QAC3D,SAAS,EAAE,CAAC,MAAW,EAAE,EAAE;YACzB,KAAK,CAAC,OAAO,CACX,mBAAmB,MAAM,EAAE,KAAK,IAAI,QAAQ,CAAC,IAAI,wCAAwC,CAC1F,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACf,KAAK,CAAC,KAAK,CACT,sBAAsB,QAAQ,CAAC,KAAK,KAClC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CACjD,EAAE,CACH,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;IAEH,OAAO,CACL,eAAK,SAAS,EAAC,6HAA6H,aAC1I,cACE,SAAS,EAAC,yEAAyE,EACnF,KAAK,EAAE;oBACL,eAAe,EAAE,OAAO,QAAQ,CAAC,QAAQ,UAAU;oBACnD,KAAK,EAAE,QAAQ,CAAC,KAAK;iBACtB,YAED,KAAC,IAAI,IAAC,IAAI,EAAE,EAAE,GAAI,GACd,EACN,eAAK,SAAS,EAAC,8BAA8B,aAC3C,cAAK,SAAS,EAAC,iCAAiC,YAC9C,aAAI,SAAS,EAAC,gDAAgD,YAC3D,QAAQ,CAAC,KAAK,GACZ,GACD,EACN,YAAG,SAAS,EAAC,iEAAiE,YAC3E,QAAQ,CAAC,IAAI,GACZ,EACJ,cAAK,SAAS,EAAC,cAAc,YAC3B,KAAC,MAAM,IACL,IAAI,EAAC,IAAI,EACT,OAAO,EAAC,SAAS,EACjB,QAAQ,EAAE,QAAQ,CAAC,SAAS,EAC5B,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,YAE1D,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CACpB,8BACE,KAAC,WAAW,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,qBAAqB,GAAG,iBAExD,CACJ,CAAC,CAAC,CAAC,CACF,8BACE,KAAC,QAAQ,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,QAAQ,GAAG,wBAExC,CACJ,GACM,GACL,IACF,IACF,CACP,CAAC;AACJ,CAAC","sourcesContent":["import { useState } from \"react\";\nimport { useActionMutation, useActionQuery } from \"@agent-native/core/client\";\nimport {\n IconApps,\n IconBrain,\n IconBrush,\n IconCalendarMonth,\n IconChartBar,\n IconChevronDown,\n IconClipboardList,\n IconContract,\n IconEyeOff,\n IconFileText,\n IconLoader2,\n IconMail,\n IconPhoto,\n IconPlus,\n IconPresentation,\n IconScreenShare,\n IconSparkles,\n IconStack3,\n IconVideo,\n} from \"@tabler/icons-react\";\nimport { toast } from \"sonner\";\nimport { CreateAppPopover } from \"@/components/create-app-popover\";\nimport { DispatchShell } from \"@/components/dispatch-shell\";\nimport { WorkspaceAppCard } from \"@/components/workspace-app-card\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"@/components/ui/collapsible\";\nimport { Skeleton } from \"@/components/ui/skeleton\";\nimport { cn } from \"@/lib/utils\";\nimport type { WorkspaceAppSummary } from \"@/lib/workspace-apps\";\n\nexport function meta() {\n return [{ title: \"Apps — Dispatch\" }];\n}\n\ninterface WorkspaceInfo {\n name: string | null;\n displayName: string | null;\n appCount: number;\n}\n\ninterface AvailableTemplate {\n name: string;\n label: string;\n hint: string;\n icon: string;\n color: string;\n colorRgb: string;\n core: boolean;\n}\n\nconst TEMPLATE_ICONS: Record<string, typeof IconMail> = {\n Mail: IconMail,\n CalendarMonth: IconCalendarMonth,\n FileText: IconFileText,\n Presentation: IconPresentation,\n ScreenShare: IconScreenShare,\n Brain: IconBrain,\n Photo: IconPhoto,\n ChartBar: IconChartBar,\n ClipboardList: IconClipboardList,\n Contract: IconContract,\n Brush: IconBrush,\n Video: IconVideo,\n};\n\nexport default function AppsRoute() {\n const [showHidden, setShowHidden] = useState(false);\n const [templatesOpen, setTemplatesOpen] = useState(false);\n const { data: apps = [], isLoading: appsLoading } = useActionQuery(\n \"list-workspace-apps\",\n { includeAgentCards: false, includeArchived: true },\n {\n refetchInterval: 2_000,\n },\n );\n const { data: workspace } = useActionQuery(\n \"get-workspace-info\",\n {},\n { staleTime: 60_000 },\n );\n const { data: templates = [], isLoading: templatesLoading } = useActionQuery(\n \"list-available-workspace-templates\",\n {},\n { refetchInterval: 5_000 },\n );\n\n const ws = workspace as WorkspaceInfo | undefined;\n const workspaceLabel = ws?.displayName ?? ws?.name ?? null;\n const allApps = (apps as WorkspaceAppSummary[]).filter(\n (app) => !app.isDispatch,\n );\n const visibleApps = allApps.filter((app) => !app.archived);\n const archivedApps = allApps.filter((app) => app.archived);\n const typedTemplates = templates as AvailableTemplate[];\n const showAppSkeletons = appsLoading && allApps.length === 0;\n\n return (\n <DispatchShell\n title=\"Apps\"\n description={\n workspaceLabel\n ? `Apps in the \"${workspaceLabel}\" workspace. Each app gets its own route under this workspace and shares its database, auth, and agent chat.`\n : \"Open workspace apps and start new app creation from Dispatch.\"\n }\n >\n <div className=\"space-y-8\">\n <section className=\"space-y-3\">\n <div className=\"flex flex-wrap items-end justify-between gap-3\">\n <div className=\"flex min-w-0 items-start gap-2\">\n <IconApps\n size={16}\n className=\"mt-0.5 shrink-0 text-muted-foreground\"\n />\n <div className=\"min-w-0\">\n <h2 className=\"truncate text-sm font-semibold text-foreground\">\n {workspaceLabel\n ? `Apps in ${workspaceLabel}`\n : \"Workspace apps\"}\n </h2>\n <p className=\"mt-0.5 text-xs text-muted-foreground\">\n {visibleApps.length} active\n {archivedApps.length > 0\n ? ` · ${archivedApps.length} hidden`\n : \"\"}\n </p>\n </div>\n </div>\n {visibleApps.length > 0 ? (\n <CreateAppPopover\n align=\"end\"\n trigger={\n <Button size=\"sm\">\n <IconPlus size={15} className=\"mr-1.5\" />\n Create app\n </Button>\n }\n />\n ) : null}\n </div>\n\n {showAppSkeletons ? (\n <AppsSkeletonGrid />\n ) : visibleApps.length > 0 ? (\n <div className=\"grid auto-rows-fr gap-3 md:grid-cols-2 xl:grid-cols-3\">\n {visibleApps.map((app) => (\n <WorkspaceAppCard key={app.id} app={app} className=\"h-full\" />\n ))}\n </div>\n ) : (\n <EmptyAppsState />\n )}\n </section>\n\n {typedTemplates.length > 0 || templatesLoading ? (\n <Collapsible open={templatesOpen} onOpenChange={setTemplatesOpen}>\n <section className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center justify-between gap-3 border-t pt-4\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <IconStack3\n size={16}\n className=\"shrink-0 text-muted-foreground\"\n />\n <div className=\"min-w-0\">\n <h2 className=\"text-sm font-semibold text-foreground\">\n Templates\n </h2>\n <p className=\"text-xs text-muted-foreground\">\n {templatesLoading\n ? \"Checking available templates\"\n : `${typedTemplates.length} available to scaffold`}\n </p>\n </div>\n </div>\n <CollapsibleTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"gap-1.5\"\n >\n {templatesOpen ? \"Hide\" : \"Show\"}\n <IconChevronDown\n size={14}\n className={cn(\n \"transition-transform\",\n templatesOpen && \"rotate-180\",\n )}\n />\n </Button>\n </CollapsibleTrigger>\n </div>\n <CollapsibleContent>\n {templatesLoading && typedTemplates.length === 0 ? (\n <AppsSkeletonGrid />\n ) : (\n <div className=\"grid auto-rows-fr gap-3 md:grid-cols-2 xl:grid-cols-3\">\n {typedTemplates.map((template) => (\n <AddTemplateCard\n key={template.name}\n template={template}\n />\n ))}\n </div>\n )}\n </CollapsibleContent>\n </section>\n </Collapsible>\n ) : null}\n\n {archivedApps.length > 0 ? (\n <Collapsible open={showHidden} onOpenChange={setShowHidden}>\n <section className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center justify-between gap-3 border-t pt-4\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <IconEyeOff\n size={16}\n className=\"shrink-0 text-muted-foreground\"\n />\n <div className=\"min-w-0\">\n <h2 className=\"text-sm font-semibold text-foreground\">\n Hidden apps\n </h2>\n <p className=\"text-xs text-muted-foreground\">\n {archivedApps.length} hidden{\" \"}\n {archivedApps.length === 1 ? \"app\" : \"apps\"}\n </p>\n </div>\n </div>\n <CollapsibleTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"gap-1.5\"\n >\n {showHidden ? \"Hide\" : \"Show\"}\n <IconChevronDown\n size={14}\n className={cn(\n \"transition-transform\",\n showHidden && \"rotate-180\",\n )}\n />\n </Button>\n </CollapsibleTrigger>\n </div>\n <CollapsibleContent>\n <div className=\"grid auto-rows-fr gap-3 md:grid-cols-2 xl:grid-cols-3\">\n {archivedApps.map((app) => (\n <WorkspaceAppCard\n key={app.id}\n app={app}\n className=\"h-full\"\n />\n ))}\n </div>\n </CollapsibleContent>\n </section>\n </Collapsible>\n ) : null}\n </div>\n </DispatchShell>\n );\n}\n\nfunction AppsSkeletonGrid() {\n return (\n <div className=\"grid gap-3 md:grid-cols-2 xl:grid-cols-3\">\n {Array.from({ length: 3 }).map((_, index) => (\n <div key={index} className=\"rounded-lg border bg-card p-4\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0 flex-1 space-y-3\">\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-24\" />\n <div className=\"space-y-2 pt-1\">\n <Skeleton className=\"h-3 w-full\" />\n <Skeleton className=\"h-3 w-2/3\" />\n </div>\n </div>\n <Skeleton className=\"h-7 w-7 rounded-md\" />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\nfunction EmptyAppsState() {\n return (\n <div className=\"rounded-lg border border-dashed bg-card px-4 py-10 text-center\">\n <div className=\"mx-auto flex size-10 items-center justify-center rounded-lg bg-muted text-muted-foreground\">\n <IconApps size={18} />\n </div>\n <h3 className=\"mt-3 text-sm font-semibold text-foreground\">\n No workspace apps yet\n </h3>\n <p className=\"mx-auto mt-1 max-w-sm text-sm text-muted-foreground\">\n Create an app when a workflow needs its own focused place to live.\n </p>\n <div className=\"mt-4\">\n <CreateAppPopover\n trigger={\n <Button size=\"sm\">\n <IconPlus size={15} className=\"mr-1.5\" />\n Create app\n </Button>\n }\n />\n </div>\n </div>\n );\n}\n\nfunction AddTemplateCard({ template }: { template: AvailableTemplate }) {\n const Icon = TEMPLATE_ICONS[template.icon] ?? IconSparkles;\n const scaffold = useActionMutation(\"scaffold-workspace-app\", {\n onSuccess: (result: any) => {\n toast.success(\n `Scaffolded apps/${result?.appId || template.name}. The gateway will pick it up shortly.`,\n );\n },\n onError: (err) => {\n toast.error(\n `Could not scaffold ${template.label}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n },\n });\n\n return (\n <div className=\"group relative flex h-full min-h-36 items-stretch gap-3 rounded-lg border bg-card p-4 transition hover:border-foreground/30\">\n <div\n className=\"flex h-9 w-9 shrink-0 items-center justify-center self-start rounded-md\"\n style={{\n backgroundColor: `rgb(${template.colorRgb} / 0.12)`,\n color: template.color,\n }}\n >\n <Icon size={18} />\n </div>\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <h3 className=\"truncate text-sm font-semibold text-foreground\">\n {template.label}\n </h3>\n </div>\n <p className=\"mt-1 line-clamp-2 text-xs leading-relaxed text-muted-foreground\">\n {template.hint}\n </p>\n <div className=\"mt-auto pt-3\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled={scaffold.isPending}\n onClick={() => scaffold.mutate({ template: template.name })}\n >\n {scaffold.isPending ? (\n <>\n <IconLoader2 size={14} className=\"mr-1.5 animate-spin\" />\n Adding...\n </>\n ) : (\n <>\n <IconPlus size={14} className=\"mr-1.5\" />\n Add to workspace\n </>\n )}\n </Button>\n </div>\n </div>\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"apps.js","sourceRoot":"","sources":["../../../src/routes/pages/apps.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState } from \"react\";\nimport {\n useActionMutation,\n useActionQuery,\n useT,\n} from \"@agent-native/core/client\";\nimport {\n IconApps,\n IconBrain,\n IconBrush,\n IconCalendarMonth,\n IconChartBar,\n IconChevronDown,\n IconClipboardList,\n IconContract,\n IconEyeOff,\n IconFileText,\n IconLoader2,\n IconMail,\n IconPhoto,\n IconPlus,\n IconPresentation,\n IconScreenShare,\n IconSparkles,\n IconStack3,\n IconVideo,\n} from \"@tabler/icons-react\";\nimport { toast } from \"sonner\";\nimport { CreateAppPopover } from \"@/components/create-app-popover\";\nimport { DispatchShell } from \"@/components/dispatch-shell\";\nimport { WorkspaceAppCard } from \"@/components/workspace-app-card\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"@/components/ui/collapsible\";\nimport { Skeleton } from \"@/components/ui/skeleton\";\nimport { cn } from \"@/lib/utils\";\nimport type { WorkspaceAppSummary } from \"@/lib/workspace-apps\";\n\nexport function meta() {\n return [{ title: \"Apps — Dispatch\" }];\n}\n\ninterface WorkspaceInfo {\n name: string | null;\n displayName: string | null;\n appCount: number;\n}\n\ninterface AvailableTemplate {\n name: string;\n label: string;\n hint: string;\n icon: string;\n color: string;\n colorRgb: string;\n core: boolean;\n}\n\nconst TEMPLATE_ICONS: Record<string, typeof IconMail> = {\n Mail: IconMail,\n CalendarMonth: IconCalendarMonth,\n FileText: IconFileText,\n Presentation: IconPresentation,\n ScreenShare: IconScreenShare,\n Brain: IconBrain,\n Photo: IconPhoto,\n ChartBar: IconChartBar,\n ClipboardList: IconClipboardList,\n Contract: IconContract,\n Brush: IconBrush,\n Video: IconVideo,\n};\n\nexport default function AppsRoute() {\n const t = useT();\n const [showHidden, setShowHidden] = useState(false);\n const [templatesOpen, setTemplatesOpen] = useState(false);\n const { data: apps = [], isLoading: appsLoading } = useActionQuery(\n \"list-workspace-apps\",\n { includeAgentCards: false, includeArchived: true },\n {\n refetchInterval: 2_000,\n },\n );\n const { data: workspace } = useActionQuery(\n \"get-workspace-info\",\n {},\n { staleTime: 60_000 },\n );\n const { data: templates = [], isLoading: templatesLoading } = useActionQuery(\n \"list-available-workspace-templates\",\n {},\n { refetchInterval: 5_000 },\n );\n\n const ws = workspace as WorkspaceInfo | undefined;\n const workspaceLabel = ws?.displayName ?? ws?.name ?? null;\n const allApps = (apps as WorkspaceAppSummary[]).filter(\n (app) => !app.isDispatch,\n );\n const visibleApps = allApps.filter((app) => !app.archived);\n const archivedApps = allApps.filter((app) => app.archived);\n const typedTemplates = templates as AvailableTemplate[];\n const showAppSkeletons = appsLoading && allApps.length === 0;\n\n return (\n <DispatchShell\n title={t(\"dispatch.nav.apps\")}\n description={\n workspaceLabel\n ? t(\"dispatch.pages.appsDescriptionWithWorkspace\", {\n workspace: workspaceLabel,\n })\n : t(\"dispatch.pages.appsDescription\")\n }\n >\n <div className=\"space-y-8\">\n <section className=\"space-y-3\">\n <div className=\"flex flex-wrap items-end justify-between gap-3\">\n <div className=\"flex min-w-0 items-start gap-2\">\n <IconApps\n size={16}\n className=\"mt-0.5 shrink-0 text-muted-foreground\"\n />\n <div className=\"min-w-0\">\n <h2 className=\"truncate text-sm font-semibold text-foreground\">\n {workspaceLabel\n ? t(\"dispatch.pages.appsInWorkspace\", {\n workspace: workspaceLabel,\n })\n : t(\"dispatch.pages.workspaceApps\")}\n </h2>\n <p className=\"mt-0.5 text-xs text-muted-foreground\">\n {t(\"dispatch.pages.activeCount\", {\n count: visibleApps.length,\n })}\n {archivedApps.length > 0\n ? ` · ${t(\"dispatch.pages.hiddenCount\", {\n count: archivedApps.length,\n })}`\n : \"\"}\n </p>\n </div>\n </div>\n {visibleApps.length > 0 ? (\n <CreateAppPopover\n align=\"end\"\n trigger={\n <Button size=\"sm\">\n <IconPlus size={15} className=\"mr-1.5\" />\n {t(\"dispatch.pages.createApp\")}\n </Button>\n }\n />\n ) : null}\n </div>\n\n {showAppSkeletons ? (\n <AppsSkeletonGrid />\n ) : visibleApps.length > 0 ? (\n <div className=\"grid auto-rows-fr gap-3 md:grid-cols-2 xl:grid-cols-3\">\n {visibleApps.map((app) => (\n <WorkspaceAppCard key={app.id} app={app} className=\"h-full\" />\n ))}\n </div>\n ) : (\n <EmptyAppsState />\n )}\n </section>\n\n {typedTemplates.length > 0 || templatesLoading ? (\n <Collapsible open={templatesOpen} onOpenChange={setTemplatesOpen}>\n <section className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center justify-between gap-3 border-t pt-4\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <IconStack3\n size={16}\n className=\"shrink-0 text-muted-foreground\"\n />\n <div className=\"min-w-0\">\n <h2 className=\"text-sm font-semibold text-foreground\">\n {t(\"dispatch.pages.templates\")}\n </h2>\n <p className=\"text-xs text-muted-foreground\">\n {templatesLoading\n ? t(\"dispatch.pages.checkingTemplates\")\n : t(\"dispatch.pages.templatesAvailable\", {\n count: typedTemplates.length,\n })}\n </p>\n </div>\n </div>\n <CollapsibleTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"gap-1.5\"\n >\n {templatesOpen\n ? t(\"dispatch.pages.hide\")\n : t(\"dispatch.pages.show\")}\n <IconChevronDown\n size={14}\n className={cn(\n \"transition-transform\",\n templatesOpen && \"rotate-180\",\n )}\n />\n </Button>\n </CollapsibleTrigger>\n </div>\n <CollapsibleContent>\n {templatesLoading && typedTemplates.length === 0 ? (\n <AppsSkeletonGrid />\n ) : (\n <div className=\"grid auto-rows-fr gap-3 md:grid-cols-2 xl:grid-cols-3\">\n {typedTemplates.map((template) => (\n <AddTemplateCard\n key={template.name}\n template={template}\n />\n ))}\n </div>\n )}\n </CollapsibleContent>\n </section>\n </Collapsible>\n ) : null}\n\n {archivedApps.length > 0 ? (\n <Collapsible open={showHidden} onOpenChange={setShowHidden}>\n <section className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center justify-between gap-3 border-t pt-4\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <IconEyeOff\n size={16}\n className=\"shrink-0 text-muted-foreground\"\n />\n <div className=\"min-w-0\">\n <h2 className=\"text-sm font-semibold text-foreground\">\n {t(\"dispatch.pages.hiddenApps\")}\n </h2>\n <p className=\"text-xs text-muted-foreground\">\n {t(\"dispatch.pages.hiddenAppCount\", {\n count: archivedApps.length,\n })}\n </p>\n </div>\n </div>\n <CollapsibleTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"gap-1.5\"\n >\n {showHidden\n ? t(\"dispatch.pages.hide\")\n : t(\"dispatch.pages.show\")}\n <IconChevronDown\n size={14}\n className={cn(\n \"transition-transform\",\n showHidden && \"rotate-180\",\n )}\n />\n </Button>\n </CollapsibleTrigger>\n </div>\n <CollapsibleContent>\n <div className=\"grid auto-rows-fr gap-3 md:grid-cols-2 xl:grid-cols-3\">\n {archivedApps.map((app) => (\n <WorkspaceAppCard\n key={app.id}\n app={app}\n className=\"h-full\"\n />\n ))}\n </div>\n </CollapsibleContent>\n </section>\n </Collapsible>\n ) : null}\n </div>\n </DispatchShell>\n );\n}\n\nfunction AppsSkeletonGrid() {\n return (\n <div className=\"grid gap-3 md:grid-cols-2 xl:grid-cols-3\">\n {Array.from({ length: 3 }).map((_, index) => (\n <div key={index} className=\"rounded-lg border bg-card p-4\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0 flex-1 space-y-3\">\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-24\" />\n <div className=\"space-y-2 pt-1\">\n <Skeleton className=\"h-3 w-full\" />\n <Skeleton className=\"h-3 w-2/3\" />\n </div>\n </div>\n <Skeleton className=\"h-7 w-7 rounded-md\" />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\nfunction EmptyAppsState() {\n const t = useT();\n return (\n <div className=\"rounded-lg border border-dashed bg-card px-4 py-10 text-center\">\n <div className=\"mx-auto flex size-10 items-center justify-center rounded-lg bg-muted text-muted-foreground\">\n <IconApps size={18} />\n </div>\n <h3 className=\"mt-3 text-sm font-semibold text-foreground\">\n {t(\"dispatch.pages.noWorkspaceApps\")}\n </h3>\n <p className=\"mx-auto mt-1 max-w-sm text-sm text-muted-foreground\">\n {t(\"dispatch.pages.noWorkspaceAppsDescription\")}\n </p>\n <div className=\"mt-4\">\n <CreateAppPopover\n trigger={\n <Button size=\"sm\">\n <IconPlus size={15} className=\"mr-1.5\" />\n {t(\"dispatch.pages.createApp\")}\n </Button>\n }\n />\n </div>\n </div>\n );\n}\n\nfunction AddTemplateCard({ template }: { template: AvailableTemplate }) {\n const Icon = TEMPLATE_ICONS[template.icon] ?? IconSparkles;\n const scaffold = useActionMutation(\"scaffold-workspace-app\", {\n onSuccess: (result: any) => {\n toast.success(\n `Scaffolded apps/${result?.appId || template.name}. The gateway will pick it up shortly.`,\n );\n },\n onError: (err) => {\n toast.error(\n `Could not scaffold ${template.label}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n },\n });\n\n return (\n <div className=\"group relative flex h-full min-h-36 items-stretch gap-3 rounded-lg border bg-card p-4 transition hover:border-foreground/30\">\n <div\n className=\"flex h-9 w-9 shrink-0 items-center justify-center self-start rounded-md\"\n style={{\n backgroundColor: `rgb(${template.colorRgb} / 0.12)`,\n color: template.color,\n }}\n >\n <Icon size={18} />\n </div>\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <h3 className=\"truncate text-sm font-semibold text-foreground\">\n {template.label}\n </h3>\n </div>\n <p className=\"mt-1 line-clamp-2 text-xs leading-relaxed text-muted-foreground\">\n {template.hint}\n </p>\n <div className=\"mt-auto pt-3\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled={scaffold.isPending}\n onClick={() => scaffold.mutate({ template: template.name })}\n >\n {scaffold.isPending ? (\n <>\n <IconLoader2 size={14} className=\"mr-1.5 animate-spin\" />\n Adding...\n </>\n ) : (\n <>\n <IconPlus size={14} className=\"mr-1.5\" />\n Add to workspace\n </>\n )}\n </Button>\n </div>\n </div>\n </div>\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"destinations.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/destinations.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"destinations.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/destinations.tsx"],"names":[],"mappings":"AA8BA,wBAAgB,IAAI;;IAEnB;AA4CD,MAAM,CAAC,OAAO,UAAU,iBAAiB,4CA2LxC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from "react";
|
|
3
|
-
import { useActionMutation, useActionQuery } from "@agent-native/core/client";
|
|
3
|
+
import { useActionMutation, useActionQuery, useT, } from "@agent-native/core/client";
|
|
4
4
|
import { toast } from "sonner";
|
|
5
5
|
import { DispatchShell } from "../../components/dispatch-shell.js";
|
|
6
6
|
import { Button } from "../../components/ui/button.js";
|
|
@@ -12,22 +12,26 @@ export function meta() {
|
|
|
12
12
|
return [{ title: "Destinations — Dispatch" }];
|
|
13
13
|
}
|
|
14
14
|
function QuickSendRow({ destination, }) {
|
|
15
|
+
const t = useT();
|
|
15
16
|
const [text, setText] = useState("");
|
|
16
17
|
const send = useActionMutation("send-platform-message", {
|
|
17
18
|
onSuccess: () => {
|
|
18
|
-
toast.success("
|
|
19
|
+
toast.success(t("dispatch.pages.messageSent"));
|
|
19
20
|
setText("");
|
|
20
21
|
},
|
|
21
22
|
onError: (error) => {
|
|
22
|
-
toast.error(error instanceof Error
|
|
23
|
+
toast.error(error instanceof Error
|
|
24
|
+
? error.message
|
|
25
|
+
: t("dispatch.pages.unableToSendMessage"));
|
|
23
26
|
},
|
|
24
27
|
});
|
|
25
|
-
return (_jsxs("div", { className: "mt-3 flex gap-2", children: [_jsx(Input, { value: text, onChange: (event) => setText(event.target.value), placeholder: "
|
|
28
|
+
return (_jsxs("div", { className: "mt-3 flex gap-2", children: [_jsx(Input, { value: text, onChange: (event) => setText(event.target.value), placeholder: t("dispatch.pages.quickTestMessage") }), _jsx(Button, { onClick: () => send.mutate({
|
|
26
29
|
destinationId: destination.id,
|
|
27
30
|
text: text || `Test message to ${destination.name}`,
|
|
28
|
-
}), disabled: send.isPending, children: "
|
|
31
|
+
}), disabled: send.isPending, children: t("dispatch.pages.send") })] }));
|
|
29
32
|
}
|
|
30
33
|
export default function DestinationsRoute() {
|
|
34
|
+
const t = useT();
|
|
31
35
|
const { data } = useActionQuery("list-destinations", {});
|
|
32
36
|
const [form, setForm] = useState({
|
|
33
37
|
name: "",
|
|
@@ -38,7 +42,7 @@ export default function DestinationsRoute() {
|
|
|
38
42
|
});
|
|
39
43
|
const upsert = useActionMutation("upsert-destination", {
|
|
40
44
|
onSuccess: () => {
|
|
41
|
-
toast.success("
|
|
45
|
+
toast.success(t("dispatch.pages.destinationSaved"));
|
|
42
46
|
setForm((current) => ({
|
|
43
47
|
...current,
|
|
44
48
|
name: "",
|
|
@@ -49,11 +53,13 @@ export default function DestinationsRoute() {
|
|
|
49
53
|
},
|
|
50
54
|
});
|
|
51
55
|
const remove = useActionMutation("delete-destination", {
|
|
52
|
-
onSuccess: () => toast.success("
|
|
56
|
+
onSuccess: () => toast.success(t("dispatch.pages.destinationRemoved")),
|
|
53
57
|
});
|
|
54
|
-
return (_jsx(DispatchShell, { title: "
|
|
58
|
+
return (_jsx(DispatchShell, { title: t("dispatch.nav.destinations"), description: t("dispatch.pages.destinationsDescription"), children: _jsxs("div", { className: "grid gap-4 xl:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)]", children: [_jsxs("section", { className: "rounded-2xl border bg-card p-5", children: [_jsx("h2", { className: "text-lg font-semibold text-foreground", children: t("dispatch.pages.savedDestinations") }), _jsxs("div", { className: "mt-4 space-y-3", children: [(data || []).map((destination) => (_jsxs("div", { className: "rounded-xl border bg-muted/30 p-4", 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: destination.name }), _jsxs("div", { className: "mt-1 text-xs text-muted-foreground", children: [destination.platform, " \u00B7 ", destination.destination, destination.threadRef
|
|
55
59
|
? ` · thread ${destination.threadRef}`
|
|
56
|
-
: ""] }), destination.notes && (_jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: destination.notes }))] }), _jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", size: "sm", children: "
|
|
60
|
+
: ""] }), destination.notes && (_jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: destination.notes }))] }), _jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", size: "sm", children: t("dispatch.pages.delete") }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: t("dispatch.pages.deleteDestinationTitle") }), _jsx(AlertDialogDescription, { children: t("dispatch.pages.deleteDestinationDescription", {
|
|
61
|
+
name: destination.name,
|
|
62
|
+
}) })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: t("dispatch.pages.cancel") }), _jsx(AlertDialogAction, { onClick: () => remove.mutate({ id: destination.id }), children: t("dispatch.pages.delete") })] })] })] })] }), _jsx(QuickSendRow, { destination: destination })] }, destination.id))), (data?.length || 0) === 0 && (_jsx("div", { className: "rounded-xl border border-dashed px-4 py-8 text-sm text-muted-foreground", children: t("dispatch.pages.noDestinations") }))] })] }), _jsxs("section", { className: "rounded-2xl border bg-card p-5", children: [_jsx("h2", { className: "text-lg font-semibold text-foreground", children: t("dispatch.pages.addDestination") }), _jsxs("div", { className: "mt-4 space-y-3", children: [_jsx(Input, { value: form.name, onChange: (event) => setForm((current) => ({ ...current, name: event.target.value })), placeholder: t("dispatch.pages.dailyDigestChannel") }), _jsxs(Select, { value: form.platform, onValueChange: (value) => setForm((current) => ({
|
|
57
63
|
...current,
|
|
58
64
|
platform: value,
|
|
59
65
|
})), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "slack", children: "Slack" }), _jsx(SelectItem, { value: "telegram", children: "Telegram" }), _jsx(SelectItem, { value: "email", children: "Email" })] })] }), _jsx(Input, { value: form.destination, onChange: (event) => setForm((current) => ({
|
|
@@ -66,15 +72,15 @@ export default function DestinationsRoute() {
|
|
|
66
72
|
: "123456789" }), _jsx(Input, { value: form.threadRef, onChange: (event) => setForm((current) => ({
|
|
67
73
|
...current,
|
|
68
74
|
threadRef: event.target.value,
|
|
69
|
-
})), placeholder: "
|
|
75
|
+
})), placeholder: t("dispatch.pages.optionalThreadOrTopicId") }), _jsx(Textarea, { value: form.notes, onChange: (event) => setForm((current) => ({
|
|
70
76
|
...current,
|
|
71
77
|
notes: event.target.value,
|
|
72
|
-
})), placeholder: "
|
|
78
|
+
})), placeholder: t("dispatch.pages.destinationNotes") }), _jsx(Button, { className: "w-full", onClick: () => upsert.mutate({
|
|
73
79
|
name: form.name,
|
|
74
80
|
platform: form.platform,
|
|
75
81
|
destination: form.destination,
|
|
76
82
|
threadRef: form.threadRef || undefined,
|
|
77
83
|
notes: form.notes || undefined,
|
|
78
|
-
}), disabled: !form.name || !form.destination, children: "
|
|
84
|
+
}), disabled: !form.name || !form.destination, children: t("dispatch.pages.saveDestination") })] })] })] }) }));
|
|
79
85
|
}
|
|
80
86
|
//# sourceMappingURL=destinations.js.map
|