@agent-native/dispatch 0.29.1 → 0.29.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/components/workspace-app-host.d.ts +4 -2
- package/dist/components/workspace-app-host.d.ts.map +1 -1
- package/dist/components/workspace-app-host.js +37 -5
- package/dist/components/workspace-app-host.js.map +1 -1
- package/dist/lib/workspace-apps.d.ts +2 -0
- package/dist/lib/workspace-apps.d.ts.map +1 -1
- package/dist/lib/workspace-apps.js +23 -0
- package/dist/lib/workspace-apps.js.map +1 -1
- package/dist/lib/workspace-apps.test.js +60 -2
- package/dist/lib/workspace-apps.test.js.map +1 -1
- package/dist/routes/pages/$appId.d.ts.map +1 -1
- package/dist/routes/pages/$appId.js +15 -6
- package/dist/routes/pages/$appId.js.map +1 -1
- package/dist/routes/pages/apps.$appId.d.ts +1 -0
- package/dist/routes/pages/apps.$appId.d.ts.map +1 -1
- package/dist/routes/pages/apps.$appId.js +5 -1
- package/dist/routes/pages/apps.$appId.js.map +1 -1
- package/package.json +2 -2
- package/src/components/workspace-app-host.spec.tsx +118 -0
- package/src/components/workspace-app-host.tsx +54 -3
- package/src/lib/workspace-apps.test.ts +70 -1
- package/src/lib/workspace-apps.ts +24 -0
- package/src/routes/pages/$appId.spec.tsx +115 -0
- package/src/routes/pages/$appId.tsx +28 -5
- package/src/routes/pages/apps.$appId.spec.tsx +66 -0
- package/src/routes/pages/apps.$appId.tsx +11 -1
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
IconArrowUpRight,
|
|
8
8
|
IconClockHour4,
|
|
9
9
|
} from "@tabler/icons-react";
|
|
10
|
-
import { useEffect, useMemo } from "react";
|
|
10
|
+
import { useEffect, useMemo, useState } from "react";
|
|
11
11
|
import {
|
|
12
12
|
Link,
|
|
13
13
|
Navigate,
|
|
@@ -24,6 +24,7 @@ import { Button } from "../../components/ui/button";
|
|
|
24
24
|
import { Spinner } from "../../components/ui/spinner";
|
|
25
25
|
import { resolveServerCatchAllTarget } from "../../lib/catch-all-target";
|
|
26
26
|
import {
|
|
27
|
+
navigateToWorkspaceApp,
|
|
27
28
|
workspaceAppHref,
|
|
28
29
|
type WorkspaceAppSummary,
|
|
29
30
|
} from "../../lib/workspace-apps";
|
|
@@ -111,12 +112,18 @@ export default function WorkspaceAppCatchAllRoute() {
|
|
|
111
112
|
);
|
|
112
113
|
const href = app ? workspaceAppHref(app) : null;
|
|
113
114
|
const isSelfReference = appId === "dispatch";
|
|
115
|
+
const hasApp = app !== null;
|
|
116
|
+
const appIsPending = app?.status === "pending";
|
|
117
|
+
const [navigationFailed, setNavigationFailed] = useState(false);
|
|
114
118
|
|
|
115
119
|
useEffect(() => {
|
|
116
120
|
if (isSelfReference) return;
|
|
117
|
-
if (!
|
|
118
|
-
|
|
119
|
-
|
|
121
|
+
if (!hasApp || appIsPending || !href) {
|
|
122
|
+
setNavigationFailed(false);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
setNavigationFailed(!navigateToWorkspaceApp(href));
|
|
126
|
+
}, [appIsPending, hasApp, href, isSelfReference]);
|
|
120
127
|
|
|
121
128
|
if (isSelfReference) {
|
|
122
129
|
return <Navigate to={appPath("/overview")} replace />;
|
|
@@ -136,7 +143,23 @@ export default function WorkspaceAppCatchAllRoute() {
|
|
|
136
143
|
);
|
|
137
144
|
}
|
|
138
145
|
|
|
139
|
-
if (
|
|
146
|
+
if (navigationFailed && href) {
|
|
147
|
+
return (
|
|
148
|
+
<DispatchShell
|
|
149
|
+
title={t("dispatch.pages.dataLoadFailed")}
|
|
150
|
+
description={t("dispatch.pages.pageNotFoundDescription")}
|
|
151
|
+
>
|
|
152
|
+
<ActionQueryError
|
|
153
|
+
onRetry={() => setNavigationFailed(!navigateToWorkspaceApp(href))}
|
|
154
|
+
/>
|
|
155
|
+
</DispatchShell>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (
|
|
160
|
+
(isLoading && !app) ||
|
|
161
|
+
(app && app.status !== "pending" && href && !navigationFailed)
|
|
162
|
+
) {
|
|
140
163
|
return (
|
|
141
164
|
<div className="flex h-screen w-full items-center justify-center">
|
|
142
165
|
<Spinner className="size-8" />
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
import React, { act } from "react";
|
|
3
|
+
import { createRoot, type Root } from "react-dom/client";
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
|
|
6
|
+
const routeState = vi.hoisted(() => ({
|
|
7
|
+
appId: "mail",
|
|
8
|
+
hostProps: null as {
|
|
9
|
+
appId?: string;
|
|
10
|
+
navigateToTopWindow?: (href: string) => boolean | void;
|
|
11
|
+
} | null,
|
|
12
|
+
navigateToWorkspaceApp: vi.fn(() => true),
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
vi.mock("react-router", () => ({
|
|
16
|
+
useParams: () => ({ appId: routeState.appId }),
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
vi.mock("../../components/workspace-app-host", () => ({
|
|
20
|
+
WorkspaceAppHost: (props: typeof routeState.hostProps) => {
|
|
21
|
+
routeState.hostProps = props;
|
|
22
|
+
return <div data-workspace-app-id={props?.appId} />;
|
|
23
|
+
},
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
vi.mock("../../lib/workspace-apps", () => ({
|
|
27
|
+
navigateToWorkspaceApp: routeState.navigateToWorkspaceApp,
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
import WorkspaceAppRoute from "./apps.$appId";
|
|
31
|
+
|
|
32
|
+
describe("WorkspaceAppRoute", () => {
|
|
33
|
+
let container: HTMLDivElement;
|
|
34
|
+
let root: Root;
|
|
35
|
+
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
38
|
+
routeState.appId = "mail";
|
|
39
|
+
routeState.hostProps = null;
|
|
40
|
+
routeState.navigateToWorkspaceApp.mockClear();
|
|
41
|
+
container = document.createElement("div");
|
|
42
|
+
document.body.appendChild(container);
|
|
43
|
+
root = createRoot(container);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
act(() => root.unmount());
|
|
48
|
+
container.remove();
|
|
49
|
+
vi.unstubAllGlobals();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("passes the route app id and top-window helper to the workspace host", async () => {
|
|
53
|
+
await act(async () => {
|
|
54
|
+
root.render(<WorkspaceAppRoute />);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
expect(routeState.hostProps?.appId).toBe("mail");
|
|
58
|
+
expect(routeState.hostProps?.navigateToTopWindow).toEqual(
|
|
59
|
+
expect.any(Function),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
routeState.hostProps?.navigateToTopWindow?.("/mail");
|
|
63
|
+
|
|
64
|
+
expect(routeState.navigateToWorkspaceApp).toHaveBeenCalledWith("/mail");
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { useParams } from "react-router";
|
|
2
2
|
|
|
3
3
|
import { WorkspaceAppHost } from "../../components/workspace-app-host";
|
|
4
|
+
import { navigateToWorkspaceApp } from "../../lib/workspace-apps";
|
|
5
|
+
|
|
6
|
+
export function navigateWorkspaceAppFromRoute(href: string): boolean {
|
|
7
|
+
return navigateToWorkspaceApp(href);
|
|
8
|
+
}
|
|
4
9
|
|
|
5
10
|
export function meta() {
|
|
6
11
|
return [{ title: "Workspace app - Dispatch" }];
|
|
@@ -8,5 +13,10 @@ export function meta() {
|
|
|
8
13
|
|
|
9
14
|
export default function WorkspaceAppRoute() {
|
|
10
15
|
const { appId } = useParams();
|
|
11
|
-
return
|
|
16
|
+
return (
|
|
17
|
+
<WorkspaceAppHost
|
|
18
|
+
appId={appId}
|
|
19
|
+
navigateToTopWindow={navigateWorkspaceAppFromRoute}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
12
22
|
}
|