@agent-native/dispatch 0.23.5 → 0.24.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/list-connected-agents.d.ts +1 -0
- package/dist/actions/list-connected-agents.js +5 -1
- package/dist/actions/list-connected-agents.js.map +1 -1
- package/dist/actions/list-dispatch-usage-metrics.d.ts +2 -0
- package/dist/actions/list-dispatch-usage-metrics.js +11 -1
- package/dist/actions/list-dispatch-usage-metrics.js.map +1 -1
- package/dist/actions/provider-api-register.d.ts +12 -12
- package/dist/actions/remix-workspace-template.js +4 -3
- package/dist/actions/remix-workspace-template.js.map +1 -1
- package/dist/actions/scaffold-workspace-app.js +3 -2
- package/dist/actions/scaffold-workspace-app.js.map +1 -1
- package/dist/actions/start-workspace-app-creation.js +3 -2
- package/dist/actions/start-workspace-app-creation.js.map +1 -1
- package/dist/actions/view-screen.js +11 -1
- package/dist/actions/view-screen.js.map +1 -1
- package/dist/components/admin-navigation.d.ts.map +1 -1
- package/dist/components/admin-navigation.js +21 -5
- package/dist/components/admin-navigation.js.map +1 -1
- package/dist/components/app-icon.js +1 -1
- package/dist/components/app-icon.js.map +1 -1
- package/dist/components/app-list-row.d.ts +1 -1
- package/dist/components/app-list-row.d.ts.map +1 -1
- package/dist/components/app-list-row.js +1 -1
- package/dist/components/app-list-row.js.map +1 -1
- package/dist/components/app-open-actions.d.ts +1 -17
- package/dist/components/app-open-actions.d.ts.map +1 -1
- package/dist/components/app-open-actions.js +1 -20
- package/dist/components/app-open-actions.js.map +1 -1
- package/dist/components/app-row-settings.d.ts +6 -0
- package/dist/components/app-row-settings.d.ts.map +1 -0
- package/dist/components/app-row-settings.js +11 -0
- package/dist/components/app-row-settings.js.map +1 -0
- package/dist/components/automation-run-history-dialog.d.ts.map +1 -1
- package/dist/components/automation-run-history-dialog.js +3 -2
- package/dist/components/automation-run-history-dialog.js.map +1 -1
- package/dist/components/connected-app-card.d.ts.map +1 -1
- package/dist/components/connected-app-card.js +3 -2
- package/dist/components/connected-app-card.js.map +1 -1
- package/dist/components/create-app-popover.js +2 -2
- package/dist/components/create-app-popover.js.map +1 -1
- package/dist/components/dispatch-control-plane.d.ts.map +1 -1
- package/dist/components/dispatch-control-plane.js +23 -7
- package/dist/components/dispatch-control-plane.js.map +1 -1
- package/dist/components/dispatch-shell.d.ts.map +1 -1
- package/dist/components/dispatch-shell.js +5 -1
- package/dist/components/dispatch-shell.js.map +1 -1
- package/dist/components/docs-link.d.ts +16 -0
- package/dist/components/docs-link.d.ts.map +1 -0
- package/dist/components/docs-link.js +34 -0
- package/dist/components/docs-link.js.map +1 -0
- package/dist/components/layout/Layout.d.ts +1 -0
- package/dist/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +43 -35
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/messaging-setup-panel.d.ts.map +1 -1
- package/dist/components/messaging-setup-panel.js +3 -2
- package/dist/components/messaging-setup-panel.js.map +1 -1
- package/dist/components/usage-alerts-panel.d.ts +11 -0
- package/dist/components/usage-alerts-panel.d.ts.map +1 -0
- package/dist/components/usage-alerts-panel.js +125 -0
- package/dist/components/usage-alerts-panel.js.map +1 -0
- package/dist/components/workspace-app-card.d.ts +3 -1
- package/dist/components/workspace-app-card.d.ts.map +1 -1
- package/dist/components/workspace-app-card.js +70 -29
- package/dist/components/workspace-app-card.js.map +1 -1
- package/dist/components/workspace-app-search.d.ts +10 -0
- package/dist/components/workspace-app-search.d.ts.map +1 -0
- package/dist/components/workspace-app-search.js +27 -0
- package/dist/components/workspace-app-search.js.map +1 -0
- package/dist/components/workspace-resource-effective-stack.d.ts.map +1 -1
- package/dist/components/workspace-resource-effective-stack.js +3 -2
- package/dist/components/workspace-resource-effective-stack.js.map +1 -1
- package/dist/components/workspace-template-card.d.ts.map +1 -1
- package/dist/components/workspace-template-card.js +10 -15
- package/dist/components/workspace-template-card.js.map +1 -1
- package/dist/hooks/use-navigation-state.d.ts +2 -0
- package/dist/hooks/use-navigation-state.d.ts.map +1 -1
- package/dist/hooks/use-navigation-state.js +10 -0
- package/dist/hooks/use-navigation-state.js.map +1 -1
- package/dist/lib/embed-session-recovery.d.ts +3 -0
- package/dist/lib/embed-session-recovery.d.ts.map +1 -0
- package/dist/lib/embed-session-recovery.js +18 -0
- package/dist/lib/embed-session-recovery.js.map +1 -0
- package/dist/lib/other-apps.d.ts +2 -0
- package/dist/lib/other-apps.d.ts.map +1 -1
- package/dist/lib/other-apps.js.map +1 -1
- package/dist/lib/workspace-app-layout.d.ts +19 -0
- package/dist/lib/workspace-app-layout.d.ts.map +1 -0
- package/dist/lib/workspace-app-layout.js +75 -0
- package/dist/lib/workspace-app-layout.js.map +1 -0
- package/dist/lib/workspace-apps.d.ts +14 -0
- package/dist/lib/workspace-apps.d.ts.map +1 -1
- package/dist/lib/workspace-apps.js +66 -0
- package/dist/lib/workspace-apps.js.map +1 -1
- package/dist/lib/workspace-apps.test.d.ts +2 -0
- package/dist/lib/workspace-apps.test.d.ts.map +1 -0
- package/dist/lib/workspace-apps.test.js +33 -0
- package/dist/lib/workspace-apps.test.js.map +1 -0
- package/dist/routes/pages/$appId.d.ts.map +1 -1
- package/dist/routes/pages/$appId.js +4 -2
- package/dist/routes/pages/$appId.js.map +1 -1
- package/dist/routes/pages/agents.d.ts.map +1 -1
- package/dist/routes/pages/agents.js +2 -3
- package/dist/routes/pages/agents.js.map +1 -1
- package/dist/routes/pages/apps.$appId.d.ts.map +1 -1
- package/dist/routes/pages/apps.$appId.js +17 -13
- package/dist/routes/pages/apps.$appId.js.map +1 -1
- package/dist/routes/pages/apps.d.ts.map +1 -1
- package/dist/routes/pages/apps.js +31 -16
- package/dist/routes/pages/apps.js.map +1 -1
- package/dist/routes/pages/audit.d.ts.map +1 -1
- package/dist/routes/pages/audit.js +2 -1
- package/dist/routes/pages/audit.js.map +1 -1
- package/dist/routes/pages/chat.d.ts.map +1 -1
- package/dist/routes/pages/chat.js +7 -2
- package/dist/routes/pages/chat.js.map +1 -1
- package/dist/routes/pages/dreams.d.ts.map +1 -1
- package/dist/routes/pages/dreams.js +14 -18
- package/dist/routes/pages/dreams.js.map +1 -1
- package/dist/routes/pages/integrations.d.ts.map +1 -1
- package/dist/routes/pages/integrations.js +51 -14
- package/dist/routes/pages/integrations.js.map +1 -1
- package/dist/routes/pages/metrics.d.ts.map +1 -1
- package/dist/routes/pages/metrics.js +146 -17
- package/dist/routes/pages/metrics.js.map +1 -1
- package/dist/routes/pages/operations.js +1 -1
- package/dist/routes/pages/operations.js.map +1 -1
- package/dist/routes/pages/settings.d.ts.map +1 -1
- package/dist/routes/pages/settings.js +19 -2
- package/dist/routes/pages/settings.js.map +1 -1
- package/dist/routes/pages/thread-debug.d.ts.map +1 -1
- package/dist/routes/pages/thread-debug.js +5 -8
- package/dist/routes/pages/thread-debug.js.map +1 -1
- package/dist/routes/pages/vault.d.ts.map +1 -1
- package/dist/routes/pages/vault.js +1 -1
- package/dist/routes/pages/vault.js.map +1 -1
- package/dist/routes/pages/workspace.d.ts.map +1 -1
- package/dist/routes/pages/workspace.js +13 -10
- package/dist/routes/pages/workspace.js.map +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/app-creation-store.d.ts.map +1 -1
- package/dist/server/lib/app-creation-store.js +12 -52
- package/dist/server/lib/app-creation-store.js.map +1 -1
- package/dist/server/lib/usage-metrics-store.d.ts +17 -0
- package/dist/server/lib/usage-metrics-store.d.ts.map +1 -1
- package/dist/server/lib/usage-metrics-store.js +187 -30
- package/dist/server/lib/usage-metrics-store.js.map +1 -1
- package/dist/server/plugins/agent-chat.js +2 -0
- package/dist/server/plugins/agent-chat.js.map +1 -1
- package/dist/server/plugins/integrations.d.ts.map +1 -1
- package/dist/server/plugins/integrations.js +1 -0
- package/dist/server/plugins/integrations.js.map +1 -1
- package/dist/shared/app-roles.d.ts +9 -0
- package/dist/shared/app-roles.d.ts.map +1 -0
- package/dist/shared/app-roles.js +7 -0
- package/dist/shared/app-roles.js.map +1 -0
- package/package.json +4 -3
- package/src/actions/list-connected-agents.spec.ts +73 -0
- package/src/actions/list-connected-agents.ts +6 -2
- package/src/actions/list-dispatch-usage-metrics.ts +11 -1
- package/src/actions/remix-workspace-template.spec.ts +29 -0
- package/src/actions/remix-workspace-template.ts +13 -6
- package/src/actions/scaffold-workspace-app.ts +12 -5
- package/src/actions/start-workspace-app-creation.ts +8 -2
- package/src/actions/view-screen.ts +13 -1
- package/src/components/admin-navigation.tsx +57 -11
- package/src/components/app-icon.spec.tsx +34 -0
- package/src/components/app-icon.tsx +1 -1
- package/src/components/app-list-row.tsx +1 -2
- package/src/components/app-open-actions.tsx +5 -114
- package/src/components/app-row-settings.tsx +54 -0
- package/src/components/automation-run-history-dialog.tsx +8 -4
- package/src/components/connected-app-card.tsx +3 -2
- package/src/components/create-app-popover.spec.tsx +1 -1
- package/src/components/create-app-popover.tsx +2 -2
- package/src/components/dispatch-control-plane.spec.tsx +44 -3
- package/src/components/dispatch-control-plane.tsx +83 -27
- package/src/components/dispatch-shell.tsx +7 -1
- package/src/components/docs-link.tsx +52 -0
- package/src/components/layout/Layout.spec.tsx +13 -0
- package/src/components/layout/Layout.tsx +63 -32
- package/src/components/messaging-setup-panel.tsx +10 -3
- package/src/components/usage-alerts-panel.tsx +445 -0
- package/src/components/workspace-app-card.spec.tsx +130 -9
- package/src/components/workspace-app-card.tsx +128 -71
- package/src/components/workspace-app-search.tsx +96 -0
- package/src/components/workspace-resource-effective-stack.tsx +10 -5
- package/src/components/workspace-template-card.spec.tsx +53 -24
- package/src/components/workspace-template-card.tsx +16 -26
- package/src/hooks/use-navigation-state.ts +12 -0
- package/src/lib/embed-session-recovery.spec.ts +63 -0
- package/src/lib/embed-session-recovery.ts +26 -0
- package/src/lib/other-apps.ts +2 -0
- package/src/lib/workspace-app-layout.spec.ts +47 -0
- package/src/lib/workspace-app-layout.ts +121 -0
- package/src/lib/workspace-apps.test.ts +64 -0
- package/src/lib/workspace-apps.ts +82 -0
- package/src/routes/pages/$appId.tsx +3 -6
- package/src/routes/pages/agents.tsx +6 -3
- package/src/routes/pages/apps.$appId.tsx +16 -17
- package/src/routes/pages/apps.tsx +116 -62
- package/src/routes/pages/audit.tsx +28 -8
- package/src/routes/pages/chat.spec.tsx +10 -0
- package/src/routes/pages/chat.tsx +8 -0
- package/src/routes/pages/dreams.tsx +92 -142
- package/src/routes/pages/integrations.tsx +147 -68
- package/src/routes/pages/metrics.tsx +460 -102
- package/src/routes/pages/operations.tsx +2 -2
- package/src/routes/pages/settings.tsx +27 -10
- package/src/routes/pages/thread-debug.tsx +18 -36
- package/src/routes/pages/vault.tsx +7 -2
- package/src/routes/pages/workspace.tsx +92 -56
- package/src/server/index.ts +4 -0
- package/src/server/lib/app-creation-store.spec.ts +90 -43
- package/src/server/lib/app-creation-store.ts +15 -61
- package/src/server/lib/usage-metrics-store.spec.ts +117 -0
- package/src/server/lib/usage-metrics-store.ts +249 -30
- package/src/server/plugins/agent-chat.spec.ts +4 -0
- package/src/server/plugins/agent-chat.ts +2 -0
- package/src/server/plugins/integrations.ts +1 -0
- package/src/shared/app-roles.ts +8 -0
- package/src/styles/dispatch.css +9 -0
|
@@ -37,6 +37,72 @@ export function workspaceAppHref(app) {
|
|
|
37
37
|
}
|
|
38
38
|
return app.path || app.url || null;
|
|
39
39
|
}
|
|
40
|
+
export function workspaceAppEmbedTarget(app) {
|
|
41
|
+
const url = app.url?.trim();
|
|
42
|
+
if (url)
|
|
43
|
+
return { url };
|
|
44
|
+
const path = app.path.trim();
|
|
45
|
+
return path.startsWith("/") ? { path } : path ? { url: path } : {};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Resolve an app route without an embed ticket so the target can render its
|
|
49
|
+
* own error document when session setup fails.
|
|
50
|
+
*/
|
|
51
|
+
export function workspaceAppDirectHref(app, targetPath) {
|
|
52
|
+
const target = targetPath.trim();
|
|
53
|
+
if (!target || !target.startsWith("/") || target.startsWith("//")) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
let targetUrl;
|
|
57
|
+
try {
|
|
58
|
+
targetUrl = new URL(target, "https://agent-native.invalid");
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// coercion-ok: invalid relative target input has no safe href.
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
const targetPathname = targetUrl.pathname || "/";
|
|
65
|
+
let absoluteBase = null;
|
|
66
|
+
const rawUrl = app.url?.trim();
|
|
67
|
+
if (rawUrl) {
|
|
68
|
+
try {
|
|
69
|
+
const parsedBase = new URL(rawUrl);
|
|
70
|
+
if (parsedBase.protocol === "http:" || parsedBase.protocol === "https:") {
|
|
71
|
+
absoluteBase = parsedBase;
|
|
72
|
+
}
|
|
73
|
+
// coercion-ok: invalid app URLs use the mounted path fallback below.
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
absoluteBase = null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const mountedPath = app.path?.trim();
|
|
80
|
+
const basePath = absoluteBase
|
|
81
|
+
? absoluteBase.pathname
|
|
82
|
+
: mountedPath
|
|
83
|
+
? `/${mountedPath.replace(/^[/\\]+/, "").split(/[?#]/, 1)[0]}`
|
|
84
|
+
: null;
|
|
85
|
+
if (!basePath)
|
|
86
|
+
return null;
|
|
87
|
+
const normalizedBasePath = basePath.replace(/\/+$/, "") || "/";
|
|
88
|
+
const targetIsMountedPath = normalizedBasePath !== "/" &&
|
|
89
|
+
(targetPathname === normalizedBasePath ||
|
|
90
|
+
targetPathname.startsWith(`${normalizedBasePath}/`));
|
|
91
|
+
const resolvedPath = targetIsMountedPath
|
|
92
|
+
? targetPathname
|
|
93
|
+
: normalizedBasePath === "/"
|
|
94
|
+
? targetPathname
|
|
95
|
+
: targetPathname === "/"
|
|
96
|
+
? normalizedBasePath
|
|
97
|
+
: `${normalizedBasePath}/${targetPathname.replace(/^\/+/, "")}`;
|
|
98
|
+
if (absoluteBase) {
|
|
99
|
+
absoluteBase.pathname = resolvedPath;
|
|
100
|
+
absoluteBase.search = targetUrl.search;
|
|
101
|
+
absoluteBase.hash = targetUrl.hash;
|
|
102
|
+
return absoluteBase.toString();
|
|
103
|
+
}
|
|
104
|
+
return `${resolvedPath}${targetUrl.search}${targetUrl.hash}`;
|
|
105
|
+
}
|
|
40
106
|
export function isPendingBuilderHref(app) {
|
|
41
107
|
return app.status === "pending" && !!app.builderUrl;
|
|
42
108
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-apps.js","sourceRoot":"","sources":["../../src/lib/workspace-apps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAClF,OAAO,EAAE,4BAA4B,EAAE,MAAM,iDAAiD,CAAC;
|
|
1
|
+
{"version":3,"file":"workspace-apps.js","sourceRoot":"","sources":["../../src/lib/workspace-apps.ts"],"names":[],"mappings":"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","sourcesContent":["import { CHAT_FIRST_DEFAULT_APP_IDS } from \"@agent-native/core/client/chat-first\";\nimport { withBuilderUtmTrackingParams } from \"@agent-native/core/shared/builder-link-tracking\";\n\nexport interface WorkspaceAppSummary {\n id: string;\n name: string;\n description?: string;\n path: string;\n url?: string | null;\n isDispatch?: boolean;\n audience?: \"internal\" | \"public\";\n publicPaths?: string[];\n protectedPaths?: string[];\n status?: \"ready\" | \"pending\";\n statusLabel?: string;\n builderUrl?: string | null;\n branchName?: string | null;\n createdAt?: string | null;\n createdBy?: string | null;\n owner?: string | null;\n teams?: string[];\n agentCardUrl?: string | null;\n agentCardReachable?: boolean;\n a2aEndpointUrl?: string | null;\n agentName?: string | null;\n agentSkillsCount?: number | null;\n archived?: boolean;\n}\n\ninterface WorkspaceAppHrefSource {\n path?: string | null;\n url?: string | null;\n}\n\nexport function isDispatchWorkspaceAppId(appId: string): boolean {\n return appId.trim().toLowerCase() === \"dispatch\";\n}\n\nexport function isDefaultWorkspaceAppHiddenId(appId: string): boolean {\n const normalized = appId.trim().toLowerCase();\n return normalized === \"chat\" || isDispatchWorkspaceAppId(normalized);\n}\n\nexport function isWorkspaceAppVisibleInDefaultLaunchers(\n app: Pick<WorkspaceAppSummary, \"id\" | \"isDispatch\">,\n): boolean {\n return !app.isDispatch && !isDefaultWorkspaceAppHiddenId(app.id);\n}\n\nexport function workspaceAppRoute(appId: string): string {\n return `/apps/${encodeURIComponent(appId)}`;\n}\n\nexport function workspaceAppIdFromRoute(pathname: string): string | null {\n const match = pathname.match(/^\\/apps\\/([^/]+)(?:\\/|$)/);\n if (!match) return null;\n try {\n const appId = decodeURIComponent(match[1]).trim();\n return appId || null;\n } catch {\n // coercion-ok: malformed app routes are inactive, not app ids.\n return null;\n }\n}\n\nexport function workspaceAppHref(app: WorkspaceAppSummary): string | null {\n if (app.status === \"pending\") {\n return app.builderUrl\n ? withBuilderUtmTrackingParams(app.builderUrl, {\n campaign: \"product\",\n content: \"dispatch_branch\",\n })\n : null;\n }\n return app.path || app.url || null;\n}\n\nexport function workspaceAppEmbedTarget(\n app: Pick<WorkspaceAppSummary, \"path\" | \"url\">,\n): { path?: string; url?: string } {\n const url = app.url?.trim();\n if (url) return { url };\n\n const path = app.path.trim();\n return path.startsWith(\"/\") ? { path } : path ? { url: path } : {};\n}\n\n/**\n * Resolve an app route without an embed ticket so the target can render its\n * own error document when session setup fails.\n */\nexport function workspaceAppDirectHref(\n app: WorkspaceAppHrefSource,\n targetPath: string,\n): string | null {\n const target = targetPath.trim();\n if (!target || !target.startsWith(\"/\") || target.startsWith(\"//\")) {\n return null;\n }\n\n let targetUrl: URL;\n try {\n targetUrl = new URL(target, \"https://agent-native.invalid\");\n } catch {\n // coercion-ok: invalid relative target input has no safe href.\n return null;\n }\n const targetPathname = targetUrl.pathname || \"/\";\n\n let absoluteBase: URL | null = null;\n const rawUrl = app.url?.trim();\n if (rawUrl) {\n try {\n const parsedBase = new URL(rawUrl);\n if (parsedBase.protocol === \"http:\" || parsedBase.protocol === \"https:\") {\n absoluteBase = parsedBase;\n }\n // coercion-ok: invalid app URLs use the mounted path fallback below.\n } catch {\n absoluteBase = null;\n }\n }\n\n const mountedPath = app.path?.trim();\n const basePath = absoluteBase\n ? absoluteBase.pathname\n : mountedPath\n ? `/${mountedPath.replace(/^[/\\\\]+/, \"\").split(/[?#]/, 1)[0]}`\n : null;\n if (!basePath) return null;\n\n const normalizedBasePath = basePath.replace(/\\/+$/, \"\") || \"/\";\n const targetIsMountedPath =\n normalizedBasePath !== \"/\" &&\n (targetPathname === normalizedBasePath ||\n targetPathname.startsWith(`${normalizedBasePath}/`));\n const resolvedPath = targetIsMountedPath\n ? targetPathname\n : normalizedBasePath === \"/\"\n ? targetPathname\n : targetPathname === \"/\"\n ? normalizedBasePath\n : `${normalizedBasePath}/${targetPathname.replace(/^\\/+/, \"\")}`;\n\n if (absoluteBase) {\n absoluteBase.pathname = resolvedPath;\n absoluteBase.search = targetUrl.search;\n absoluteBase.hash = targetUrl.hash;\n return absoluteBase.toString();\n }\n\n return `${resolvedPath}${targetUrl.search}${targetUrl.hash}`;\n}\n\nexport function isPendingBuilderHref(app: WorkspaceAppSummary): boolean {\n return app.status === \"pending\" && !!app.builderUrl;\n}\n\n/**\n * Keep the chat-first rail useful before a workspace manifest is populated.\n * Mounted workspace rows still win, so custom names and routes remain the\n * source of truth once an app exists in the workspace.\n */\nexport function mergeChatFirstWorkspaceApps(\n apps: readonly WorkspaceAppSummary[] | undefined,\n): WorkspaceAppSummary[] {\n const merged = new Map<string, WorkspaceAppSummary>();\n for (const id of CHAT_FIRST_DEFAULT_APP_IDS) {\n merged.set(id, {\n id,\n name: id.charAt(0).toUpperCase() + id.slice(1),\n path: `/${id}`,\n url: null,\n status: \"ready\",\n });\n }\n for (const app of apps ?? []) merged.set(app.id, app);\n\n return [...merged.values()];\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-apps.test.d.ts","sourceRoot":"","sources":["../../src/lib/workspace-apps.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { workspaceAppDirectHref, workspaceAppEmbedTarget, } from "./workspace-apps.js";
|
|
3
|
+
describe("workspaceAppEmbedTarget", () => {
|
|
4
|
+
it("uses the app URL as the embed root when a mount path is also present", () => {
|
|
5
|
+
expect(workspaceAppEmbedTarget({
|
|
6
|
+
path: "/content",
|
|
7
|
+
url: "https://workspace.example.test/content",
|
|
8
|
+
})).toEqual({ url: "https://workspace.example.test/content" });
|
|
9
|
+
});
|
|
10
|
+
it("falls back to the mounted path when no app URL is available", () => {
|
|
11
|
+
expect(workspaceAppEmbedTarget({ path: "/content", url: null })).toEqual({
|
|
12
|
+
path: "/content",
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
describe("workspaceAppDirectHref", () => {
|
|
17
|
+
it("joins an app-relative route onto an absolute app URL", () => {
|
|
18
|
+
expect(workspaceAppDirectHref({ path: "/atlas", url: "https://workspace.example.test/atlas" }, "/emails?status=failed#latest")).toBe("https://workspace.example.test/atlas/emails?status=failed#latest");
|
|
19
|
+
});
|
|
20
|
+
it("does not duplicate a mount path already present in the target", () => {
|
|
21
|
+
expect(workspaceAppDirectHref({ path: "/atlas", url: "https://workspace.example.test/atlas" }, "/atlas")).toBe("https://workspace.example.test/atlas");
|
|
22
|
+
});
|
|
23
|
+
it("resolves a mounted relative app path", () => {
|
|
24
|
+
expect(workspaceAppDirectHref({ path: "/atlas" }, "/emails")).toBe("/atlas/emails");
|
|
25
|
+
});
|
|
26
|
+
it("falls back to a safe mount path when the app URL is invalid", () => {
|
|
27
|
+
expect(workspaceAppDirectHref({ path: "/atlas", url: "javascript:alert(1)" }, "/")).toBe("/atlas");
|
|
28
|
+
});
|
|
29
|
+
it("rejects an unsafe target path", () => {
|
|
30
|
+
expect(workspaceAppDirectHref({ path: "/atlas" }, "//evil.example")).toBe(null);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=workspace-apps.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-apps.test.js","sourceRoot":"","sources":["../../src/lib/workspace-apps.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EACL,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAE1B,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,CACJ,uBAAuB,CAAC;YACtB,IAAI,EAAE,UAAU;YAChB,GAAG,EAAE,wCAAwC;SAC9C,CAAC,CACH,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,wCAAwC,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YACvE,IAAI,EAAE,UAAU;SACjB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,CACJ,sBAAsB,CACpB,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,sCAAsC,EAAE,EAC/D,8BAA8B,CAC/B,CACF,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,CACJ,sBAAsB,CACpB,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,sCAAsC,EAAE,EAC/D,QAAQ,CACT,CACF,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,sBAAsB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAChE,eAAe,CAChB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,CACJ,sBAAsB,CACpB,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,qBAAqB,EAAE,EAC9C,GAAG,CACJ,CACF,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,sBAAsB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC,IAAI,CACvE,IAAI,CACL,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it } from \"vitest\";\n\nimport {\n workspaceAppDirectHref,\n workspaceAppEmbedTarget,\n} from \"./workspace-apps\";\n\ndescribe(\"workspaceAppEmbedTarget\", () => {\n it(\"uses the app URL as the embed root when a mount path is also present\", () => {\n expect(\n workspaceAppEmbedTarget({\n path: \"/content\",\n url: \"https://workspace.example.test/content\",\n }),\n ).toEqual({ url: \"https://workspace.example.test/content\" });\n });\n\n it(\"falls back to the mounted path when no app URL is available\", () => {\n expect(workspaceAppEmbedTarget({ path: \"/content\", url: null })).toEqual({\n path: \"/content\",\n });\n });\n});\n\ndescribe(\"workspaceAppDirectHref\", () => {\n it(\"joins an app-relative route onto an absolute app URL\", () => {\n expect(\n workspaceAppDirectHref(\n { path: \"/atlas\", url: \"https://workspace.example.test/atlas\" },\n \"/emails?status=failed#latest\",\n ),\n ).toBe(\"https://workspace.example.test/atlas/emails?status=failed#latest\");\n });\n\n it(\"does not duplicate a mount path already present in the target\", () => {\n expect(\n workspaceAppDirectHref(\n { path: \"/atlas\", url: \"https://workspace.example.test/atlas\" },\n \"/atlas\",\n ),\n ).toBe(\"https://workspace.example.test/atlas\");\n });\n\n it(\"resolves a mounted relative app path\", () => {\n expect(workspaceAppDirectHref({ path: \"/atlas\" }, \"/emails\")).toBe(\n \"/atlas/emails\",\n );\n });\n\n it(\"falls back to a safe mount path when the app URL is invalid\", () => {\n expect(\n workspaceAppDirectHref(\n { path: \"/atlas\", url: \"javascript:alert(1)\" },\n \"/\",\n ),\n ).toBe(\"/atlas\");\n });\n\n it(\"rejects an unsafe target path\", () => {\n expect(workspaceAppDirectHref({ path: \"/atlas\" }, \"//evil.example\")).toBe(\n null,\n );\n });\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"$appId.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/$appId.tsx"],"names":[],"mappings":"AAUA,OAAO,EAKL,KAAK,wBAAwB,EAC7B,KAAK,kBAAkB,EACxB,MAAM,cAAc,CAAC;AAatB,wBAAgB,IAAI;;IAEnB;AA2CD,wBAAsB,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,kBAAkB,iBAQ1D;AAED,wBAAsB,YAAY,CAAC,EACjC,MAAM,EACN,YAAY,GACb,EAAE,wBAAwB,oBAS1B;AAED,MAAM,CAAC,OAAO,UAAU,yBAAyB,
|
|
1
|
+
{"version":3,"file":"$appId.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/$appId.tsx"],"names":[],"mappings":"AAUA,OAAO,EAKL,KAAK,wBAAwB,EAC7B,KAAK,kBAAkB,EACxB,MAAM,cAAc,CAAC;AAatB,wBAAgB,IAAI;;IAEnB;AA2CD,wBAAsB,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,kBAAkB,iBAQ1D;AAED,wBAAsB,YAAY,CAAC,EACjC,MAAM,EACN,YAAY,GACb,EAAE,wBAAwB,oBAS1B;AAED,MAAM,CAAC,OAAO,UAAU,yBAAyB,oDAoHhD"}
|
|
@@ -106,9 +106,11 @@ export default function WorkspaceAppCatchAllRoute() {
|
|
|
106
106
|
if ((isLoading && !app) || (app && app.status !== "pending" && href)) {
|
|
107
107
|
return (_jsx("div", { className: "flex h-screen w-full items-center justify-center", children: _jsx(Spinner, { className: "size-8" }) }));
|
|
108
108
|
}
|
|
109
|
-
return (_jsx(DispatchShell, { title: app?.name || t("dispatch.pages.pageNotFound"), description: t("dispatch.pages.pageNotFoundDescription"), children: _jsxs("div", { className: "max-w-2xl rounded-lg bg-card p-5", children: [_jsx(Button, { asChild: true, size: "sm", variant: "ghost", className: "-ml-2 mb-4", children: _jsxs(Link, { to: appPath("/overview"), children: [_jsx(IconArrowLeft, { size: 15, className: "mr-1.5" }), t("dispatch.nav.overview")] }) }), 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.
|
|
109
|
+
return (_jsx(DispatchShell, { title: app?.name || t("dispatch.pages.pageNotFound"), description: t("dispatch.pages.pageNotFoundDescription"), children: _jsxs("div", { className: "max-w-2xl rounded-lg bg-card p-5", children: [_jsx(Button, { asChild: true, size: "sm", variant: "ghost", className: "-ml-2 mb-4", children: _jsxs(Link, { to: appPath("/overview"), children: [_jsx(IconArrowLeft, { size: 15, className: "mr-1.5" }), t("dispatch.nav.overview")] }) }), 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.builderUrl ? (_jsx(Button, { asChild: true, children: _jsxs("a", { href: withBuilderUtmTrackingParams(app.builderUrl, {
|
|
110
110
|
campaign: "product",
|
|
111
111
|
content: "dispatch_branch",
|
|
112
|
-
}), target: "_blank", rel: "noreferrer", children: [t("dispatch.pages.openBuilderBranch"
|
|
112
|
+
}), target: "_blank", rel: "noreferrer", children: [t("dispatch.pages.openBuilderBranch", {
|
|
113
|
+
defaultValue: "Open in Builder",
|
|
114
|
+
}), _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.pageNotFound") }), _jsxs("p", { className: "text-sm text-muted-foreground", children: [_jsxs("span", { className: "font-mono text-foreground", children: ["/", appId] }), " isn't", t("dispatch.pages.notDispatchOrWorkspaceApp")] }), _jsx(Button, { asChild: true, children: _jsx(Link, { to: appPath("/apps"), children: t("dispatch.pages.browseApps") }) })] }))] }) }));
|
|
113
115
|
}
|
|
114
116
|
//# sourceMappingURL=$appId.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"$appId.js","sourceRoot":"","sources":["../../../src/routes/pages/$appId.tsx"],"names":[],"mappings":"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","sourcesContent":["import { appPath } from \"@agent-native/core/client/api-path\";\nimport { useActionQuery } 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 {\n IconArrowLeft,\n IconArrowUpRight,\n IconClockHour4,\n} from \"@tabler/icons-react\";\nimport { useEffect, useMemo } from \"react\";\nimport {\n Link,\n Navigate,\n redirect,\n useParams,\n type ClientLoaderFunctionArgs,\n type LoaderFunctionArgs,\n} from \"react-router\";\n\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { Spinner } from \"../../components/ui/spinner\";\nimport { resolveServerCatchAllTarget } from \"../../lib/catch-all-target\";\nimport {\n workspaceAppHref,\n type WorkspaceAppSummary,\n} from \"../../lib/workspace-apps\";\n\nexport function meta() {\n return [{ title: \"Workspace app - Dispatch\" }];\n}\n\n/**\n * Catch-all for `/dispatch/<segment>` paths that don't match an explicit\n * Dispatch route. When `<segment>` is the id of a workspace app sibling\n * (e.g. `/dispatch/todo` after Builder.io routes a \"navigate to /todo\"\n * call through Dispatch's mount point), bounce to the absolute `/<appId>`\n * so the user lands on the actual app instead of a 404 inside Dispatch.\n *\n * Server-side redirect: we resolve the workspace app manifest via the\n * shared `loadWorkspaceAppsManifest()` helper, which checks the\n * `AGENT_NATIVE_WORKSPACE_APPS_JSON` env var, then the\n * `.agent-native/workspace-apps.json` file written by `workspace-deploy.ts`,\n * then a live filesystem scan of `apps/` for local dev. We then throw\n * `redirect(\"/<appId>\")`. React Router 7 does not prepend the basename to\n * absolute paths returned from a loader, so the redirect escapes Dispatch's\n * `/dispatch` mount cleanly.\n *\n * Why a catch-all instead of fixing the agent prompt: Builder.io currently\n * resolves \"navigate to /todo\" relative to Dispatch's mount, sending the\n * user to /dispatch/todo. The same wrong path then gets captured as the\n * OAuth callbackURL, so Google sign-in completes back at /dispatch/todo\n * and looks broken. This route fixes both the post-creation navigation\n * and the OAuth round-trip from a single place.\n *\n * Built-in template fallback: when no workspace manifest is available\n * (framework dev with each template on its own port, hosted dispatch with\n * no sibling apps), redirect to the matching first-party template's deploy\n * URL — `http://localhost:<devPort>` in dev, `https://<id>.agent-native.com`\n * in production. Without this, a user visiting `/forms` on dispatch is\n * forced to sign in (auth guard) and then lands on this route's \"Page not\n * found\" pane after the post-login reload.\n *\n * `appId === \"dispatch\"` short-circuit: when the segment matches Dispatch\n * itself (e.g. `/dispatch/dispatch`), we go straight to the overview rather\n * than chaining through `/dispatch` (which polled `useActionQuery` re-fired\n * `window.location.assign` against and looped forever in production).\n */\nfunction dispatchSelfRedirect(appId: string | undefined): string | null {\n if (appId === \"dispatch\") return appPath(\"/overview\");\n return null;\n}\n\nexport async function loader({ params }: LoaderFunctionArgs) {\n const appId = params.appId;\n if (!appId) return null;\n const selfTarget = dispatchSelfRedirect(appId);\n if (selfTarget) throw redirect(selfTarget);\n const target = await resolveServerCatchAllTarget(appId);\n if (target) throw redirect(target);\n return null;\n}\n\nexport async function clientLoader({\n params,\n serverLoader,\n}: ClientLoaderFunctionArgs) {\n const selfTarget = dispatchSelfRedirect(params.appId);\n if (selfTarget) throw redirect(selfTarget);\n // Defer to the server loader so the built-in template fallback runs on\n // SPA navigations too (e.g. clicking a `/<template-id>` link inside\n // dispatch). Without this the client side would only check the workspace\n // apps query, which never lists the static first-party templates and so\n // the user would land on the \"Page not found\" pane.\n return serverLoader();\n}\n\nexport default function WorkspaceAppCatchAllRoute() {\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 isSelfReference = appId === \"dispatch\";\n\n useEffect(() => {\n if (isSelfReference) return;\n if (!app || app.status === \"pending\" || !href) return;\n window.location.assign(href);\n }, [app, href, isSelfReference]);\n\n if (isSelfReference) {\n return <Navigate to={appPath(\"/overview\")} replace />;\n }\n\n if (appsQuery.isError) {\n return (\n <DispatchShell\n title={t(\"dispatch.pages.dataLoadFailed\")}\n description={t(\"dispatch.pages.pageNotFoundDescription\")}\n >\n <ActionQueryError\n error={appsQuery.error}\n onRetry={() => void appsQuery.refetch()}\n />\n </DispatchShell>\n );\n }\n\n if ((isLoading && !app) || (app && app.status !== \"pending\" && href)) {\n return (\n <div className=\"flex h-screen w-full items-center justify-center\">\n <Spinner className=\"size-8\" />\n </div>\n );\n }\n\n return (\n <DispatchShell\n title={app?.name || t(\"dispatch.pages.pageNotFound\")}\n description={t(\"dispatch.pages.pageNotFoundDescription\")}\n >\n <div className=\"max-w-2xl rounded-lg bg-card p-5\">\n <Button asChild size=\"sm\" variant=\"ghost\" className=\"-ml-2 mb-4\">\n <Link to={appPath(\"/overview\")}>\n <IconArrowLeft size={15} className=\"mr-1.5\" />\n {t(\"dispatch.nav.overview\")}\n </Link>\n </Button>\n\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\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 <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.pageNotFound\")}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n <span className=\"font-mono text-foreground\">/{appId}</span> isn't\n {t(\"dispatch.pages.notDispatchOrWorkspaceApp\")}\n </p>\n <Button asChild>\n <Link to={appPath(\"/apps\")}>\n {t(\"dispatch.pages.browseApps\")}\n </Link>\n </Button>\n </div>\n )}\n </div>\n </DispatchShell>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"$appId.js","sourceRoot":"","sources":["../../../src/routes/pages/$appId.tsx"],"names":[],"mappings":"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","sourcesContent":["import { appPath } from \"@agent-native/core/client/api-path\";\nimport { useActionQuery } 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 {\n IconArrowLeft,\n IconArrowUpRight,\n IconClockHour4,\n} from \"@tabler/icons-react\";\nimport { useEffect, useMemo } from \"react\";\nimport {\n Link,\n Navigate,\n redirect,\n useParams,\n type ClientLoaderFunctionArgs,\n type LoaderFunctionArgs,\n} from \"react-router\";\n\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { Spinner } from \"../../components/ui/spinner\";\nimport { resolveServerCatchAllTarget } from \"../../lib/catch-all-target\";\nimport {\n workspaceAppHref,\n type WorkspaceAppSummary,\n} from \"../../lib/workspace-apps\";\n\nexport function meta() {\n return [{ title: \"Workspace app - Dispatch\" }];\n}\n\n/**\n * Catch-all for `/dispatch/<segment>` paths that don't match an explicit\n * Dispatch route. When `<segment>` is the id of a workspace app sibling\n * (e.g. `/dispatch/todo` after Builder.io routes a \"navigate to /todo\"\n * call through Dispatch's mount point), bounce to the absolute `/<appId>`\n * so the user lands on the actual app instead of a 404 inside Dispatch.\n *\n * Server-side redirect: we resolve the workspace app manifest via the\n * shared `loadWorkspaceAppsManifest()` helper, which checks the\n * `AGENT_NATIVE_WORKSPACE_APPS_JSON` env var, then the\n * `.agent-native/workspace-apps.json` file written by `workspace-deploy.ts`,\n * then a live filesystem scan of `apps/` for local dev. We then throw\n * `redirect(\"/<appId>\")`. React Router 7 does not prepend the basename to\n * absolute paths returned from a loader, so the redirect escapes Dispatch's\n * `/dispatch` mount cleanly.\n *\n * Why a catch-all instead of fixing the agent prompt: Builder.io currently\n * resolves \"navigate to /todo\" relative to Dispatch's mount, sending the\n * user to /dispatch/todo. The same wrong path then gets captured as the\n * OAuth callbackURL, so Google sign-in completes back at /dispatch/todo\n * and looks broken. This route fixes both the post-creation navigation\n * and the OAuth round-trip from a single place.\n *\n * Built-in template fallback: when no workspace manifest is available\n * (framework dev with each template on its own port, hosted dispatch with\n * no sibling apps), redirect to the matching first-party template's deploy\n * URL — `http://localhost:<devPort>` in dev, `https://<id>.agent-native.com`\n * in production. Without this, a user visiting `/forms` on dispatch is\n * forced to sign in (auth guard) and then lands on this route's \"Page not\n * found\" pane after the post-login reload.\n *\n * `appId === \"dispatch\"` short-circuit: when the segment matches Dispatch\n * itself (e.g. `/dispatch/dispatch`), we go straight to the overview rather\n * than chaining through `/dispatch` (which polled `useActionQuery` re-fired\n * `window.location.assign` against and looped forever in production).\n */\nfunction dispatchSelfRedirect(appId: string | undefined): string | null {\n if (appId === \"dispatch\") return appPath(\"/overview\");\n return null;\n}\n\nexport async function loader({ params }: LoaderFunctionArgs) {\n const appId = params.appId;\n if (!appId) return null;\n const selfTarget = dispatchSelfRedirect(appId);\n if (selfTarget) throw redirect(selfTarget);\n const target = await resolveServerCatchAllTarget(appId);\n if (target) throw redirect(target);\n return null;\n}\n\nexport async function clientLoader({\n params,\n serverLoader,\n}: ClientLoaderFunctionArgs) {\n const selfTarget = dispatchSelfRedirect(params.appId);\n if (selfTarget) throw redirect(selfTarget);\n // Defer to the server loader so the built-in template fallback runs on\n // SPA navigations too (e.g. clicking a `/<template-id>` link inside\n // dispatch). Without this the client side would only check the workspace\n // apps query, which never lists the static first-party templates and so\n // the user would land on the \"Page not found\" pane.\n return serverLoader();\n}\n\nexport default function WorkspaceAppCatchAllRoute() {\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 isSelfReference = appId === \"dispatch\";\n\n useEffect(() => {\n if (isSelfReference) return;\n if (!app || app.status === \"pending\" || !href) return;\n window.location.assign(href);\n }, [app, href, isSelfReference]);\n\n if (isSelfReference) {\n return <Navigate to={appPath(\"/overview\")} replace />;\n }\n\n if (appsQuery.isError) {\n return (\n <DispatchShell\n title={t(\"dispatch.pages.dataLoadFailed\")}\n description={t(\"dispatch.pages.pageNotFoundDescription\")}\n >\n <ActionQueryError\n error={appsQuery.error}\n onRetry={() => void appsQuery.refetch()}\n />\n </DispatchShell>\n );\n }\n\n if ((isLoading && !app) || (app && app.status !== \"pending\" && href)) {\n return (\n <div className=\"flex h-screen w-full items-center justify-center\">\n <Spinner className=\"size-8\" />\n </div>\n );\n }\n\n return (\n <DispatchShell\n title={app?.name || t(\"dispatch.pages.pageNotFound\")}\n description={t(\"dispatch.pages.pageNotFoundDescription\")}\n >\n <div className=\"max-w-2xl rounded-lg bg-card p-5\">\n <Button asChild size=\"sm\" variant=\"ghost\" className=\"-ml-2 mb-4\">\n <Link to={appPath(\"/overview\")}>\n <IconArrowLeft size={15} className=\"mr-1.5\" />\n {t(\"dispatch.nav.overview\")}\n </Link>\n </Button>\n\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.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 defaultValue: \"Open in Builder\",\n })}\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.pageNotFound\")}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n <span className=\"font-mono text-foreground\">/{appId}</span> isn't\n {t(\"dispatch.pages.notDispatchOrWorkspaceApp\")}\n </p>\n <Button asChild>\n <Link to={appPath(\"/apps\")}>\n {t(\"dispatch.pages.browseApps\")}\n </Link>\n </Button>\n </div>\n )}\n </div>\n </DispatchShell>\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/agents.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/agents.tsx"],"names":[],"mappings":"AAoBA,wBAAgB,IAAI;;IAEnB;AAuLD,MAAM,CAAC,OAAO,UAAU,WAAW,oDAyBlC"}
|
|
@@ -9,6 +9,7 @@ import { AgentsPanel, } from "../../components/agents-panel.js";
|
|
|
9
9
|
import { DispatchShell } from "../../components/dispatch-shell.js";
|
|
10
10
|
import { Button } from "../../components/ui/button.js";
|
|
11
11
|
import { Input } from "../../components/ui/input.js";
|
|
12
|
+
import { Skeleton } from "../../components/ui/skeleton.js";
|
|
12
13
|
import { Switch } from "../../components/ui/switch.js";
|
|
13
14
|
export function meta() {
|
|
14
15
|
return [{ title: "Agents — Dispatch" }];
|
|
@@ -66,9 +67,7 @@ function DispatchMcpAccessPanel() {
|
|
|
66
67
|
}
|
|
67
68
|
return (_jsxs("section", { className: "rounded-2xl 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"
|
|
68
69
|
? t("dispatch.pages.allApps")
|
|
69
|
-
: t("dispatch.pages.selectedApps") }), _jsx("div", { className: "text-xs text-muted-foreground", children: isLoading
|
|
70
|
-
? t("dispatch.pages.loading")
|
|
71
|
-
: t("dispatch.pages.grantedCount", { count: grantedCount }) })] }), _jsx(Switch, { checked: access.mode === "all-apps", disabled: saveAccess.isPending || apps.length === 0, onCheckedChange: (checked) => persist({
|
|
70
|
+
: t("dispatch.pages.selectedApps") }), _jsx("div", { className: "text-xs text-muted-foreground", children: isLoading ? (_jsx(Skeleton, { className: "h-3 w-16" })) : (t("dispatch.pages.grantedCount", { count: grantedCount })) })] }), _jsx(Switch, { checked: access.mode === "all-apps", disabled: saveAccess.isPending || apps.length === 0, onCheckedChange: (checked) => persist({
|
|
72
71
|
mode: checked ? "all-apps" : "selected-apps",
|
|
73
72
|
selectedAppIds: checked
|
|
74
73
|
? access.selectedAppIds
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../../src/routes/pages/agents.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 { IconCheck, IconCopy, IconPlugConnected } from \"@tabler/icons-react\";\nimport { useMemo, useState } from \"react\";\nimport { toast } from \"sonner\";\n\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport {\n AgentsPanel,\n type ConnectedAgent,\n} from \"../../components/agents-panel\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport { Button } from \"../../components/ui/button\";\nimport { Input } from \"../../components/ui/input\";\nimport { Switch } from \"../../components/ui/switch\";\n\nexport function meta() {\n return [{ title: \"Agents — Dispatch\" }];\n}\n\ninterface McpAccessApp {\n id: string;\n name: string;\n description: string;\n url: string;\n color: string;\n granted: boolean;\n}\n\ntype McpAccessMode = \"all-apps\" | \"selected-apps\";\n\ninterface McpAccessState {\n mode: McpAccessMode;\n selectedAppIds: string[];\n}\n\nfunction dispatchMcpUrl(): string {\n const path = \"/mcp\";\n if (typeof window === \"undefined\") return path;\n return new URL(path, window.location.origin).href;\n}\n\nfunction DispatchMcpAccessPanel() {\n const t = useT();\n const { data, isLoading, isError, error, refetch } = useActionQuery(\n \"list-mcp-app-access\",\n {},\n );\n const [optimistic, setOptimistic] = useState<McpAccessState | null>(null);\n const saveAccess = useActionMutation(\"set-mcp-app-access\", {\n onSuccess: () => {\n setOptimistic(null);\n toast.success(t(\"dispatch.pages.mcpAccessUpdated\"));\n },\n onError: (error) => {\n setOptimistic(null);\n toast.error(error.message);\n },\n });\n\n const apps = ((data as { apps?: McpAccessApp[] } | undefined)?.apps ??\n []) as McpAccessApp[];\n const access =\n optimistic ??\n ({\n mode: ((data as { mode?: McpAccessMode } | undefined)?.mode ??\n \"all-apps\") as McpAccessMode,\n selectedAppIds:\n (data as { selectedAppIds?: string[] } | undefined)?.selectedAppIds ??\n [],\n } satisfies McpAccessState);\n const selected = useMemo(\n () => new Set(access.selectedAppIds),\n [access.selectedAppIds],\n );\n const grantedCount =\n access.mode === \"all-apps\" ? apps.length : access.selectedAppIds.length;\n const mcpUrl = dispatchMcpUrl();\n\n function persist(next: McpAccessState) {\n setOptimistic(next);\n saveAccess.mutate(next);\n }\n\n function toggleApp(appId: string) {\n const next = selected.has(appId)\n ? access.selectedAppIds.filter((id) => id !== appId)\n : [...access.selectedAppIds, appId];\n persist({ mode: \"selected-apps\", selectedAppIds: next });\n }\n\n async function copyUrl() {\n try {\n await navigator.clipboard.writeText(mcpUrl);\n toast.success(t(\"dispatch.pages.mcpUrlCopied\"));\n } catch {\n toast.error(t(\"dispatch.pages.mcpUrlCopyFailed\"));\n }\n }\n\n return (\n <section className=\"rounded-2xl bg-card p-5\">\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2 text-sm font-medium text-foreground\">\n <IconPlugConnected size={16} />\n {t(\"dispatch.pages.unifiedMcpGateway\")}\n </div>\n <div className=\"mt-1 max-w-2xl text-sm text-muted-foreground\">\n {t(\"dispatch.pages.unifiedMcpGatewayDescription\")}{\" \"}\n <code>list_apps</code>, <code>ask_app</code>, and{\" \"}\n <code>open_app</code>.\n </div>\n </div>\n <div className=\"flex items-center gap-3 rounded-xl border px-3 py-2\">\n <div>\n <div className=\"text-xs font-medium text-foreground\">\n {access.mode === \"all-apps\"\n ? t(\"dispatch.pages.allApps\")\n : t(\"dispatch.pages.selectedApps\")}\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {isLoading\n ? t(\"dispatch.pages.loading\")\n : t(\"dispatch.pages.grantedCount\", { count: grantedCount })}\n </div>\n </div>\n <Switch\n checked={access.mode === \"all-apps\"}\n disabled={saveAccess.isPending || apps.length === 0}\n onCheckedChange={(checked) =>\n persist({\n mode: checked ? \"all-apps\" : \"selected-apps\",\n selectedAppIds: checked\n ? access.selectedAppIds\n : apps.map((app) => app.id),\n })\n }\n aria-label={t(\"dispatch.pages.exposeAllAppsMcp\")}\n />\n </div>\n </div>\n\n <div className=\"mt-4 flex flex-col gap-2 sm:flex-row\">\n <Input readOnly value={mcpUrl} className=\"font-mono text-xs\" />\n <Button type=\"button\" variant=\"outline\" onClick={copyUrl}>\n <IconCopy size={15} />\n {t(\"dispatch.pages.copyUrl\")}\n </Button>\n </div>\n\n {isError ? (\n <ActionQueryError\n className=\"mt-4\"\n error={error}\n onRetry={() => void refetch()}\n />\n ) : access.mode === \"selected-apps\" ? (\n <div className=\"mt-4 grid gap-2 sm:grid-cols-2 xl:grid-cols-3\">\n {apps.map((app) => {\n const isSelected = selected.has(app.id);\n return (\n <button\n key={app.id}\n type=\"button\"\n disabled={\n saveAccess.isPending &&\n optimistic?.selectedAppIds.includes(app.id) !== isSelected\n }\n onClick={() => toggleApp(app.id)}\n className=\"flex min-h-[76px] items-start gap-3 rounded-xl border bg-muted/20 px-3 py-3 text-left transition hover:bg-muted/40 disabled:cursor-not-allowed disabled:opacity-60\"\n aria-pressed={isSelected}\n >\n <span\n className=\"mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-xs font-bold text-white\"\n style={{ backgroundColor: app.color }}\n >\n {app.name.charAt(0).toUpperCase()}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"flex items-center gap-2 text-sm font-medium text-foreground\">\n {app.name}\n {isSelected ? (\n <IconCheck size={14} className=\"text-emerald-500\" />\n ) : null}\n </span>\n <span className=\"mt-1 line-clamp-2 block text-xs text-muted-foreground\">\n {app.description || app.url}\n </span>\n </span>\n </button>\n );\n })}\n </div>\n ) : null}\n </section>\n );\n}\n\nexport default function AgentsRoute() {\n const t = useT();\n const agentsQuery = useActionQuery(\"list-connected-agents\", {});\n\n return (\n <DispatchShell\n title={t(\"dispatch.nav.agents\")}\n description={t(\"dispatch.pages.agentsDescription\")}\n >\n <div className=\"space-y-4\">\n <DispatchMcpAccessPanel />\n {agentsQuery.isError ? (\n <ActionQueryError\n error={agentsQuery.error}\n onRetry={() => void agentsQuery.refetch()}\n />\n ) : (\n <AgentsPanel\n agents={(agentsQuery.data || []) as ConnectedAgent[]}\n onRefresh={agentsQuery.refetch}\n />\n )}\n </div>\n </DispatchShell>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../../src/routes/pages/agents.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 { IconCheck, IconCopy, IconPlugConnected } from \"@tabler/icons-react\";\nimport { useMemo, useState } from \"react\";\nimport { toast } from \"sonner\";\n\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport {\n AgentsPanel,\n type ConnectedAgent,\n} from \"../../components/agents-panel\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport { Button } from \"../../components/ui/button\";\nimport { Input } from \"../../components/ui/input\";\nimport { Skeleton } from \"../../components/ui/skeleton\";\nimport { Switch } from \"../../components/ui/switch\";\n\nexport function meta() {\n return [{ title: \"Agents — Dispatch\" }];\n}\n\ninterface McpAccessApp {\n id: string;\n name: string;\n description: string;\n url: string;\n color: string;\n granted: boolean;\n}\n\ntype McpAccessMode = \"all-apps\" | \"selected-apps\";\n\ninterface McpAccessState {\n mode: McpAccessMode;\n selectedAppIds: string[];\n}\n\nfunction dispatchMcpUrl(): string {\n const path = \"/mcp\";\n if (typeof window === \"undefined\") return path;\n return new URL(path, window.location.origin).href;\n}\n\nfunction DispatchMcpAccessPanel() {\n const t = useT();\n const { data, isLoading, isError, error, refetch } = useActionQuery(\n \"list-mcp-app-access\",\n {},\n );\n const [optimistic, setOptimistic] = useState<McpAccessState | null>(null);\n const saveAccess = useActionMutation(\"set-mcp-app-access\", {\n onSuccess: () => {\n setOptimistic(null);\n toast.success(t(\"dispatch.pages.mcpAccessUpdated\"));\n },\n onError: (error) => {\n setOptimistic(null);\n toast.error(error.message);\n },\n });\n\n const apps = ((data as { apps?: McpAccessApp[] } | undefined)?.apps ??\n []) as McpAccessApp[];\n const access =\n optimistic ??\n ({\n mode: ((data as { mode?: McpAccessMode } | undefined)?.mode ??\n \"all-apps\") as McpAccessMode,\n selectedAppIds:\n (data as { selectedAppIds?: string[] } | undefined)?.selectedAppIds ??\n [],\n } satisfies McpAccessState);\n const selected = useMemo(\n () => new Set(access.selectedAppIds),\n [access.selectedAppIds],\n );\n const grantedCount =\n access.mode === \"all-apps\" ? apps.length : access.selectedAppIds.length;\n const mcpUrl = dispatchMcpUrl();\n\n function persist(next: McpAccessState) {\n setOptimistic(next);\n saveAccess.mutate(next);\n }\n\n function toggleApp(appId: string) {\n const next = selected.has(appId)\n ? access.selectedAppIds.filter((id) => id !== appId)\n : [...access.selectedAppIds, appId];\n persist({ mode: \"selected-apps\", selectedAppIds: next });\n }\n\n async function copyUrl() {\n try {\n await navigator.clipboard.writeText(mcpUrl);\n toast.success(t(\"dispatch.pages.mcpUrlCopied\"));\n } catch {\n toast.error(t(\"dispatch.pages.mcpUrlCopyFailed\"));\n }\n }\n\n return (\n <section className=\"rounded-2xl 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 <Skeleton className=\"h-3 w-16\" />\n ) : (\n t(\"dispatch.pages.grantedCount\", { count: grantedCount })\n )}\n </div>\n </div>\n <Switch\n checked={access.mode === \"all-apps\"}\n disabled={saveAccess.isPending || apps.length === 0}\n onCheckedChange={(checked) =>\n persist({\n mode: checked ? \"all-apps\" : \"selected-apps\",\n selectedAppIds: checked\n ? access.selectedAppIds\n : apps.map((app) => app.id),\n })\n }\n aria-label={t(\"dispatch.pages.exposeAllAppsMcp\")}\n />\n </div>\n </div>\n\n <div className=\"mt-4 flex flex-col gap-2 sm:flex-row\">\n <Input readOnly value={mcpUrl} className=\"font-mono text-xs\" />\n <Button type=\"button\" variant=\"outline\" onClick={copyUrl}>\n <IconCopy size={15} />\n {t(\"dispatch.pages.copyUrl\")}\n </Button>\n </div>\n\n {isError ? (\n <ActionQueryError\n className=\"mt-4\"\n error={error}\n onRetry={() => void refetch()}\n />\n ) : access.mode === \"selected-apps\" ? (\n <div className=\"mt-4 grid gap-2 sm:grid-cols-2 xl:grid-cols-3\">\n {apps.map((app) => {\n const isSelected = selected.has(app.id);\n return (\n <button\n key={app.id}\n type=\"button\"\n disabled={\n saveAccess.isPending &&\n optimistic?.selectedAppIds.includes(app.id) !== isSelected\n }\n onClick={() => toggleApp(app.id)}\n className=\"flex min-h-[76px] items-start gap-3 rounded-xl border bg-muted/20 px-3 py-3 text-left transition hover:bg-muted/40 disabled:cursor-not-allowed disabled:opacity-60\"\n aria-pressed={isSelected}\n >\n <span\n className=\"mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-xs font-bold text-white\"\n style={{ backgroundColor: app.color }}\n >\n {app.name.charAt(0).toUpperCase()}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"flex items-center gap-2 text-sm font-medium text-foreground\">\n {app.name}\n {isSelected ? (\n <IconCheck size={14} className=\"text-emerald-500\" />\n ) : null}\n </span>\n <span className=\"mt-1 line-clamp-2 block text-xs text-muted-foreground\">\n {app.description || app.url}\n </span>\n </span>\n </button>\n );\n })}\n </div>\n ) : null}\n </section>\n );\n}\n\nexport default function AgentsRoute() {\n const t = useT();\n const agentsQuery = useActionQuery(\"list-connected-agents\", {});\n\n return (\n <DispatchShell\n title={t(\"dispatch.nav.agents\")}\n description={t(\"dispatch.pages.agentsDescription\")}\n >\n <div className=\"space-y-4\">\n <DispatchMcpAccessPanel />\n {agentsQuery.isError ? (\n <ActionQueryError\n error={agentsQuery.error}\n onRetry={() => void agentsQuery.refetch()}\n />\n ) : (\n <AgentsPanel\n agents={(agentsQuery.data || []) as ConnectedAgent[]}\n onRefresh={agentsQuery.refetch}\n />\n )}\n </div>\n </DispatchShell>\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.$appId.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/apps.$appId.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"apps.$appId.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/apps.$appId.tsx"],"names":[],"mappings":"AAqCA,wBAAgB,IAAI;;IAEnB;AAED,MAAM,CAAC,OAAO,UAAU,iBAAiB,oDA+MxC"}
|
|
@@ -10,7 +10,8 @@ import { Badge } from "../../components/ui/badge.js";
|
|
|
10
10
|
import { Button } from "../../components/ui/button.js";
|
|
11
11
|
import { Skeleton } from "../../components/ui/skeleton.js";
|
|
12
12
|
import { Spinner } from "../../components/ui/spinner.js";
|
|
13
|
-
import {
|
|
13
|
+
import { isEmbedSessionExpiredMessage } from "../../lib/embed-session-recovery.js";
|
|
14
|
+
import { workspaceAppDirectHref, workspaceAppEmbedTarget, workspaceAppHref, } from "../../lib/workspace-apps.js";
|
|
14
15
|
export function meta() {
|
|
15
16
|
return [{ title: "Workspace app - Dispatch" }];
|
|
16
17
|
}
|
|
@@ -33,12 +34,12 @@ export default function WorkspaceAppRoute() {
|
|
|
33
34
|
const embedInput = useMemo(() => {
|
|
34
35
|
if (!app || !href)
|
|
35
36
|
return null;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}, [app?.id, app?.path, href]);
|
|
37
|
+
return {
|
|
38
|
+
app: app.id,
|
|
39
|
+
...workspaceAppEmbedTarget(app),
|
|
40
|
+
chrome: "minimal",
|
|
41
|
+
};
|
|
42
|
+
}, [app?.id, app?.path, app?.url, href]);
|
|
42
43
|
useEffect(() => {
|
|
43
44
|
if (!app || app.status === "pending" || !embedInput)
|
|
44
45
|
return;
|
|
@@ -53,6 +54,9 @@ export default function WorkspaceAppRoute() {
|
|
|
53
54
|
})
|
|
54
55
|
.catch((cause) => {
|
|
55
56
|
if (!cancelled) {
|
|
57
|
+
const directAppUrl = workspaceAppDirectHref(app, "/");
|
|
58
|
+
if (directAppUrl)
|
|
59
|
+
setEmbedUrl(directAppUrl);
|
|
56
60
|
setEmbedError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
57
61
|
}
|
|
58
62
|
});
|
|
@@ -69,10 +73,8 @@ export default function WorkspaceAppRoute() {
|
|
|
69
73
|
]);
|
|
70
74
|
useEffect(() => {
|
|
71
75
|
const handleEmbedSessionExpired = (event) => {
|
|
72
|
-
if (event
|
|
73
|
-
event.source !== embedFrameRef.current?.contentWindow) {
|
|
76
|
+
if (!isEmbedSessionExpiredMessage(event, embedFrameRef.current, null))
|
|
74
77
|
return;
|
|
75
|
-
}
|
|
76
78
|
setEmbedAttempt((attempt) => attempt + 1);
|
|
77
79
|
};
|
|
78
80
|
window.addEventListener("message", handleEmbedSessionExpired);
|
|
@@ -88,11 +90,13 @@ export default function WorkspaceAppRoute() {
|
|
|
88
90
|
return (_jsx("div", { className: "flex h-full min-h-0 items-center justify-center p-6", children: _jsxs("div", { className: "w-full max-w-2xl rounded-xl border bg-card p-6", 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")] }) }), _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") })] })] }) }));
|
|
89
91
|
}
|
|
90
92
|
if (app.status === "pending") {
|
|
91
|
-
return (_jsx("div", { className: "flex h-full min-h-0 items-center justify-center p-6", children: _jsxs("div", { className: "w-full max-w-2xl rounded-xl border bg-card p-6", 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")] }) }), _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.
|
|
93
|
+
return (_jsx("div", { className: "flex h-full min-h-0 items-center justify-center p-6", children: _jsxs("div", { className: "w-full max-w-2xl rounded-xl border bg-card p-6", 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")] }) }), _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.builderUrl ? (_jsx(Button, { asChild: true, children: _jsx("a", { href: withBuilderUtmTrackingParams(app.builderUrl, {
|
|
92
94
|
campaign: "product",
|
|
93
95
|
content: "dispatch_branch",
|
|
94
|
-
}), target: "_blank", rel: "noreferrer", children: t("dispatch.pages.openBuilderBranch"
|
|
96
|
+
}), target: "_blank", rel: "noreferrer", children: t("dispatch.pages.openBuilderBranch", {
|
|
97
|
+
defaultValue: "Open in Builder",
|
|
98
|
+
}) }) })) : null] })] }) }));
|
|
95
99
|
}
|
|
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") })] })) }) }));
|
|
100
|
+
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" }, `${embedUrl}:${embedAttempt}`)) : 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") })] })) }) }));
|
|
97
101
|
}
|
|
98
102
|
//# 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, 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
|
+
{"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, 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 { isEmbedSessionExpiredMessage } from \"../../lib/embed-session-recovery\";\nimport {\n workspaceAppDirectHref,\n workspaceAppEmbedTarget,\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 return {\n app: app.id,\n ...workspaceAppEmbedTarget(app),\n chrome: \"minimal\",\n };\n }, [app?.id, app?.path, app?.url, 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 const directAppUrl = workspaceAppDirectHref(app, \"/\");\n if (directAppUrl) setEmbedUrl(directAppUrl);\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 (!isEmbedSessionExpiredMessage(event, embedFrameRef.current, null))\n return;\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.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 defaultValue: \"Open in Builder\",\n })}\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 key={`${embedUrl}:${embedAttempt}`}\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 +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":"AAiDA,wBAAgB,IAAI;;IAEnB;AAQD,MAAM,CAAC,OAAO,UAAU,cAAc,oDAGrC"}
|