@agent-native/toolkit 0.207.0-nightly-20261011153008 → 0.207.0
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/agent-native.eject.json +1 -0
- package/dist/app/auth/AuthPage.d.ts.map +1 -1
- package/dist/app/auth/AuthPage.js +24 -55
- package/dist/app/auth/AuthPage.js.map +1 -1
- package/dist/app/chat/chat/run-recovery.d.ts.map +1 -1
- package/dist/app/chat/chat/run-recovery.js +21 -5
- package/dist/app/chat/chat/run-recovery.js.map +1 -1
- package/dist/app/chat/chat-first/ChatFirstAgentActivityPanel.d.ts.map +1 -1
- package/dist/app/chat/chat-first/ChatFirstAgentActivityPanel.js +3 -2
- package/dist/app/chat/chat-first/ChatFirstAgentActivityPanel.js.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.js +10 -2
- package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.js +10 -2
- package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
- package/dist/app/i18n/catalogs/en-US.d.ts +10 -2
- package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/en-US.js +10 -2
- package/dist/app/i18n/catalogs/en-US.js.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.js +10 -2
- package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.js +10 -2
- package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.js +10 -2
- package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.js +10 -2
- package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.js +10 -2
- package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.js +10 -2
- package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.js +10 -2
- package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.js +10 -2
- package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
- package/dist/app/onboarding/OnboardingBanner.d.ts.map +1 -1
- package/dist/app/onboarding/OnboardingBanner.js +37 -3
- package/dist/app/onboarding/OnboardingBanner.js.map +1 -1
- package/dist/app/onboarding/OnboardingPanel.d.ts.map +1 -1
- package/dist/app/onboarding/OnboardingPanel.js +49 -11
- package/dist/app/onboarding/OnboardingPanel.js.map +1 -1
- package/dist/app/progress/RunsTray.d.ts.map +1 -1
- package/dist/app/progress/RunsTray.js +136 -17
- package/dist/app/progress/RunsTray.js.map +1 -1
- package/dist/app/settings/BuilderConnectPopover.d.ts +1 -0
- package/dist/app/settings/BuilderConnectPopover.d.ts.map +1 -1
- package/dist/app/settings/BuilderConnectPopover.js +21 -5
- package/dist/app/settings/BuilderConnectPopover.js.map +1 -1
- package/dist/app/settings/shell/pages/audit.d.ts.map +1 -1
- package/dist/app/settings/shell/pages/audit.js +3 -3
- package/dist/app/settings/shell/pages/audit.js.map +1 -1
- package/dist/app/settings/useBuilderStatus.d.ts +1 -0
- package/dist/app/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/app/settings/useBuilderStatus.js +1 -0
- package/dist/app/settings/useBuilderStatus.js.map +1 -1
- package/dist/app/shared/AgentMark.d.ts +6 -0
- package/dist/app/shared/AgentMark.d.ts.map +1 -0
- package/dist/app/shared/AgentMark.js +5 -0
- package/dist/app/shared/AgentMark.js.map +1 -0
- package/dist/app/shared/index.d.ts +1 -0
- package/dist/app/shared/index.d.ts.map +1 -1
- package/dist/app/shared/index.js +1 -0
- package/dist/app/shared/index.js.map +1 -1
- package/dist/app/sharing/ShareButton.d.ts +1 -0
- package/dist/app/sharing/ShareButton.d.ts.map +1 -1
- package/dist/app/sharing/ShareButton.js +2 -2
- package/dist/app/sharing/ShareButton.js.map +1 -1
- package/dist/app/styles/agent-native.css +1 -0
- package/dist/app-shell/sidebar.d.ts.map +1 -1
- package/dist/app-shell/sidebar.js +3 -3
- package/dist/app-shell/sidebar.js.map +1 -1
- package/dist/sharing/ShareControls.d.ts +1 -0
- package/dist/sharing/ShareControls.d.ts.map +1 -1
- package/dist/sharing/ShareControls.js +5 -2
- package/dist/sharing/ShareControls.js.map +1 -1
- package/package.json +4 -4
- package/src/app/auth/AuthPage.attribution.spec.tsx +268 -0
- package/src/app/auth/AuthPage.tsx +27 -54
- package/src/app/chat/chat/run-recovery.spec.tsx +76 -0
- package/src/app/chat/chat/run-recovery.tsx +101 -23
- package/src/app/chat/chat-first/ChatFirstAgentActivityPanel.tsx +11 -5
- package/src/app/i18n/catalogs/ar-SA.ts +17 -2
- package/src/app/i18n/catalogs/de-DE.ts +18 -2
- package/src/app/i18n/catalogs/en-US.ts +17 -2
- package/src/app/i18n/catalogs/es-ES.ts +17 -2
- package/src/app/i18n/catalogs/fr-FR.ts +18 -2
- package/src/app/i18n/catalogs/hi-IN.ts +17 -2
- package/src/app/i18n/catalogs/ja-JP.ts +17 -2
- package/src/app/i18n/catalogs/ko-KR.ts +17 -2
- package/src/app/i18n/catalogs/pt-BR.ts +17 -2
- package/src/app/i18n/catalogs/zh-CN.ts +16 -2
- package/src/app/i18n/catalogs/zh-TW.ts +16 -2
- package/src/app/onboarding/OnboardingBanner.tsx +70 -5
- package/src/app/onboarding/OnboardingPanel.save-scope.spec.tsx +143 -2
- package/src/app/onboarding/OnboardingPanel.tsx +72 -5
- package/src/app/progress/RunsTray.spec.tsx +577 -0
- package/src/app/progress/RunsTray.tsx +253 -51
- package/src/app/settings/BuilderConnectPopover.spec.tsx +39 -1
- package/src/app/settings/BuilderConnectPopover.tsx +27 -4
- package/src/app/settings/shell/pages/audit.tsx +7 -3
- package/src/app/settings/useBuilderStatus.spec.tsx +21 -1
- package/src/app/settings/useBuilderStatus.ts +2 -0
- package/src/app/shared/AgentMark.tsx +34 -0
- package/src/app/shared/index.ts +1 -0
- package/src/app/sharing/ShareButton.tsx +3 -0
- package/src/app/styles/agent-native.css +1 -0
- package/src/app-shell/sidebar.tsx +29 -21
- package/src/sharing/ShareControls.spec.tsx +36 -0
- package/src/sharing/ShareControls.tsx +17 -2
|
@@ -146,8 +146,16 @@ const messages: ToolkitAgentChatTranslation = {
|
|
|
146
146
|
"onboarding.builderActivateTitle": "啟用免費額度",
|
|
147
147
|
"onboarding.builderAccountExistsTitle": "您已有 Builder.io 帳戶",
|
|
148
148
|
"onboarding.builderAccountExistsDescription": "登入以使用您的帳戶。",
|
|
149
|
+
"onboarding.builderActivationChecking": "正在確認是否可以建立新帳戶。",
|
|
150
|
+
"onboarding.builderActivationUnavailable":
|
|
151
|
+
"此應用程式未啟用新帳戶建立功能。你仍可連結現有帳戶。",
|
|
152
|
+
"onboarding.builderActivationUnavailableInMode":
|
|
153
|
+
"此模式無法啟用新帳戶。你仍可連結現有帳戶。",
|
|
154
|
+
"onboarding.builderActivationCheckFailed":
|
|
155
|
+
"無法確認此應用程式是否可以建立新帳戶。",
|
|
156
|
+
|
|
149
157
|
"onboarding.builderActivationDescription":
|
|
150
|
-
"
|
|
158
|
+
"建立新帳戶以啟用免費點數,或使用現有帳戶繼續。",
|
|
151
159
|
"onboarding.builderOrgActivationDescription":
|
|
152
160
|
"我們會一鍵建立您的 Builder.io 帳戶,讓您的組織可以使用。",
|
|
153
161
|
"onboarding.builderCreateAndActivate": "建立並啟用",
|
|
@@ -155,7 +163,7 @@ const messages: ToolkitAgentChatTranslation = {
|
|
|
155
163
|
"onboarding.builderTerms": "服務條款",
|
|
156
164
|
"onboarding.builderPrivacy": "隱私權政策",
|
|
157
165
|
"onboarding.builderConsentAnd": "和",
|
|
158
|
-
"onboarding.builderExistingAccount": "
|
|
166
|
+
"onboarding.builderExistingAccount": "我有 Builder.io 帳戶",
|
|
159
167
|
"onboarding.builderActivating": "正在啟用 Builder.io 免費額度",
|
|
160
168
|
"onboarding.builderConnecting": "正在設定 Builder.io 免費額度",
|
|
161
169
|
"onboarding.builderProvisioningDescription":
|
|
@@ -1161,6 +1169,12 @@ const messages: ToolkitAgentChatTranslation = {
|
|
|
1161
1169
|
"selection.attached": "已附加所選內容的 {{formattedCount}} 個字元",
|
|
1162
1170
|
"selection.attached_other": "已附加所選內容的 {{formattedCount}} 個字元",
|
|
1163
1171
|
"selection.clear": "清除所選內容的上下文",
|
|
1172
|
+
"setup.addKeyInSettings": "在設定中新增金鑰",
|
|
1173
|
+
"setup.addKeyInSettingsDescription": "供你的個人帳戶或組織使用。",
|
|
1174
|
+
"setup.setEnvironmentVariable": "設定環境變數",
|
|
1175
|
+
"setup.setEnvironmentVariableDescription":
|
|
1176
|
+
"此應用程式的所有使用者共用一個供應商金鑰。",
|
|
1177
|
+
|
|
1164
1178
|
"setup.addOwnKeys": "加入您自己的金鑰",
|
|
1165
1179
|
"setup.builderCredits":
|
|
1166
1180
|
"Builder.io 提供免費額度,您也可以使用自己的 API 金鑰。",
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { useOnboarding } from "@agent-native/core/client/onboarding/use-onboarding";
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
3
|
+
import { Button } from "@agent-native/toolkit/ui/button";
|
|
4
|
+
import {
|
|
5
|
+
IconChecklist,
|
|
6
|
+
IconChevronRight,
|
|
7
|
+
IconLoader2,
|
|
8
|
+
} from "@tabler/icons-react";
|
|
9
|
+
import React, { useState } from "react";
|
|
4
10
|
|
|
5
11
|
interface OnboardingBannerProps {
|
|
6
12
|
onContinue?: () => void;
|
|
@@ -11,9 +17,55 @@ export function OnboardingBanner({
|
|
|
11
17
|
onContinue,
|
|
12
18
|
className,
|
|
13
19
|
}: OnboardingBannerProps) {
|
|
14
|
-
const {
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
const {
|
|
21
|
+
loading,
|
|
22
|
+
totalCount,
|
|
23
|
+
completeCount,
|
|
24
|
+
allComplete,
|
|
25
|
+
dismissed,
|
|
26
|
+
error,
|
|
27
|
+
summaryKnown,
|
|
28
|
+
refresh,
|
|
29
|
+
} = useOnboarding();
|
|
30
|
+
const t = useT();
|
|
31
|
+
const [retrying, setRetrying] = useState(false);
|
|
32
|
+
|
|
33
|
+
if (
|
|
34
|
+
loading ||
|
|
35
|
+
(summaryKnown && (dismissed || (totalCount > 0 && allComplete)))
|
|
36
|
+
) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
if (error && (!summaryKnown || totalCount > 0)) {
|
|
40
|
+
const retry = async () => {
|
|
41
|
+
setRetrying(true);
|
|
42
|
+
try {
|
|
43
|
+
await refresh();
|
|
44
|
+
} finally {
|
|
45
|
+
setRetrying(false);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div role="alert" className={className} style={styles.error}>
|
|
51
|
+
<span>{t("agentChat.common.chunkLoadFailed")}</span>
|
|
52
|
+
<Button
|
|
53
|
+
type="button"
|
|
54
|
+
variant="outline"
|
|
55
|
+
size="xs"
|
|
56
|
+
data-testid="onboarding-summary-retry"
|
|
57
|
+
disabled={retrying}
|
|
58
|
+
onClick={() => void retry()}
|
|
59
|
+
>
|
|
60
|
+
{retrying ? (
|
|
61
|
+
<IconLoader2 className="animate-spin" aria-hidden />
|
|
62
|
+
) : null}
|
|
63
|
+
{t("agentChat.common.retry")}
|
|
64
|
+
</Button>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
if (!summaryKnown || totalCount === 0) return null;
|
|
17
69
|
|
|
18
70
|
return (
|
|
19
71
|
<button
|
|
@@ -38,6 +90,19 @@ export function OnboardingBanner({
|
|
|
38
90
|
}
|
|
39
91
|
|
|
40
92
|
const styles: Record<string, React.CSSProperties> = {
|
|
93
|
+
error: {
|
|
94
|
+
display: "flex",
|
|
95
|
+
flexWrap: "wrap",
|
|
96
|
+
alignItems: "center",
|
|
97
|
+
justifyContent: "space-between",
|
|
98
|
+
gap: 8,
|
|
99
|
+
width: "100%",
|
|
100
|
+
padding: "8px 12px",
|
|
101
|
+
borderBottom: "1px solid hsl(var(--border) / 0.7)",
|
|
102
|
+
background: "hsl(var(--muted) / 0.25)",
|
|
103
|
+
color: "hsl(var(--muted-foreground))",
|
|
104
|
+
fontSize: 12,
|
|
105
|
+
},
|
|
41
106
|
root: {
|
|
42
107
|
display: "flex",
|
|
43
108
|
alignItems: "center",
|
|
@@ -8,15 +8,26 @@ import { createRoot, type Root } from "react-dom/client";
|
|
|
8
8
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
9
9
|
|
|
10
10
|
let steps: OnboardingStepStatus[] = [];
|
|
11
|
+
let onboardingError: string | null = null;
|
|
12
|
+
let dismissed = false;
|
|
13
|
+
let summaryKnown = true;
|
|
14
|
+
let refresh = vi.fn(async () => {});
|
|
11
15
|
vi.mock("@agent-native/core/client/onboarding/use-onboarding", () => ({
|
|
12
16
|
createOnboardingCorrelationId: () => "test-onboarding-correlation-id",
|
|
13
17
|
trackOnboardingEvent: vi.fn(),
|
|
14
18
|
useOnboarding: () => ({
|
|
15
19
|
steps,
|
|
16
20
|
currentStepId: steps[0]?.id ?? null,
|
|
17
|
-
|
|
21
|
+
completeCount: steps.filter((step) => step.complete).length,
|
|
22
|
+
totalCount: steps.length,
|
|
23
|
+
allComplete:
|
|
24
|
+
steps.length > 0 &&
|
|
25
|
+
steps.filter((step) => step.required).every((step) => step.complete),
|
|
26
|
+
dismissed,
|
|
27
|
+
summaryKnown,
|
|
18
28
|
loading: false,
|
|
19
|
-
|
|
29
|
+
error: onboardingError,
|
|
30
|
+
refresh,
|
|
20
31
|
complete: vi.fn(),
|
|
21
32
|
dismiss: vi.fn(),
|
|
22
33
|
}),
|
|
@@ -28,6 +39,7 @@ vi.mock("@agent-native/core/client/use-dev-mode", () => ({
|
|
|
28
39
|
useDevMode: () => ({ isDevMode: false }),
|
|
29
40
|
}));
|
|
30
41
|
|
|
42
|
+
import { OnboardingBanner } from "./OnboardingBanner.js";
|
|
31
43
|
import { OnboardingPanel } from "./OnboardingPanel.js";
|
|
32
44
|
|
|
33
45
|
function json(body: unknown): Response {
|
|
@@ -69,9 +81,30 @@ afterEach(() => {
|
|
|
69
81
|
container?.remove();
|
|
70
82
|
root = null;
|
|
71
83
|
container = null;
|
|
84
|
+
steps = [];
|
|
85
|
+
onboardingError = null;
|
|
86
|
+
dismissed = false;
|
|
87
|
+
summaryKnown = true;
|
|
88
|
+
refresh = vi.fn(async () => {});
|
|
72
89
|
vi.unstubAllGlobals();
|
|
73
90
|
});
|
|
74
91
|
|
|
92
|
+
async function renderOnboarding(child: React.ReactNode): Promise<void> {
|
|
93
|
+
container = document.createElement("div");
|
|
94
|
+
document.body.appendChild(container);
|
|
95
|
+
root = createRoot(container);
|
|
96
|
+
const queryClient = new QueryClient({
|
|
97
|
+
defaultOptions: { queries: { retry: false } },
|
|
98
|
+
});
|
|
99
|
+
await act(async () => {
|
|
100
|
+
root!.render(
|
|
101
|
+
<QueryClientProvider client={queryClient}>
|
|
102
|
+
<TooltipProvider>{child}</TooltipProvider>
|
|
103
|
+
</QueryClientProvider>,
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
75
108
|
async function saveAs(
|
|
76
109
|
role: "member" | "admin",
|
|
77
110
|
saveTo?: "scoped-secrets",
|
|
@@ -156,4 +189,112 @@ describe("onboarding form save scope", () => {
|
|
|
156
189
|
const [secretSave] = await saveAs("admin", "scoped-secrets");
|
|
157
190
|
expect(secretSave.body.scope).toBe("workspace");
|
|
158
191
|
});
|
|
192
|
+
|
|
193
|
+
it("shows retry only when the initial summary is unavailable", async () => {
|
|
194
|
+
steps = [formStep()];
|
|
195
|
+
onboardingError = "summary: 503";
|
|
196
|
+
summaryKnown = false;
|
|
197
|
+
refresh = vi.fn(async () => {});
|
|
198
|
+
await renderOnboarding(<OnboardingPanel />);
|
|
199
|
+
|
|
200
|
+
const retry = container?.querySelector<HTMLButtonElement>(
|
|
201
|
+
'[data-testid="onboarding-summary-retry"]',
|
|
202
|
+
);
|
|
203
|
+
expect(container?.querySelector('[role="alert"]')).not.toBeNull();
|
|
204
|
+
expect(container?.textContent).not.toContain("Example keys");
|
|
205
|
+
expect(retry).not.toBeNull();
|
|
206
|
+
await act(async () => retry?.click());
|
|
207
|
+
expect(refresh).toHaveBeenCalledOnce();
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("keeps known steps visible while showing a summary retry state", async () => {
|
|
211
|
+
steps = [formStep()];
|
|
212
|
+
onboardingError = "summary: 503";
|
|
213
|
+
await renderOnboarding(<OnboardingPanel />);
|
|
214
|
+
|
|
215
|
+
expect(container?.querySelector('[role="alert"]')).not.toBeNull();
|
|
216
|
+
expect(container?.textContent).toContain("Example keys");
|
|
217
|
+
expect(
|
|
218
|
+
container?.querySelector('[data-testid="onboarding-summary-retry"]'),
|
|
219
|
+
).not.toBeNull();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("shows a retry-only banner when the initial summary is unavailable", async () => {
|
|
223
|
+
steps = [formStep()];
|
|
224
|
+
onboardingError = "summary: 503";
|
|
225
|
+
summaryKnown = false;
|
|
226
|
+
refresh = vi.fn(async () => {});
|
|
227
|
+
await renderOnboarding(<OnboardingBanner />);
|
|
228
|
+
|
|
229
|
+
const retry = container?.querySelector<HTMLButtonElement>(
|
|
230
|
+
'[data-testid="onboarding-summary-retry"]',
|
|
231
|
+
);
|
|
232
|
+
expect(container?.querySelector('[role="alert"]')).not.toBeNull();
|
|
233
|
+
expect(container?.textContent).not.toContain("Example keys");
|
|
234
|
+
expect(container?.textContent).not.toContain("Continue");
|
|
235
|
+
expect(retry).not.toBeNull();
|
|
236
|
+
await act(async () => retry?.click());
|
|
237
|
+
expect(refresh).toHaveBeenCalledOnce();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it("shows a retry action on the banner for a known active summary", async () => {
|
|
241
|
+
steps = [formStep()];
|
|
242
|
+
onboardingError = "summary: 503";
|
|
243
|
+
summaryKnown = true;
|
|
244
|
+
refresh = vi.fn(async () => {});
|
|
245
|
+
await renderOnboarding(<OnboardingBanner />);
|
|
246
|
+
|
|
247
|
+
const retry = container?.querySelector<HTMLButtonElement>(
|
|
248
|
+
'[data-testid="onboarding-summary-retry"]',
|
|
249
|
+
);
|
|
250
|
+
expect(container?.querySelector('[role="alert"]')).not.toBeNull();
|
|
251
|
+
expect(retry).not.toBeNull();
|
|
252
|
+
await act(async () => retry?.click());
|
|
253
|
+
expect(refresh).toHaveBeenCalledOnce();
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it("hides summary errors after onboarding is dismissed", async () => {
|
|
257
|
+
dismissed = true;
|
|
258
|
+
summaryKnown = true;
|
|
259
|
+
onboardingError = "summary: 503";
|
|
260
|
+
|
|
261
|
+
await renderOnboarding(
|
|
262
|
+
<>
|
|
263
|
+
<OnboardingBanner />
|
|
264
|
+
<OnboardingPanel />
|
|
265
|
+
</>,
|
|
266
|
+
);
|
|
267
|
+
expect(container?.querySelector('[role="alert"]')).toBeNull();
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it("hides summary errors after all required steps are complete", async () => {
|
|
271
|
+
steps = [{ ...formStep(), complete: true }];
|
|
272
|
+
summaryKnown = true;
|
|
273
|
+
onboardingError = "summary: 503";
|
|
274
|
+
|
|
275
|
+
await renderOnboarding(
|
|
276
|
+
<>
|
|
277
|
+
<OnboardingBanner />
|
|
278
|
+
<OnboardingPanel />
|
|
279
|
+
</>,
|
|
280
|
+
);
|
|
281
|
+
expect(container?.querySelector('[role="alert"]')).toBeNull();
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("keeps the retry notice visible while the panel is collapsed", async () => {
|
|
285
|
+
steps = [formStep()];
|
|
286
|
+
summaryKnown = true;
|
|
287
|
+
onboardingError = "summary: 503";
|
|
288
|
+
await renderOnboarding(<OnboardingPanel />);
|
|
289
|
+
|
|
290
|
+
const collapse = container?.querySelector<HTMLButtonElement>(
|
|
291
|
+
'[aria-label="Collapse onboarding"]',
|
|
292
|
+
);
|
|
293
|
+
await act(async () => collapse?.click());
|
|
294
|
+
|
|
295
|
+
expect(container?.querySelector('[role="alert"]')).not.toBeNull();
|
|
296
|
+
expect(
|
|
297
|
+
container?.querySelector('[data-testid="onboarding-summary-retry"]'),
|
|
298
|
+
).not.toBeNull();
|
|
299
|
+
});
|
|
159
300
|
});
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
OnboardingMethod,
|
|
13
13
|
OnboardingStepStatus,
|
|
14
14
|
} from "@agent-native/core/onboarding/types";
|
|
15
|
+
import { Button } from "@agent-native/toolkit/ui/button";
|
|
15
16
|
import {
|
|
16
17
|
Tooltip,
|
|
17
18
|
TooltipContent,
|
|
@@ -56,10 +57,13 @@ export function OnboardingPanel({
|
|
|
56
57
|
currentStepId: rawCurrentStepId,
|
|
57
58
|
dismissed,
|
|
58
59
|
loading,
|
|
60
|
+
error,
|
|
61
|
+
summaryKnown,
|
|
59
62
|
refresh,
|
|
60
63
|
complete,
|
|
61
64
|
dismiss,
|
|
62
65
|
} = onboarding;
|
|
66
|
+
const t = useT();
|
|
63
67
|
const DEV_ONLY_STEP_IDS = new Set(["database", "auth"]);
|
|
64
68
|
const steps = isDevMode
|
|
65
69
|
? rawSteps
|
|
@@ -75,6 +79,7 @@ export function OnboardingPanel({
|
|
|
75
79
|
const checklistVisible =
|
|
76
80
|
!loading && totalCount > 0 && (previewMode || (!dismissed && !allComplete));
|
|
77
81
|
const [expanded, setExpanded] = useState(true);
|
|
82
|
+
const [retrying, setRetrying] = useState(false);
|
|
78
83
|
const stepViewRef = useRef<{ key: string; id: string } | null>(null);
|
|
79
84
|
|
|
80
85
|
useEffect(() => {
|
|
@@ -102,12 +107,58 @@ export function OnboardingPanel({
|
|
|
102
107
|
});
|
|
103
108
|
}, [checklistVisible, currentStepId, expanded, previewMode, steps]);
|
|
104
109
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
const handleRetry = async () => {
|
|
111
|
+
setRetrying(true);
|
|
112
|
+
try {
|
|
113
|
+
await refresh();
|
|
114
|
+
} finally {
|
|
115
|
+
setRetrying(false);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
const errorNotice =
|
|
119
|
+
error &&
|
|
120
|
+
(previewMode ||
|
|
121
|
+
!summaryKnown ||
|
|
122
|
+
(totalCount > 0 && !dismissed && !allComplete)) ? (
|
|
123
|
+
<div role="alert" style={styles.errorNotice}>
|
|
124
|
+
<span>{t("agentChat.common.chunkLoadFailed")}</span>
|
|
125
|
+
<Button
|
|
126
|
+
type="button"
|
|
127
|
+
variant="outline"
|
|
128
|
+
size="xs"
|
|
129
|
+
data-testid="onboarding-summary-retry"
|
|
130
|
+
disabled={retrying}
|
|
131
|
+
onClick={() => void handleRetry()}
|
|
132
|
+
>
|
|
133
|
+
{retrying ? (
|
|
134
|
+
<IconLoader2 className="animate-spin" aria-hidden />
|
|
135
|
+
) : null}
|
|
136
|
+
{t("agentChat.common.retry")}
|
|
137
|
+
</Button>
|
|
138
|
+
</div>
|
|
139
|
+
) : null;
|
|
110
140
|
|
|
141
|
+
if (loading) return null;
|
|
142
|
+
if (!previewMode && !summaryKnown) {
|
|
143
|
+
if (!errorNotice) return null;
|
|
144
|
+
return (
|
|
145
|
+
<div className={className} style={styles.errorOnly}>
|
|
146
|
+
{errorNotice}
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
if (!previewMode && (dismissed || (totalCount > 0 && allComplete))) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
if (error && totalCount === 0) {
|
|
154
|
+
if (!errorNotice) return null;
|
|
155
|
+
return (
|
|
156
|
+
<div className={className} style={styles.errorOnly}>
|
|
157
|
+
{errorNotice}
|
|
158
|
+
</div>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
if (totalCount === 0) return null;
|
|
111
162
|
if (!expanded) {
|
|
112
163
|
return (
|
|
113
164
|
<div className={className} style={styles.compactBanner}>
|
|
@@ -139,6 +190,7 @@ export function OnboardingPanel({
|
|
|
139
190
|
</TooltipTrigger>
|
|
140
191
|
<TooltipContent>Expand setup</TooltipContent>
|
|
141
192
|
</Tooltip>
|
|
193
|
+
{errorNotice}
|
|
142
194
|
</div>
|
|
143
195
|
);
|
|
144
196
|
}
|
|
@@ -174,6 +226,8 @@ export function OnboardingPanel({
|
|
|
174
226
|
</Tooltip>
|
|
175
227
|
</div>
|
|
176
228
|
|
|
229
|
+
{errorNotice}
|
|
230
|
+
|
|
177
231
|
<div style={styles.list}>
|
|
178
232
|
{steps.map((step) => (
|
|
179
233
|
<StepCard
|
|
@@ -853,6 +907,19 @@ function badgeStyle(
|
|
|
853
907
|
}
|
|
854
908
|
|
|
855
909
|
const styles: Record<string, React.CSSProperties> = {
|
|
910
|
+
errorOnly: {
|
|
911
|
+
borderBottom: "1px solid hsl(var(--border) / 0.7)",
|
|
912
|
+
background: "hsl(var(--muted) / 0.25)",
|
|
913
|
+
fontSize: 12,
|
|
914
|
+
},
|
|
915
|
+
errorNotice: {
|
|
916
|
+
display: "flex",
|
|
917
|
+
alignItems: "center",
|
|
918
|
+
justifyContent: "space-between",
|
|
919
|
+
gap: 8,
|
|
920
|
+
padding: "8px 12px",
|
|
921
|
+
color: "hsl(var(--muted-foreground))",
|
|
922
|
+
},
|
|
856
923
|
root: {
|
|
857
924
|
borderBottom: "1px solid hsl(var(--border) / 0.7)",
|
|
858
925
|
background: "hsl(var(--muted) / 0.25)",
|