@agent-native/dispatch 0.23.2 → 0.23.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/app-open-actions.d.ts.map +1 -1
- package/dist/components/app-open-actions.js +3 -2
- package/dist/components/app-open-actions.js.map +1 -1
- package/dist/components/layout/Layout.d.ts +4 -2
- package/dist/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +83 -12
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/layout/workspace-apps-rail.d.ts.map +1 -1
- package/dist/components/layout/workspace-apps-rail.js +2 -22
- package/dist/components/layout/workspace-apps-rail.js.map +1 -1
- package/dist/components/workspace-app-card.d.ts.map +1 -1
- package/dist/components/workspace-app-card.js +3 -4
- package/dist/components/workspace-app-card.js.map +1 -1
- package/dist/components/workspace-template-card.d.ts.map +1 -1
- package/dist/components/workspace-template-card.js +1 -1
- package/dist/components/workspace-template-card.js.map +1 -1
- package/dist/lib/workspace-apps.d.ts +1 -0
- package/dist/lib/workspace-apps.d.ts.map +1 -1
- package/dist/lib/workspace-apps.js +13 -0
- package/dist/lib/workspace-apps.js.map +1 -1
- package/dist/routes/index.js +1 -1
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/pages/agent-integrations.d.ts +5 -0
- package/dist/routes/pages/agent-integrations.d.ts.map +1 -0
- package/dist/routes/pages/agent-integrations.js +15 -0
- package/dist/routes/pages/agent-integrations.js.map +1 -0
- package/dist/routes/pages/apps.$appId.d.ts.map +1 -1
- package/dist/routes/pages/apps.$appId.js +14 -2
- package/dist/routes/pages/apps.$appId.js.map +1 -1
- package/dist/routes/pages/overview.d.ts +2 -2
- package/dist/routes/pages/settings.d.ts.map +1 -1
- package/dist/routes/pages/settings.js +1 -1
- package/dist/routes/pages/settings.js.map +1 -1
- package/package.json +2 -2
- package/src/components/app-open-actions.tsx +3 -2
- package/src/components/layout/Layout.tsx +111 -16
- package/src/components/layout/workspace-apps-rail.tsx +2 -25
- package/src/components/workspace-app-card.spec.tsx +6 -6
- package/src/components/workspace-app-card.tsx +4 -7
- package/src/components/workspace-template-card.spec.tsx +4 -16
- package/src/components/workspace-template-card.tsx +0 -1
- package/src/lib/workspace-apps.spec.ts +21 -0
- package/src/lib/workspace-apps.ts +12 -0
- package/src/routes/index.ts +1 -1
- package/src/routes/pages/agent-integrations.tsx +24 -0
- package/src/routes/pages/apps.$appId.tsx +19 -1
- package/src/routes/pages/settings.tsx +1 -19
|
@@ -3,7 +3,7 @@ import { useActionMutation, useActionQuery, } from "@agent-native/core/client/ho
|
|
|
3
3
|
import { useT } from "@agent-native/core/client/i18n";
|
|
4
4
|
import { withBuilderUtmTrackingParams } from "@agent-native/core/shared/builder-link-tracking";
|
|
5
5
|
import { IconArrowLeft, IconClockHour4 } from "@tabler/icons-react";
|
|
6
|
-
import { useEffect, useMemo, useState } from "react";
|
|
6
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
7
7
|
import { Link, useParams } from "react-router";
|
|
8
8
|
import { ActionQueryError } from "../../components/action-query-error.js";
|
|
9
9
|
import { Badge } from "../../components/ui/badge.js";
|
|
@@ -26,6 +26,7 @@ export default function WorkspaceAppRoute() {
|
|
|
26
26
|
const [embedUrl, setEmbedUrl] = useState(null);
|
|
27
27
|
const [embedError, setEmbedError] = useState(null);
|
|
28
28
|
const [embedAttempt, setEmbedAttempt] = useState(0);
|
|
29
|
+
const embedFrameRef = useRef(null);
|
|
29
30
|
const createEmbedSession = useActionMutation("create_embed_session", {
|
|
30
31
|
skipActionQueryInvalidation: true,
|
|
31
32
|
});
|
|
@@ -66,6 +67,17 @@ export default function WorkspaceAppRoute() {
|
|
|
66
67
|
embedAttempt,
|
|
67
68
|
embedInput,
|
|
68
69
|
]);
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
const handleEmbedSessionExpired = (event) => {
|
|
72
|
+
if (event.data?.type !== "agentNative.embedSessionExpired" ||
|
|
73
|
+
event.source !== embedFrameRef.current?.contentWindow) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
setEmbedAttempt((attempt) => attempt + 1);
|
|
77
|
+
};
|
|
78
|
+
window.addEventListener("message", handleEmbedSessionExpired);
|
|
79
|
+
return () => window.removeEventListener("message", handleEmbedSessionExpired);
|
|
80
|
+
}, []);
|
|
69
81
|
if (appsQuery.isError) {
|
|
70
82
|
return (_jsx("div", { className: "flex h-full min-h-0 items-center justify-center p-6", children: _jsx("div", { className: "w-full max-w-2xl", children: _jsx(ActionQueryError, { error: appsQuery.error, onRetry: () => void appsQuery.refetch() }) }) }));
|
|
71
83
|
}
|
|
@@ -81,6 +93,6 @@ export default function WorkspaceAppRoute() {
|
|
|
81
93
|
content: "dispatch_branch",
|
|
82
94
|
}), target: "_blank", rel: "noreferrer", children: t("dispatch.pages.openBuilderBranch") }) })) : null] })] }) }));
|
|
83
95
|
}
|
|
84
|
-
return (_jsx("div", { "data-dispatch-workspace-app-host": true, className: "flex h-full min-h-0 flex-col bg-background", children: _jsx("div", { className: "min-h-0 flex-1 bg-muted/20", children: embedUrl ? (_jsx("iframe", { "data-dispatch-workspace-app-frame": true, src: embedUrl, title: app.name, referrerPolicy: "no-referrer", className: "h-full w-full border-0 bg-background" })) : embedError ? (_jsx("div", { className: "flex h-full items-center justify-center p-6", children: _jsx("div", { className: "w-full max-w-2xl", children: _jsx(ActionQueryError, { error: embedError, onRetry: () => setEmbedAttempt((attempt) => attempt + 1) }) }) })) : (_jsxs("div", { className: "flex h-full items-center justify-center", children: [_jsx(Spinner, { className: "size-5 text-muted-foreground" }), _jsx("span", { className: "sr-only", children: t("dispatch.pages.loading") })] })) }) }));
|
|
96
|
+
return (_jsx("div", { "data-dispatch-workspace-app-host": true, className: "flex h-full min-h-0 flex-col bg-background", children: _jsx("div", { className: "min-h-0 flex-1 bg-muted/20", children: embedUrl ? (_jsx("iframe", { "data-dispatch-workspace-app-frame": true, src: embedUrl, title: app.name, ref: embedFrameRef, referrerPolicy: "no-referrer", className: "h-full w-full border-0 bg-background" })) : embedError ? (_jsx("div", { className: "flex h-full items-center justify-center p-6", children: _jsx("div", { className: "w-full max-w-2xl", children: _jsx(ActionQueryError, { error: embedError, onRetry: () => setEmbedAttempt((attempt) => attempt + 1) }) }) })) : (_jsxs("div", { className: "flex h-full items-center justify-center", children: [_jsx(Spinner, { className: "size-5 text-muted-foreground" }), _jsx("span", { className: "sr-only", children: t("dispatch.pages.loading") })] })) }) }));
|
|
85
97
|
}
|
|
86
98
|
//# 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 {\n useActionMutation,\n useActionQuery,\n} from \"@agent-native/core/client/hooks\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport { withBuilderUtmTrackingParams } from \"@agent-native/core/shared/builder-link-tracking\";\nimport { IconArrowLeft, IconClockHour4 } from \"@tabler/icons-react\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { Link, useParams } from \"react-router\";\n\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { Skeleton } from \"../../components/ui/skeleton\";\nimport { Spinner } from \"../../components/ui/spinner\";\nimport {\n workspaceAppHref,\n type WorkspaceAppSummary,\n} from \"../../lib/workspace-apps\";\n\ninterface EmbedSessionResult {\n startUrl: string;\n targetPath?: string;\n expiresAt?: number;\n app: string;\n}\n\ninterface EmbedSessionInput {\n app: string;\n path?: string;\n url?: string;\n chrome: \"minimal\";\n}\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 const [embedUrl, setEmbedUrl] = useState<string | null>(null);\n const [embedError, setEmbedError] = useState<Error | null>(null);\n const [embedAttempt, setEmbedAttempt] = useState(0);\n const createEmbedSession = useActionMutation<\n EmbedSessionResult,\n EmbedSessionInput\n >(\"create_embed_session\", {\n skipActionQueryInvalidation: true,\n });\n const embedInput = useMemo<EmbedSessionInput | null>(() => {\n if (!app || !href) return null;\n const path = app.path.trim();\n if (path.startsWith(\"/\")) {\n return { app: app.id, path, chrome: \"minimal\" };\n }\n return { app: app.id, url: href, chrome: \"minimal\" };\n }, [app?.id, app?.path, href]);\n\n useEffect(() => {\n if (!app || app.status === \"pending\" || !embedInput) return;\n let cancelled = false;\n setEmbedUrl(null);\n setEmbedError(null);\n void createEmbedSession\n .mutateAsync(embedInput)\n .then((result) => {\n if (!cancelled) setEmbedUrl(result.startUrl);\n })\n .catch((cause: unknown) => {\n if (!cancelled) {\n setEmbedError(\n cause instanceof Error ? cause : new Error(String(cause)),\n );\n }\n });\n return () => {\n cancelled = true;\n };\n }, [\n app?.id,\n app?.path,\n app?.status,\n createEmbedSession.mutateAsync,\n embedAttempt,\n embedInput,\n ]);\n\n if (appsQuery.isError) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl\">\n <ActionQueryError\n error={appsQuery.error}\n onRetry={() => void appsQuery.refetch()}\n />\n </div>\n </div>\n );\n }\n\n if (isLoading && !app) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl space-y-3 rounded-xl border bg-card p-6\">\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 </div>\n );\n }\n\n if (!app) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl rounded-xl border bg-card p-6\">\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 <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 </div>\n </div>\n );\n }\n\n if (app.status === \"pending\") {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl rounded-xl border bg-card p-6\">\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 <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\n href={withBuilderUtmTrackingParams(app.builderUrl, {\n campaign: \"product\",\n content: \"dispatch_branch\",\n })}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {t(\"dispatch.pages.openBuilderBranch\")}\n </a>\n </Button>\n ) : null}\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-dispatch-workspace-app-host\n className=\"flex h-full min-h-0 flex-col bg-background\"\n >\n <div className=\"min-h-0 flex-1 bg-muted/20\">\n {embedUrl ? (\n <iframe\n data-dispatch-workspace-app-frame\n src={embedUrl}\n title={app.name}\n referrerPolicy=\"no-referrer\"\n className=\"h-full w-full border-0 bg-background\"\n />\n ) : embedError ? (\n <div className=\"flex h-full items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl\">\n <ActionQueryError\n error={embedError}\n onRetry={() => setEmbedAttempt((attempt) => attempt + 1)}\n />\n </div>\n </div>\n ) : (\n <div className=\"flex h-full items-center justify-center\">\n <Spinner className=\"size-5 text-muted-foreground\" />\n <span className=\"sr-only\">{t(\"dispatch.pages.loading\")}</span>\n </div>\n )}\n </div>\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"apps.$appId.js","sourceRoot":"","sources":["../../../src/routes/pages/apps.$appId.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,iBAAiB,EACjB,cAAc,GACf,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,gCAAgC,CAAC;AACtD,OAAO,EAAE,4BAA4B,EAAE,MAAM,iDAAiD,CAAC;AAC/F,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AACvE,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EACL,gBAAgB,GAEjB,MAAM,0BAA0B,CAAC;AAgBlC,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,iBAAiB;IACvC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IACjB,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,cAAc,CAAC,qBAAqB,EAAE;QACtD,iBAAiB,EAAE,KAAK;KACzB,CAAC,CAAC;IACH,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;IACjD,MAAM,GAAG,GAAG,OAAO,CACjB,GAAG,EAAE,CACF,IAA8B,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,KAAK,CAAC,IAAI,IAAI,EAC3E,CAAC,KAAK,EAAE,IAAI,CAAC,CACd,CAAC;IACF,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAC9D,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IACjE,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,aAAa,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IACtD,MAAM,kBAAkB,GAAG,iBAAiB,CAG1C,sBAAsB,EAAE;QACxB,2BAA2B,EAAE,IAAI;KAClC,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,OAAO,CAA2B,GAAG,EAAE;QACxD,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QAC/B,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAClD,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACvD,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAE/B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,UAAU;YAAE,OAAO;QAC5D,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,WAAW,CAAC,IAAI,CAAC,CAAC;QAClB,aAAa,CAAC,IAAI,CAAC,CAAC;QACpB,KAAK,kBAAkB;aACpB,WAAW,CAAC,UAAU,CAAC;aACvB,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,IAAI,CAAC,SAAS;gBAAE,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC/C,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YACxB,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,aAAa,CACX,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAC1D,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QACL,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC,CAAC;IACJ,CAAC,EAAE;QACD,GAAG,EAAE,EAAE;QACP,GAAG,EAAE,IAAI;QACT,GAAG,EAAE,MAAM;QACX,kBAAkB,CAAC,WAAW;QAC9B,YAAY;QACZ,UAAU;KACX,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,yBAAyB,GAAG,CAAC,KAAmB,EAAE,EAAE;YACxD,IACE,KAAK,CAAC,IAAI,EAAE,IAAI,KAAK,iCAAiC;gBACtD,KAAK,CAAC,MAAM,KAAK,aAAa,CAAC,OAAO,EAAE,aAAa,EACrD,CAAC;gBACD,OAAO;YACT,CAAC;YACD,eAAe,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;QAC5C,CAAC,CAAC;QAEF,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,yBAAyB,CAAC,CAAC;QAC9D,OAAO,GAAG,EAAE,CACV,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,yBAAyB,CAAC,CAAC;IACrE,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;QACtB,OAAO,CACL,cAAK,SAAS,EAAC,qDAAqD,YAClE,cAAK,SAAS,EAAC,kBAAkB,YAC/B,KAAC,gBAAgB,IACf,KAAK,EAAE,SAAS,CAAC,KAAK,EACtB,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,SAAS,CAAC,OAAO,EAAE,GACvC,GACE,GACF,CACP,CAAC;IACJ,CAAC;IAED,IAAI,SAAS,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,OAAO,CACL,cAAK,SAAS,EAAC,qDAAqD,YAClE,eAAK,SAAS,EAAC,0DAA0D,aACvE,KAAC,QAAQ,IAAC,SAAS,EAAC,UAAU,GAAG,EACjC,KAAC,QAAQ,IAAC,SAAS,EAAC,YAAY,GAAG,EACnC,KAAC,QAAQ,IAAC,SAAS,EAAC,WAAW,GAAG,IAC9B,GACF,CACP,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,CACL,cAAK,SAAS,EAAC,qDAAqD,YAClE,eAAK,SAAS,EAAC,gDAAgD,aAC7D,KAAC,MAAM,IAAC,OAAO,QAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAC,OAAO,EAAC,SAAS,EAAC,YAAY,YAC9D,MAAC,IAAI,IAAC,EAAE,EAAC,OAAO,aACd,KAAC,aAAa,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,QAAQ,GAAG,EAC7C,CAAC,CAAC,mBAAmB,CAAC,IAClB,GACA,EACT,eAAK,SAAS,EAAC,WAAW,aACxB,aAAI,SAAS,EAAC,yCAAyC,YACpD,CAAC,CAAC,4BAA4B,CAAC,GAC7B,EACL,YAAG,SAAS,EAAC,+BAA+B,YACzC,CAAC,CAAC,wCAAwC,CAAC,GAC1C,IACA,IACF,GACF,CACP,CAAC;IACJ,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,CACL,cAAK,SAAS,EAAC,qDAAqD,YAClE,eAAK,SAAS,EAAC,gDAAgD,aAC7D,KAAC,MAAM,IAAC,OAAO,QAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAC,OAAO,EAAC,SAAS,EAAC,YAAY,YAC9D,MAAC,IAAI,IAAC,EAAE,EAAC,OAAO,aACd,KAAC,aAAa,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,QAAQ,GAAG,EAC7C,CAAC,CAAC,mBAAmB,CAAC,IAClB,GACA,EACT,eAAK,SAAS,EAAC,WAAW,aACxB,eAAK,SAAS,EAAC,mCAAmC,aAChD,aAAI,SAAS,EAAC,yCAAyC,YACpD,GAAG,CAAC,IAAI,GACN,EACL,MAAC,KAAK,IACJ,OAAO,EAAC,SAAS,EACjB,SAAS,EAAC,8EAA8E,aAExF,KAAC,cAAc,IAAC,IAAI,EAAE,EAAE,GAAI,EAC3B,CAAC,CAAC,yBAAyB,CAAC,IACvB,IACJ,EACN,aAAG,SAAS,EAAC,+BAA+B,aACzC,CAAC,CAAC,kCAAkC,CAAC,EAAE,GAAG,EAC3C,eAAM,SAAS,EAAC,2BAA2B,YAAE,GAAG,CAAC,IAAI,GAAQ,EAAC,GAAG,EAChE,CAAC,CAAC,kCAAkC,CAAC,IACpC,EACH,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAChB,YAAG,SAAS,EAAC,+BAA+B,YACzC,CAAC,CAAC,uBAAuB,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC,GACrD,CACL,CAAC,CAAC,CAAC,IAAI,EACP,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAChB,KAAC,MAAM,IAAC,OAAO,kBACb,YACE,IAAI,EAAE,4BAA4B,CAAC,GAAG,CAAC,UAAU,EAAE;wCACjD,QAAQ,EAAE,SAAS;wCACnB,OAAO,EAAE,iBAAiB;qCAC3B,CAAC,EACF,MAAM,EAAC,QAAQ,EACf,GAAG,EAAC,YAAY,YAEf,CAAC,CAAC,kCAAkC,CAAC,GACpC,GACG,CACV,CAAC,CAAC,CAAC,IAAI,IACJ,IACF,GACF,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,wDAEE,SAAS,EAAC,4CAA4C,YAEtD,cAAK,SAAS,EAAC,4BAA4B,YACxC,QAAQ,CAAC,CAAC,CAAC,CACV,4DAEE,GAAG,EAAE,QAAQ,EACb,KAAK,EAAE,GAAG,CAAC,IAAI,EACf,GAAG,EAAE,aAAa,EAClB,cAAc,EAAC,aAAa,EAC5B,SAAS,EAAC,sCAAsC,GAChD,CACH,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CACf,cAAK,SAAS,EAAC,6CAA6C,YAC1D,cAAK,SAAS,EAAC,kBAAkB,YAC/B,KAAC,gBAAgB,IACf,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,GAAG,CAAC,CAAC,GACxD,GACE,GACF,CACP,CAAC,CAAC,CAAC,CACF,eAAK,SAAS,EAAC,yCAAyC,aACtD,KAAC,OAAO,IAAC,SAAS,EAAC,8BAA8B,GAAG,EACpD,eAAM,SAAS,EAAC,SAAS,YAAE,CAAC,CAAC,wBAAwB,CAAC,GAAQ,IAC1D,CACP,GACG,GACF,CACP,CAAC;AACJ,CAAC","sourcesContent":["import {\n useActionMutation,\n useActionQuery,\n} from \"@agent-native/core/client/hooks\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport { withBuilderUtmTrackingParams } from \"@agent-native/core/shared/builder-link-tracking\";\nimport { IconArrowLeft, IconClockHour4 } from \"@tabler/icons-react\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { Link, useParams } from \"react-router\";\n\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { Skeleton } from \"../../components/ui/skeleton\";\nimport { Spinner } from \"../../components/ui/spinner\";\nimport {\n workspaceAppHref,\n type WorkspaceAppSummary,\n} from \"../../lib/workspace-apps\";\n\ninterface EmbedSessionResult {\n startUrl: string;\n targetPath?: string;\n expiresAt?: number;\n app: string;\n}\n\ninterface EmbedSessionInput {\n app: string;\n path?: string;\n url?: string;\n chrome: \"minimal\";\n}\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 const [embedUrl, setEmbedUrl] = useState<string | null>(null);\n const [embedError, setEmbedError] = useState<Error | null>(null);\n const [embedAttempt, setEmbedAttempt] = useState(0);\n const embedFrameRef = useRef<HTMLIFrameElement>(null);\n const createEmbedSession = useActionMutation<\n EmbedSessionResult,\n EmbedSessionInput\n >(\"create_embed_session\", {\n skipActionQueryInvalidation: true,\n });\n const embedInput = useMemo<EmbedSessionInput | null>(() => {\n if (!app || !href) return null;\n const path = app.path.trim();\n if (path.startsWith(\"/\")) {\n return { app: app.id, path, chrome: \"minimal\" };\n }\n return { app: app.id, url: href, chrome: \"minimal\" };\n }, [app?.id, app?.path, href]);\n\n useEffect(() => {\n if (!app || app.status === \"pending\" || !embedInput) return;\n let cancelled = false;\n setEmbedUrl(null);\n setEmbedError(null);\n void createEmbedSession\n .mutateAsync(embedInput)\n .then((result) => {\n if (!cancelled) setEmbedUrl(result.startUrl);\n })\n .catch((cause: unknown) => {\n if (!cancelled) {\n setEmbedError(\n cause instanceof Error ? cause : new Error(String(cause)),\n );\n }\n });\n return () => {\n cancelled = true;\n };\n }, [\n app?.id,\n app?.path,\n app?.status,\n createEmbedSession.mutateAsync,\n embedAttempt,\n embedInput,\n ]);\n\n useEffect(() => {\n const handleEmbedSessionExpired = (event: MessageEvent) => {\n if (\n event.data?.type !== \"agentNative.embedSessionExpired\" ||\n event.source !== embedFrameRef.current?.contentWindow\n ) {\n return;\n }\n setEmbedAttempt((attempt) => attempt + 1);\n };\n\n window.addEventListener(\"message\", handleEmbedSessionExpired);\n return () =>\n window.removeEventListener(\"message\", handleEmbedSessionExpired);\n }, []);\n\n if (appsQuery.isError) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl\">\n <ActionQueryError\n error={appsQuery.error}\n onRetry={() => void appsQuery.refetch()}\n />\n </div>\n </div>\n );\n }\n\n if (isLoading && !app) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl space-y-3 rounded-xl border bg-card p-6\">\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 </div>\n );\n }\n\n if (!app) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl rounded-xl border bg-card p-6\">\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 <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 </div>\n </div>\n );\n }\n\n if (app.status === \"pending\") {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl rounded-xl border bg-card p-6\">\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 <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\n href={withBuilderUtmTrackingParams(app.builderUrl, {\n campaign: \"product\",\n content: \"dispatch_branch\",\n })}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {t(\"dispatch.pages.openBuilderBranch\")}\n </a>\n </Button>\n ) : null}\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-dispatch-workspace-app-host\n className=\"flex h-full min-h-0 flex-col bg-background\"\n >\n <div className=\"min-h-0 flex-1 bg-muted/20\">\n {embedUrl ? (\n <iframe\n data-dispatch-workspace-app-frame\n src={embedUrl}\n title={app.name}\n ref={embedFrameRef}\n referrerPolicy=\"no-referrer\"\n className=\"h-full w-full border-0 bg-background\"\n />\n ) : embedError ? (\n <div className=\"flex h-full items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl\">\n <ActionQueryError\n error={embedError}\n onRetry={() => setEmbedAttempt((attempt) => attempt + 1)}\n />\n </div>\n </div>\n ) : (\n <div className=\"flex h-full items-center justify-center\">\n <Spinner className=\"size-5 text-muted-foreground\" />\n <span className=\"sr-only\">{t(\"dispatch.pages.loading\")}</span>\n </div>\n )}\n </div>\n </div>\n );\n}\n"]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export declare function meta(): ({
|
|
2
|
+
title: string;
|
|
2
3
|
name?: undefined;
|
|
3
4
|
property?: undefined;
|
|
4
5
|
content?: undefined;
|
|
5
|
-
title: string;
|
|
6
6
|
} | {
|
|
7
7
|
title?: undefined;
|
|
8
|
-
property?: undefined;
|
|
9
8
|
name: string;
|
|
10
9
|
content: string;
|
|
10
|
+
property?: undefined;
|
|
11
11
|
} | {
|
|
12
12
|
title?: undefined;
|
|
13
13
|
name?: undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/settings.tsx"],"names":[],"mappings":"AA4BA,wBAAgB,IAAI;;IAEnB;AAED,MAAM,CAAC,OAAO,UAAU,aAAa,
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/settings.tsx"],"names":[],"mappings":"AA4BA,wBAAgB,IAAI;;IAEnB;AAED,MAAM,CAAC,OAAO,UAAU,aAAa,oDAkJpC"}
|
|
@@ -35,6 +35,6 @@ export default function SettingsRoute() {
|
|
|
35
35
|
detail: { enabled },
|
|
36
36
|
}));
|
|
37
37
|
}
|
|
38
|
-
return (_jsx(DispatchShell, { title: t("settings.title"), description: t("settings.description"), children: _jsx(SettingsTabsPage, { extraTabs: agentSettingsTabs, general: _jsxs("div", { className: "mx-auto w-full max-w-3xl space-y-6", children: [_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { className: "text-base", children: t("settings.languageTitle") }), _jsx(CardDescription, { children: t("settings.languageDescription") })] }), _jsxs(CardContent, { className: "max-w-xs space-y-1.5", children: [_jsx(Label, { children: t("settings.languageLabel") }), _jsx(LanguagePicker, { label: t("settings.languageLabel") })] })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { className: "text-base", children: "Chat-first workspace" }), _jsx(CardDescription, { children: "Keep chats at the center and open workspace apps in a contextual pane beside them." })] }), _jsxs(CardContent, { className: "flex items-center justify-between gap-4", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { htmlFor: "dispatch-chat-first-mode", children: "Use chat-first navigation" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "This preference only changes your local Dispatch shell." }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Session watch and follow-up messaging work in this browser pane too. Local CLI subscription detection stays in the Electron app; Dispatch uses workspace/provider credentials." })] }), _jsx(Switch, { id: "dispatch-chat-first-mode", checked: chatFirstMode, onCheckedChange: updateChatFirstMode })] }), chatFirstStorageNotice ? (_jsx("p", { className: "px-6 pb-4 text-sm text-destructive", role: "alert", children: chatFirstStorageNotice })) : null] }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { className: "text-base", children: t("settings.workspaceTitle") }), _jsx(CardDescription, { children: t("settings.workspaceDescription") })] }), _jsx(CardContent, { children: _jsx(Button, { variant: "outline", asChild: true, children: _jsx(Link, { to: "/admin/workspace", children: t("settings.openResourceSettings") }) }) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { className: "text-base", children: t("settings.
|
|
38
|
+
return (_jsx(DispatchShell, { title: t("settings.title"), description: t("settings.description"), children: _jsx(SettingsTabsPage, { extraTabs: agentSettingsTabs.filter((tab) => tab.id !== "integrations"), general: _jsxs("div", { className: "mx-auto w-full max-w-3xl space-y-6", children: [_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { className: "text-base", children: t("settings.languageTitle") }), _jsx(CardDescription, { children: t("settings.languageDescription") })] }), _jsxs(CardContent, { className: "max-w-xs space-y-1.5", children: [_jsx(Label, { children: t("settings.languageLabel") }), _jsx(LanguagePicker, { label: t("settings.languageLabel") })] })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { className: "text-base", children: "Chat-first workspace" }), _jsx(CardDescription, { children: "Keep chats at the center and open workspace apps in a contextual pane beside them." })] }), _jsxs(CardContent, { className: "flex items-center justify-between gap-4", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { htmlFor: "dispatch-chat-first-mode", children: "Use chat-first navigation" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "This preference only changes your local Dispatch shell." }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Session watch and follow-up messaging work in this browser pane too. Local CLI subscription detection stays in the Electron app; Dispatch uses workspace/provider credentials." })] }), _jsx(Switch, { id: "dispatch-chat-first-mode", checked: chatFirstMode, onCheckedChange: updateChatFirstMode })] }), chatFirstStorageNotice ? (_jsx("p", { className: "px-6 pb-4 text-sm text-destructive", role: "alert", children: chatFirstStorageNotice })) : null] }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { className: "text-base", children: t("settings.workspaceTitle") }), _jsx(CardDescription, { children: t("settings.workspaceDescription") })] }), _jsx(CardContent, { children: _jsx(Button, { variant: "outline", asChild: true, children: _jsx(Link, { to: "/admin/workspace", children: t("settings.openResourceSettings") }) }) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { className: "text-base", children: t("settings.deliveryTitle") }), _jsx(CardDescription, { children: t("settings.deliveryDescription") })] }), _jsx(CardContent, { children: _jsx(Button, { variant: "outline", asChild: true, children: _jsx(Link, { to: "/admin/destinations", children: t("settings.openDelivery") }) }) })] })] }), team: _jsx("div", { className: "mx-auto w-full max-w-3xl", children: _jsx(TeamPage, { showTitle: false, createOrgDescription: "Set up a team to share dispatch destinations and approvals with your colleagues." }) }), whatsNew: _jsx("div", { className: "mx-auto w-full max-w-3xl", children: _jsx(ChangelogSettingsCard, { markdown: changelog }) }) }) }));
|
|
39
39
|
}
|
|
40
40
|
//# sourceMappingURL=settings.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/routes/pages/settings.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n CHAT_FIRST_MODE_CHANGED_EVENT,\n readChatFirstModeState,\n writeChatFirstMode,\n} from \"@agent-native/core/client/agent-chat\";\nimport { ChangelogSettingsCard } from \"@agent-native/core/client/changelog\";\nimport { LanguagePicker, useT } from \"@agent-native/core/client/i18n\";\nimport { TeamPage } from \"@agent-native/core/client/org\";\nimport {\n SettingsTabsPage,\n useAgentSettingsTabs,\n} from \"@agent-native/core/client/settings\";\nimport { useState } from \"react\";\nimport { Link } from \"react-router\";\n\nimport changelog from \"../../../CHANGELOG.md?raw\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport { Button } from \"../../components/ui/button\";\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from \"../../components/ui/card\";\nimport { Label } from \"../../components/ui/label\";\nimport { Switch } from \"../../components/ui/switch\";\n\nexport function meta() {\n return [{ title: \"Settings - Dispatch\" }];\n}\n\nexport default function SettingsRoute() {\n const t = useT();\n const agentSettingsTabs = useAgentSettingsTabs();\n const [chatFirstModeState] = useState(() => readChatFirstModeState());\n const [chatFirstMode, setChatFirstMode] = useState(\n () => chatFirstModeState.enabled,\n );\n const [chatFirstStorageNotice, setChatFirstStorageNotice] = useState<\n string | null\n >(\n chatFirstModeState.availability === \"unavailable\"\n ? \"This browser is not allowing local preferences, so Chat-first mode cannot be persisted.\"\n : null,\n );\n\n function updateChatFirstMode(enabled: boolean) {\n const result = writeChatFirstMode(enabled);\n if (!result.ok) {\n setChatFirstStorageNotice(\n \"This browser blocked local preferences, so Chat-first mode was not changed.\",\n );\n return;\n }\n setChatFirstStorageNotice(null);\n setChatFirstMode(enabled);\n window.dispatchEvent(\n new CustomEvent(CHAT_FIRST_MODE_CHANGED_EVENT, {\n detail: { enabled },\n }),\n );\n }\n\n return (\n <DispatchShell\n title={t(\"settings.title\")}\n description={t(\"settings.description\")}\n >\n <SettingsTabsPage\n extraTabs={agentSettingsTabs}\n general={\n <div className=\"mx-auto w-full max-w-3xl space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t(\"settings.languageTitle\")}\n </CardTitle>\n <CardDescription>\n {t(\"settings.languageDescription\")}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"max-w-xs space-y-1.5\">\n <Label>{t(\"settings.languageLabel\")}</Label>\n <LanguagePicker label={t(\"settings.languageLabel\")} />\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n Chat-first workspace\n </CardTitle>\n <CardDescription>\n Keep chats at the center and open workspace apps in a\n contextual pane beside them.\n </CardDescription>\n </CardHeader>\n <CardContent className=\"flex items-center justify-between gap-4\">\n <div className=\"space-y-1\">\n <Label htmlFor=\"dispatch-chat-first-mode\">\n Use chat-first navigation\n </Label>\n <p className=\"text-sm text-muted-foreground\">\n This preference only changes your local Dispatch shell.\n </p>\n <p className=\"text-sm text-muted-foreground\">\n Session watch and follow-up messaging work in this browser\n pane too. Local CLI subscription detection stays in the\n Electron app; Dispatch uses workspace/provider credentials.\n </p>\n </div>\n <Switch\n id=\"dispatch-chat-first-mode\"\n checked={chatFirstMode}\n onCheckedChange={updateChatFirstMode}\n />\n </CardContent>\n {chatFirstStorageNotice ? (\n <p className=\"px-6 pb-4 text-sm text-destructive\" role=\"alert\">\n {chatFirstStorageNotice}\n </p>\n ) : null}\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t(\"settings.workspaceTitle\")}\n </CardTitle>\n <CardDescription>\n {t(\"settings.workspaceDescription\")}\n </CardDescription>\n </CardHeader>\n <CardContent>\n <Button variant=\"outline\" asChild>\n <Link to=\"/admin/workspace\">\n {t(\"settings.openResourceSettings\")}\n </Link>\n </Button>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t(\"settings.automationsTitle\")}\n </CardTitle>\n <CardDescription>\n {t(\"settings.automationsDescription\")}\n </CardDescription>\n </CardHeader>\n <CardContent>\n <Button variant=\"outline\" asChild>\n <Link to=\"/admin/automations\">\n {t(\"settings.openAutomations\")}\n </Link>\n </Button>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t(\"settings.deliveryTitle\")}\n </CardTitle>\n <CardDescription>\n {t(\"settings.deliveryDescription\")}\n </CardDescription>\n </CardHeader>\n <CardContent>\n <Button variant=\"outline\" asChild>\n <Link to=\"/admin/destinations\">\n {t(\"settings.openDelivery\")}\n </Link>\n </Button>\n </CardContent>\n </Card>\n </div>\n }\n team={\n <div className=\"mx-auto w-full max-w-3xl\">\n <TeamPage\n showTitle={false}\n createOrgDescription=\"Set up a team to share dispatch destinations and approvals with your colleagues.\"\n />\n </div>\n }\n whatsNew={\n <div className=\"mx-auto w-full max-w-3xl\">\n <ChangelogSettingsCard markdown={changelog} />\n </div>\n }\n />\n </DispatchShell>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/routes/pages/settings.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n CHAT_FIRST_MODE_CHANGED_EVENT,\n readChatFirstModeState,\n writeChatFirstMode,\n} from \"@agent-native/core/client/agent-chat\";\nimport { ChangelogSettingsCard } from \"@agent-native/core/client/changelog\";\nimport { LanguagePicker, useT } from \"@agent-native/core/client/i18n\";\nimport { TeamPage } from \"@agent-native/core/client/org\";\nimport {\n SettingsTabsPage,\n useAgentSettingsTabs,\n} from \"@agent-native/core/client/settings\";\nimport { useState } from \"react\";\nimport { Link } from \"react-router\";\n\nimport changelog from \"../../../CHANGELOG.md?raw\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport { Button } from \"../../components/ui/button\";\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from \"../../components/ui/card\";\nimport { Label } from \"../../components/ui/label\";\nimport { Switch } from \"../../components/ui/switch\";\n\nexport function meta() {\n return [{ title: \"Settings - Dispatch\" }];\n}\n\nexport default function SettingsRoute() {\n const t = useT();\n const agentSettingsTabs = useAgentSettingsTabs();\n const [chatFirstModeState] = useState(() => readChatFirstModeState());\n const [chatFirstMode, setChatFirstMode] = useState(\n () => chatFirstModeState.enabled,\n );\n const [chatFirstStorageNotice, setChatFirstStorageNotice] = useState<\n string | null\n >(\n chatFirstModeState.availability === \"unavailable\"\n ? \"This browser is not allowing local preferences, so Chat-first mode cannot be persisted.\"\n : null,\n );\n\n function updateChatFirstMode(enabled: boolean) {\n const result = writeChatFirstMode(enabled);\n if (!result.ok) {\n setChatFirstStorageNotice(\n \"This browser blocked local preferences, so Chat-first mode was not changed.\",\n );\n return;\n }\n setChatFirstStorageNotice(null);\n setChatFirstMode(enabled);\n window.dispatchEvent(\n new CustomEvent(CHAT_FIRST_MODE_CHANGED_EVENT, {\n detail: { enabled },\n }),\n );\n }\n\n return (\n <DispatchShell\n title={t(\"settings.title\")}\n description={t(\"settings.description\")}\n >\n <SettingsTabsPage\n extraTabs={agentSettingsTabs.filter((tab) => tab.id !== \"integrations\")}\n general={\n <div className=\"mx-auto w-full max-w-3xl space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t(\"settings.languageTitle\")}\n </CardTitle>\n <CardDescription>\n {t(\"settings.languageDescription\")}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"max-w-xs space-y-1.5\">\n <Label>{t(\"settings.languageLabel\")}</Label>\n <LanguagePicker label={t(\"settings.languageLabel\")} />\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n Chat-first workspace\n </CardTitle>\n <CardDescription>\n Keep chats at the center and open workspace apps in a\n contextual pane beside them.\n </CardDescription>\n </CardHeader>\n <CardContent className=\"flex items-center justify-between gap-4\">\n <div className=\"space-y-1\">\n <Label htmlFor=\"dispatch-chat-first-mode\">\n Use chat-first navigation\n </Label>\n <p className=\"text-sm text-muted-foreground\">\n This preference only changes your local Dispatch shell.\n </p>\n <p className=\"text-sm text-muted-foreground\">\n Session watch and follow-up messaging work in this browser\n pane too. Local CLI subscription detection stays in the\n Electron app; Dispatch uses workspace/provider credentials.\n </p>\n </div>\n <Switch\n id=\"dispatch-chat-first-mode\"\n checked={chatFirstMode}\n onCheckedChange={updateChatFirstMode}\n />\n </CardContent>\n {chatFirstStorageNotice ? (\n <p className=\"px-6 pb-4 text-sm text-destructive\" role=\"alert\">\n {chatFirstStorageNotice}\n </p>\n ) : null}\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t(\"settings.workspaceTitle\")}\n </CardTitle>\n <CardDescription>\n {t(\"settings.workspaceDescription\")}\n </CardDescription>\n </CardHeader>\n <CardContent>\n <Button variant=\"outline\" asChild>\n <Link to=\"/admin/workspace\">\n {t(\"settings.openResourceSettings\")}\n </Link>\n </Button>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">\n {t(\"settings.deliveryTitle\")}\n </CardTitle>\n <CardDescription>\n {t(\"settings.deliveryDescription\")}\n </CardDescription>\n </CardHeader>\n <CardContent>\n <Button variant=\"outline\" asChild>\n <Link to=\"/admin/destinations\">\n {t(\"settings.openDelivery\")}\n </Link>\n </Button>\n </CardContent>\n </Card>\n </div>\n }\n team={\n <div className=\"mx-auto w-full max-w-3xl\">\n <TeamPage\n showTitle={false}\n createOrgDescription=\"Set up a team to share dispatch destinations and approvals with your colleagues.\"\n />\n </div>\n }\n whatsNew={\n <div className=\"mx-auto w-full max-w-3xl\">\n <ChangelogSettingsCard markdown={changelog} />\n </div>\n }\n />\n </DispatchShell>\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/dispatch",
|
|
3
|
-
"version": "0.23.
|
|
3
|
+
"version": "0.23.3",
|
|
4
4
|
"description": "Dispatch — workspace control plane for agent-native apps. Vault, integrations, destinations, scheduled jobs, and cross-app delegation, shipped as a single drop-in package.",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"typescript-7": "npm:typescript@^7.0.2",
|
|
99
99
|
"vite": "8.1.0",
|
|
100
100
|
"vitest": "^4.1.5",
|
|
101
|
-
"@agent-native/core": "0.149.
|
|
101
|
+
"@agent-native/core": "0.149.5"
|
|
102
102
|
},
|
|
103
103
|
"peerDependencies": {
|
|
104
104
|
"@agent-native/core": ">=0.8.0",
|
|
@@ -44,9 +44,10 @@ export function AppOpenActions({
|
|
|
44
44
|
showNewTabOption?: boolean;
|
|
45
45
|
}) {
|
|
46
46
|
const labels = { ...DEFAULT_LABELS, ...labelOverrides };
|
|
47
|
+
const canOfferNewTab = showNewTabOption && target !== "_blank";
|
|
47
48
|
const hasMenu =
|
|
48
49
|
Boolean(onAddApp) ||
|
|
49
|
-
(Boolean(href) && (showInlineOption ||
|
|
50
|
+
(Boolean(href) && (showInlineOption || canOfferNewTab));
|
|
50
51
|
|
|
51
52
|
if (!href && !hasMenu) {
|
|
52
53
|
return (
|
|
@@ -98,7 +99,7 @@ export function AppOpenActions({
|
|
|
98
99
|
{labels.openInline}
|
|
99
100
|
</DropdownMenuItem>
|
|
100
101
|
) : null}
|
|
101
|
-
{
|
|
102
|
+
{canOfferNewTab && href ? (
|
|
102
103
|
<DropdownMenuItem asChild>
|
|
103
104
|
<a href={href} target="_blank" rel="noreferrer">
|
|
104
105
|
{labels.openInNewTab}
|
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
type ChatFirstAppItem,
|
|
56
56
|
type ChatFirstCopy,
|
|
57
57
|
type ChatFirstEmbedTarget,
|
|
58
|
+
type ChatFirstPrimaryTab,
|
|
58
59
|
} from "@agent-native/core/client/chat-first";
|
|
59
60
|
import { writeClipboardText } from "@agent-native/core/client/clipboard";
|
|
60
61
|
import {
|
|
@@ -104,6 +105,8 @@ import { toast } from "sonner";
|
|
|
104
105
|
import { cn } from "../../lib/utils";
|
|
105
106
|
import {
|
|
106
107
|
mergeChatFirstWorkspaceApps,
|
|
108
|
+
workspaceAppIdFromRoute,
|
|
109
|
+
workspaceAppRoute,
|
|
107
110
|
type WorkspaceAppSummary,
|
|
108
111
|
} from "../../lib/workspace-apps";
|
|
109
112
|
import { AppIcon } from "../app-icon";
|
|
@@ -296,6 +299,31 @@ function localDispatchPath(pathname: string): string {
|
|
|
296
299
|
return pathname;
|
|
297
300
|
}
|
|
298
301
|
|
|
302
|
+
function chatFirstPrimaryTabForPath(
|
|
303
|
+
pathname: string,
|
|
304
|
+
): ChatFirstPrimaryTab | undefined {
|
|
305
|
+
if (pathname === "/chat" || pathname.startsWith("/chat/")) {
|
|
306
|
+
return "new-chat";
|
|
307
|
+
}
|
|
308
|
+
if (
|
|
309
|
+
pathname === "/integrations" ||
|
|
310
|
+
pathname.startsWith("/integrations/") ||
|
|
311
|
+
pathname === "/admin/integrations" ||
|
|
312
|
+
pathname.startsWith("/admin/integrations/")
|
|
313
|
+
) {
|
|
314
|
+
return "integrations";
|
|
315
|
+
}
|
|
316
|
+
if (
|
|
317
|
+
pathname === "/automations" ||
|
|
318
|
+
pathname.startsWith("/automations/") ||
|
|
319
|
+
pathname === "/admin/automations" ||
|
|
320
|
+
pathname.startsWith("/admin/automations/")
|
|
321
|
+
) {
|
|
322
|
+
return "scheduled";
|
|
323
|
+
}
|
|
324
|
+
return undefined;
|
|
325
|
+
}
|
|
326
|
+
|
|
299
327
|
function dispatchNavLinkTarget(path: string): string {
|
|
300
328
|
if (typeof window === "undefined") return path;
|
|
301
329
|
const basePath = appBasePath();
|
|
@@ -543,6 +571,8 @@ function DispatchChatsSection({
|
|
|
543
571
|
chatFirstMode?: boolean;
|
|
544
572
|
chatFirstEmbedded?: boolean;
|
|
545
573
|
chatFirstNavigation?: {
|
|
574
|
+
activeTab?: ChatFirstPrimaryTab;
|
|
575
|
+
onNewChat?: () => void;
|
|
546
576
|
onOpenIntegrations: () => void;
|
|
547
577
|
onOpenScheduled: () => void;
|
|
548
578
|
};
|
|
@@ -683,13 +713,17 @@ function DispatchChatsSection({
|
|
|
683
713
|
)}
|
|
684
714
|
>
|
|
685
715
|
{showNewChat && chatFirstNavigation ? (
|
|
686
|
-
<nav className="space-y-0.5 px-
|
|
716
|
+
<nav className="space-y-0.5 px-2 py-2">
|
|
687
717
|
<ChatFirstPrimaryNavigation
|
|
688
718
|
copy={chatFirstCopy}
|
|
689
|
-
onNewChat={() =>
|
|
719
|
+
onNewChat={() => {
|
|
720
|
+
chatFirstNavigation.onNewChat?.();
|
|
721
|
+
void handleNewChat();
|
|
722
|
+
}}
|
|
690
723
|
onOpenIntegrations={chatFirstNavigation.onOpenIntegrations}
|
|
691
724
|
onOpenScheduled={chatFirstNavigation.onOpenScheduled}
|
|
692
725
|
onSearch={openCommandMenu}
|
|
726
|
+
activeTab={chatFirstNavigation.activeTab}
|
|
693
727
|
/>
|
|
694
728
|
</nav>
|
|
695
729
|
) : null}
|
|
@@ -816,7 +850,7 @@ function DispatchChatsSection({
|
|
|
816
850
|
) : null}
|
|
817
851
|
</>
|
|
818
852
|
)}
|
|
819
|
-
className="min-w-0"
|
|
853
|
+
className="min-w-0 px-2"
|
|
820
854
|
/>
|
|
821
855
|
) : (
|
|
822
856
|
<ChatHistoryRail
|
|
@@ -883,7 +917,7 @@ function DispatchChatsSection({
|
|
|
883
917
|
) : null}
|
|
884
918
|
</>
|
|
885
919
|
)}
|
|
886
|
-
className="min-w-0"
|
|
920
|
+
className={cn("min-w-0", chatFirstMode && "px-2")}
|
|
887
921
|
/>
|
|
888
922
|
)}
|
|
889
923
|
</div>
|
|
@@ -904,6 +938,8 @@ export function NavContent({
|
|
|
904
938
|
chatFirstAppsLoading = false,
|
|
905
939
|
chatFirstAppsError,
|
|
906
940
|
chatFirstActiveAppId,
|
|
941
|
+
chatFirstActivePrimaryTab,
|
|
942
|
+
onChatFirstNewChat,
|
|
907
943
|
onChatFirstAppOpen,
|
|
908
944
|
onChatFirstAppsRetry,
|
|
909
945
|
}: {
|
|
@@ -920,6 +956,8 @@ export function NavContent({
|
|
|
920
956
|
chatFirstAppsLoading?: boolean;
|
|
921
957
|
chatFirstAppsError?: string | null;
|
|
922
958
|
chatFirstActiveAppId?: string;
|
|
959
|
+
chatFirstActivePrimaryTab?: ChatFirstPrimaryTab;
|
|
960
|
+
onChatFirstNewChat?: () => void;
|
|
923
961
|
onChatFirstAppOpen?: (app: ChatFirstAppItem) => void;
|
|
924
962
|
onChatFirstAppsRetry?: () => void;
|
|
925
963
|
}) {
|
|
@@ -1219,6 +1257,8 @@ export function NavContent({
|
|
|
1219
1257
|
chatFirstMode
|
|
1220
1258
|
chatFirstEmbedded={chatFirstEmbedded}
|
|
1221
1259
|
chatFirstNavigation={{
|
|
1260
|
+
activeTab: chatFirstActivePrimaryTab,
|
|
1261
|
+
onNewChat: onChatFirstNewChat,
|
|
1222
1262
|
onOpenIntegrations: () => {
|
|
1223
1263
|
navigate(dispatchNavLinkTarget("/admin/integrations"));
|
|
1224
1264
|
onNavigate?.();
|
|
@@ -1307,6 +1347,12 @@ export function Layout({
|
|
|
1307
1347
|
const chatFirstMode =
|
|
1308
1348
|
extensions?.chatFirst === true || chatFirstPreference || chatFirstEmbedded;
|
|
1309
1349
|
const chatFirstHasActiveChat = chatFirstSurfaceScope !== "new";
|
|
1350
|
+
useEffect(() => {
|
|
1351
|
+
if (!chatFirstMode || chatFirstEmbedded || localPathname !== "/overview") {
|
|
1352
|
+
return;
|
|
1353
|
+
}
|
|
1354
|
+
navigate(dispatchNavLinkTarget("/chat"), { replace: true });
|
|
1355
|
+
}, [chatFirstEmbedded, chatFirstMode, localPathname, navigate]);
|
|
1310
1356
|
const [chatFirstAppLayout, setChatFirstAppLayout] =
|
|
1311
1357
|
useState<ChatFirstAppLayoutPreference>(() => readChatFirstAppLayout());
|
|
1312
1358
|
const chatFirstAppLayoutHydratedRef = useRef(false);
|
|
@@ -1371,6 +1417,7 @@ export function Layout({
|
|
|
1371
1417
|
null,
|
|
1372
1418
|
);
|
|
1373
1419
|
const [chatFirstEmbedAttempt, setChatFirstEmbedAttempt] = useState(0);
|
|
1420
|
+
const chatFirstAppFrameRef = useRef<HTMLIFrameElement>(null);
|
|
1374
1421
|
const [chatFirstNotice, setChatFirstNotice] = useState<string | null>(null);
|
|
1375
1422
|
const chatFirstSessionWatch = useChatFirstSessionWatch();
|
|
1376
1423
|
const chatFirstSurfaceTabs = useChatFirstSurfaceTabs(chatFirstSurfaceScope);
|
|
@@ -1410,6 +1457,19 @@ export function Layout({
|
|
|
1410
1457
|
isChatRoute &&
|
|
1411
1458
|
activeChatFirstSurfaceTab?.kind === "app" &&
|
|
1412
1459
|
activeChatFirstSurfaceTab.placement === "main";
|
|
1460
|
+
const chatFirstAppSelected =
|
|
1461
|
+
chatFirstMode && activeChatFirstSurfaceTab?.kind === "app";
|
|
1462
|
+
const chatFirstActivePrimaryTab = chatFirstAppSelected
|
|
1463
|
+
? activeChatFirstSurfaceTab?.kind === "app" &&
|
|
1464
|
+
activeChatFirstSurfaceTab.appId === "dispatch"
|
|
1465
|
+
? chatFirstPrimaryTabForPath(activeChatFirstSurfaceTab.path ?? "")
|
|
1466
|
+
: undefined
|
|
1467
|
+
: chatFirstPrimaryTabForPath(localPathname);
|
|
1468
|
+
const chatFirstActiveAppId = isWorkspaceAppRoute
|
|
1469
|
+
? (workspaceAppIdFromRoute(localPathname) ?? undefined)
|
|
1470
|
+
: chatFirstAppSelected && activeChatFirstSurfaceTab?.kind === "app"
|
|
1471
|
+
? activeChatFirstSurfaceTab.appId
|
|
1472
|
+
: undefined;
|
|
1413
1473
|
const activeChatFirstAppRegistration = useMemo(
|
|
1414
1474
|
() =>
|
|
1415
1475
|
activeChatFirstSurfaceTab?.kind === "app" &&
|
|
@@ -1496,6 +1556,25 @@ export function Layout({
|
|
|
1496
1556
|
createChatFirstEmbedSession.mutateAsync,
|
|
1497
1557
|
isChatRoute,
|
|
1498
1558
|
]);
|
|
1559
|
+
|
|
1560
|
+
useEffect(() => {
|
|
1561
|
+
if (!chatFirstMode || !isChatRoute || !activeChatFirstApp) return;
|
|
1562
|
+
|
|
1563
|
+
const handleEmbedSessionExpired = (event: MessageEvent) => {
|
|
1564
|
+
if (
|
|
1565
|
+
event.data?.type !== "agentNative.embedSessionExpired" ||
|
|
1566
|
+
event.source !== chatFirstAppFrameRef.current?.contentWindow
|
|
1567
|
+
) {
|
|
1568
|
+
return;
|
|
1569
|
+
}
|
|
1570
|
+
setChatFirstEmbedAttempt((attempt) => attempt + 1);
|
|
1571
|
+
};
|
|
1572
|
+
|
|
1573
|
+
window.addEventListener("message", handleEmbedSessionExpired);
|
|
1574
|
+
return () =>
|
|
1575
|
+
window.removeEventListener("message", handleEmbedSessionExpired);
|
|
1576
|
+
}, [activeChatFirstApp, chatFirstMode, isChatRoute]);
|
|
1577
|
+
|
|
1499
1578
|
const persistChatFirstPane = useCallback(
|
|
1500
1579
|
(pane: DispatchChatFirstPane | null) => {
|
|
1501
1580
|
setChatFirstPane(pane);
|
|
@@ -1507,6 +1586,17 @@ export function Layout({
|
|
|
1507
1586
|
},
|
|
1508
1587
|
[],
|
|
1509
1588
|
);
|
|
1589
|
+
useEffect(() => {
|
|
1590
|
+
if (!chatFirstMode || isChatRoute) return;
|
|
1591
|
+
persistChatFirstPane(null);
|
|
1592
|
+
closeChatFirstSessionWatch();
|
|
1593
|
+
chatFirstSurfaceTabsStore.closeAll();
|
|
1594
|
+
}, [
|
|
1595
|
+
chatFirstMode,
|
|
1596
|
+
chatFirstSurfaceTabsStore,
|
|
1597
|
+
isChatRoute,
|
|
1598
|
+
persistChatFirstPane,
|
|
1599
|
+
]);
|
|
1510
1600
|
const openChatFirstPane = useCallback(
|
|
1511
1601
|
(
|
|
1512
1602
|
pane: DispatchChatFirstPane,
|
|
@@ -2023,6 +2113,7 @@ export function Layout({
|
|
|
2023
2113
|
data-dispatch-chat-first-app-frame
|
|
2024
2114
|
src={url}
|
|
2025
2115
|
title={title ?? chatFirstCopy("appUnavailable")}
|
|
2116
|
+
ref={chatFirstAppFrameRef}
|
|
2026
2117
|
referrerPolicy="no-referrer"
|
|
2027
2118
|
allow="clipboard-read; clipboard-write"
|
|
2028
2119
|
className="h-full w-full border-0 bg-background"
|
|
@@ -2305,13 +2396,15 @@ export function Layout({
|
|
|
2305
2396
|
? chatFirstCopy("appsLoadError")
|
|
2306
2397
|
: null
|
|
2307
2398
|
}
|
|
2308
|
-
chatFirstActiveAppId={
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2399
|
+
chatFirstActiveAppId={chatFirstActiveAppId}
|
|
2400
|
+
chatFirstActivePrimaryTab={chatFirstActivePrimaryTab}
|
|
2401
|
+
onChatFirstNewChat={() => {
|
|
2402
|
+
closeChatFirstSessionWatch();
|
|
2403
|
+
chatFirstSurfaceTabsStore.closeAll();
|
|
2404
|
+
setChatFirstSurfacePanelOpen(false);
|
|
2405
|
+
}}
|
|
2313
2406
|
onChatFirstAppOpen={(app) =>
|
|
2314
|
-
|
|
2407
|
+
navigate(dispatchNavLinkTarget(workspaceAppRoute(app.id)))
|
|
2315
2408
|
}
|
|
2316
2409
|
onChatFirstAppsRetry={() => void chatFirstAppsQuery.refetch()}
|
|
2317
2410
|
collapsible
|
|
@@ -2345,13 +2438,15 @@ export function Layout({
|
|
|
2345
2438
|
? chatFirstCopy("appsLoadError")
|
|
2346
2439
|
: null
|
|
2347
2440
|
}
|
|
2348
|
-
chatFirstActiveAppId={
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2441
|
+
chatFirstActiveAppId={chatFirstActiveAppId}
|
|
2442
|
+
chatFirstActivePrimaryTab={chatFirstActivePrimaryTab}
|
|
2443
|
+
onChatFirstNewChat={() => {
|
|
2444
|
+
closeChatFirstSessionWatch();
|
|
2445
|
+
chatFirstSurfaceTabsStore.closeAll();
|
|
2446
|
+
setChatFirstSurfacePanelOpen(false);
|
|
2447
|
+
}}
|
|
2353
2448
|
onChatFirstAppOpen={(app) =>
|
|
2354
|
-
|
|
2449
|
+
navigate(dispatchNavLinkTarget(workspaceAppRoute(app.id)))
|
|
2355
2450
|
}
|
|
2356
2451
|
onChatFirstAppsRetry={() => void chatFirstAppsQuery.refetch()}
|
|
2357
2452
|
onNavigate={() => setMobileOpen(false)}
|
|
@@ -5,6 +5,7 @@ import { Link, useLocation } from "react-router";
|
|
|
5
5
|
|
|
6
6
|
import { cn } from "../../lib/utils";
|
|
7
7
|
import {
|
|
8
|
+
workspaceAppIdFromRoute,
|
|
8
9
|
workspaceAppRoute,
|
|
9
10
|
workspaceAppHref,
|
|
10
11
|
type WorkspaceAppSummary,
|
|
@@ -12,32 +13,8 @@ import {
|
|
|
12
13
|
import { AppIcon } from "../app-icon";
|
|
13
14
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
|
|
14
15
|
|
|
15
|
-
function pathFromValue(value: string | null | undefined): string | null {
|
|
16
|
-
const trimmed = value?.trim();
|
|
17
|
-
if (!trimmed) return null;
|
|
18
|
-
|
|
19
|
-
try {
|
|
20
|
-
const pathname = new URL(trimmed, "https://dispatch.local").pathname;
|
|
21
|
-
return pathname.replace(/\/+$/, "") || "/";
|
|
22
|
-
} catch {
|
|
23
|
-
// coercion-ok: malformed app URLs cannot match a workspace route.
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
16
|
function appMatchesPath(app: WorkspaceAppSummary, pathname: string): boolean {
|
|
29
|
-
|
|
30
|
-
if (pathname === appRoute || pathname.startsWith(`${appRoute}/`)) {
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const candidatePaths = [app.path, app.url]
|
|
35
|
-
.map(pathFromValue)
|
|
36
|
-
.filter((path): path is string => !!path);
|
|
37
|
-
|
|
38
|
-
return candidatePaths.some(
|
|
39
|
-
(path) => pathname === path || pathname.startsWith(`${path}/`),
|
|
40
|
-
);
|
|
17
|
+
return workspaceAppIdFromRoute(pathname) === app.id;
|
|
41
18
|
}
|
|
42
19
|
|
|
43
20
|
function appLabel(app: WorkspaceAppSummary): string {
|
|
@@ -62,21 +62,21 @@ describe("WorkspaceAppCard", () => {
|
|
|
62
62
|
});
|
|
63
63
|
|
|
64
64
|
const appLink = container.querySelector<HTMLAnchorElement>(
|
|
65
|
-
'a[href="/
|
|
65
|
+
'a[href="/analytics"]',
|
|
66
66
|
);
|
|
67
67
|
expect(appLink).not.toBeNull();
|
|
68
68
|
expect(appLink?.textContent).toContain("Open app");
|
|
69
|
-
expect(appLink?.
|
|
70
|
-
expect(appLink?.getAttribute("
|
|
71
|
-
expect(appLink?.getAttribute("rel")).toBeNull();
|
|
69
|
+
expect(appLink?.getAttribute("target")).toBe("_blank");
|
|
70
|
+
expect(appLink?.getAttribute("rel")).toBe("noreferrer");
|
|
72
71
|
expect(appLink?.querySelector("svg")).toBeNull();
|
|
73
|
-
expect(container.textContent).not.toContain("/apps/analytics");
|
|
74
72
|
|
|
75
73
|
expect(
|
|
76
74
|
container.querySelector(
|
|
77
75
|
'button[aria-label="Open options for Analytics"]',
|
|
78
76
|
),
|
|
79
|
-
).toBeNull();
|
|
77
|
+
).not.toBeNull();
|
|
78
|
+
expect(document.body.textContent).not.toContain("Open in new tab");
|
|
79
|
+
expect(document.body.textContent).not.toContain("Add app");
|
|
80
80
|
|
|
81
81
|
const settingsButton = container.querySelector<HTMLButtonElement>(
|
|
82
82
|
'button[aria-label="Settings for Analytics"]',
|
|
@@ -25,7 +25,6 @@ import { toast } from "sonner";
|
|
|
25
25
|
|
|
26
26
|
import { cn } from "../lib/utils";
|
|
27
27
|
import {
|
|
28
|
-
isPendingBuilderHref,
|
|
29
28
|
workspaceAppHref,
|
|
30
29
|
workspaceAppRoute,
|
|
31
30
|
type WorkspaceAppSummary,
|
|
@@ -276,7 +275,6 @@ function WorkspaceAppOpenActions({
|
|
|
276
275
|
href: string | null;
|
|
277
276
|
}) {
|
|
278
277
|
const navigate = useNavigate();
|
|
279
|
-
const openInNewTab = isPendingBuilderHref(app);
|
|
280
278
|
const appRoute = workspaceAppRoute(app.id);
|
|
281
279
|
|
|
282
280
|
if (!href) {
|
|
@@ -290,14 +288,13 @@ function WorkspaceAppOpenActions({
|
|
|
290
288
|
return (
|
|
291
289
|
<AppOpenActions
|
|
292
290
|
name={app.name}
|
|
293
|
-
href={
|
|
294
|
-
target=
|
|
295
|
-
rel=
|
|
296
|
-
showInlineOption
|
|
291
|
+
href={href}
|
|
292
|
+
target="_blank"
|
|
293
|
+
rel="noreferrer"
|
|
294
|
+
showInlineOption
|
|
297
295
|
onOpenInline={() => {
|
|
298
296
|
navigate(appRoute);
|
|
299
297
|
}}
|
|
300
|
-
showNewTabOption={openInNewTab}
|
|
301
298
|
/>
|
|
302
299
|
);
|
|
303
300
|
}
|