@agent-native/toolkit 0.201.1-nightly-20261005213104 → 0.201.1
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/agentkit/react/components.d.ts.map +1 -1
- package/dist/app/agentkit/react/components.js +21 -13
- package/dist/app/agentkit/react/components.js.map +1 -1
- package/dist/app/agentkit/react/context.d.ts +15 -1
- package/dist/app/agentkit/react/context.d.ts.map +1 -1
- package/dist/app/agentkit/react/context.js +30 -4
- package/dist/app/agentkit/react/context.js.map +1 -1
- package/dist/app/agentkit/react/styles.css +11 -7
- package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
- package/dist/app/chat/AgentKitAssistantChat.js +9 -4
- package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
- package/dist/app/chat/FileStorageSetupPopover.d.ts.map +1 -1
- package/dist/app/chat/FileStorageSetupPopover.js +3 -2
- package/dist/app/chat/FileStorageSetupPopover.js.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.js +11 -5
- 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 +11 -5
- package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
- package/dist/app/i18n/catalogs/en-US.d.ts +11 -5
- package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/en-US.js +11 -5
- 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 +11 -5
- 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 +11 -5
- 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 +11 -5
- 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 +11 -5
- 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 +11 -5
- 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 +11 -5
- 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 +11 -5
- 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 +11 -5
- package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
- package/dist/app/onboarding/BuilderIncludedServices.d.ts +23 -0
- package/dist/app/onboarding/BuilderIncludedServices.d.ts.map +1 -0
- package/dist/app/onboarding/BuilderIncludedServices.js +67 -0
- package/dist/app/onboarding/BuilderIncludedServices.js.map +1 -0
- package/dist/app/onboarding/FirstRunOnboarding.d.ts.map +1 -1
- package/dist/app/onboarding/FirstRunOnboarding.js +10 -29
- package/dist/app/onboarding/FirstRunOnboarding.js.map +1 -1
- package/dist/app/settings/BuilderConnectPopover.d.ts +1 -2
- package/dist/app/settings/BuilderConnectPopover.d.ts.map +1 -1
- package/dist/app/settings/BuilderConnectPopover.js +35 -21
- package/dist/app/settings/BuilderConnectPopover.js.map +1 -1
- package/dist/app/settings/deferred-builder-connect-popover.d.ts.map +1 -1
- package/dist/app/settings/deferred-builder-connect-popover.js +28 -1
- package/dist/app/settings/deferred-builder-connect-popover.js.map +1 -1
- package/dist/app/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/app/settings/useBuilderStatus.js +8 -1
- package/dist/app/settings/useBuilderStatus.js.map +1 -1
- package/dist/app/styles/tokens/agent-kit.css +23 -11
- package/dist/composer/MessageQueueDrawer.d.ts +5 -0
- package/dist/composer/MessageQueueDrawer.d.ts.map +1 -1
- package/dist/composer/MessageQueueDrawer.js +11 -5
- package/dist/composer/MessageQueueDrawer.js.map +1 -1
- package/package.json +5 -4
- package/src/app/agentkit/react/components.interaction.spec.tsx +13 -5
- package/src/app/agentkit/react/components.tsx +24 -14
- package/src/app/agentkit/react/context.tsx +53 -6
- package/src/app/agentkit/react/styles.css +11 -7
- package/src/app/chat/AgentKitAssistantChat.spec.tsx +35 -16
- package/src/app/chat/AgentKitAssistantChat.tsx +13 -4
- package/src/app/chat/FileStorageSetupPopover.spec.tsx +129 -0
- package/src/app/chat/FileStorageSetupPopover.tsx +10 -3
- package/src/app/i18n/catalogs/ar-SA.ts +14 -5
- package/src/app/i18n/catalogs/de-DE.ts +15 -5
- package/src/app/i18n/catalogs/en-US.ts +14 -5
- package/src/app/i18n/catalogs/es-ES.ts +14 -5
- package/src/app/i18n/catalogs/fr-FR.ts +15 -5
- package/src/app/i18n/catalogs/hi-IN.ts +14 -5
- package/src/app/i18n/catalogs/ja-JP.ts +14 -5
- package/src/app/i18n/catalogs/ko-KR.ts +14 -5
- package/src/app/i18n/catalogs/pt-BR.ts +15 -5
- package/src/app/i18n/catalogs/zh-CN.ts +13 -5
- package/src/app/i18n/catalogs/zh-TW.ts +13 -5
- package/src/app/onboarding/BuilderIncludedServices.tsx +263 -0
- package/src/app/onboarding/FirstRunOnboarding.spec.tsx +23 -8
- package/src/app/onboarding/FirstRunOnboarding.tsx +22 -112
- package/src/app/settings/BuilderConnectPopover.spec.tsx +175 -6
- package/src/app/settings/BuilderConnectPopover.tsx +87 -67
- package/src/app/settings/deferred-builder-connect-popover.tsx +46 -0
- package/src/app/settings/model/ModelSettingsPage.spec.tsx +8 -24
- package/src/app/settings/useBuilderStatus.spec.tsx +5 -0
- package/src/app/settings/useBuilderStatus.ts +8 -0
- package/src/app/styles/agent-native.spec.ts +5 -8
- package/src/app/styles/tokens/agent-kit.css +23 -11
- package/src/composer/MessageQueueDrawer.spec.tsx +20 -7
- package/src/composer/MessageQueueDrawer.tsx +47 -21
|
@@ -1,15 +1,55 @@
|
|
|
1
1
|
// @vitest-environment happy-dom
|
|
2
2
|
|
|
3
|
+
import { TooltipProvider } from "@agent-native/toolkit/ui/tooltip";
|
|
3
4
|
import React, { act } from "react";
|
|
4
5
|
import { createRoot, type Root } from "react-dom/client";
|
|
5
6
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
6
7
|
|
|
7
8
|
vi.mock("@agent-native/core/client/i18n", () => ({
|
|
8
|
-
useT:
|
|
9
|
-
options
|
|
9
|
+
useT:
|
|
10
|
+
() => (_key: string, options?: { defaultValue?: string; count?: number }) =>
|
|
11
|
+
(options?.defaultValue ?? _key).replace(
|
|
12
|
+
"{{count}}",
|
|
13
|
+
String(options?.count ?? ""),
|
|
14
|
+
),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
vi.mock("@agent-native/core/client/onboarding/use-onboarding", () => ({
|
|
18
|
+
useOnboarding: () => ({
|
|
19
|
+
loading: false,
|
|
20
|
+
error: null,
|
|
21
|
+
profile: {
|
|
22
|
+
capabilities: [
|
|
23
|
+
{
|
|
24
|
+
id: "llm",
|
|
25
|
+
label: "AI model",
|
|
26
|
+
required: true,
|
|
27
|
+
builderIncluded: true,
|
|
28
|
+
service: "model",
|
|
29
|
+
keySummary: "Connect your own AI model",
|
|
30
|
+
why: "The agent uses a language model.",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "design-system-intelligence",
|
|
34
|
+
label: "Design system intelligence",
|
|
35
|
+
required: false,
|
|
36
|
+
builderIncluded: true,
|
|
37
|
+
service: "design-system-intelligence",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "background-agents",
|
|
41
|
+
label: "Background agents",
|
|
42
|
+
required: false,
|
|
43
|
+
builderIncluded: true,
|
|
44
|
+
service: "background-agents",
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
10
49
|
}));
|
|
11
50
|
|
|
12
51
|
import { BuilderConnectPopover } from "./BuilderConnectPopover.js";
|
|
52
|
+
import { DeferredBuilderConnectPopover } from "./deferred-builder-connect-popover.js";
|
|
13
53
|
|
|
14
54
|
let container: HTMLDivElement;
|
|
15
55
|
let root: Root;
|
|
@@ -46,7 +86,7 @@ function click(element: HTMLElement) {
|
|
|
46
86
|
}
|
|
47
87
|
|
|
48
88
|
function render(node: React.ReactElement) {
|
|
49
|
-
act(() => root.render(node));
|
|
89
|
+
act(() => root.render(React.createElement(TooltipProvider, null, node)));
|
|
50
90
|
}
|
|
51
91
|
|
|
52
92
|
function trigger() {
|
|
@@ -57,6 +97,23 @@ function trigger() {
|
|
|
57
97
|
}
|
|
58
98
|
|
|
59
99
|
describe("BuilderConnectPopover before the status read resolves", () => {
|
|
100
|
+
it("starts the OAuth path from the original trigger click", () => {
|
|
101
|
+
const flow = {
|
|
102
|
+
connecting: false,
|
|
103
|
+
start: vi.fn(),
|
|
104
|
+
statusResolved: true,
|
|
105
|
+
agentNativeProvisioningEnabled: false,
|
|
106
|
+
accountExists: false,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
render(
|
|
110
|
+
React.createElement(DeferredBuilderConnectPopover, { flow }, trigger()),
|
|
111
|
+
);
|
|
112
|
+
click(connectButton());
|
|
113
|
+
|
|
114
|
+
expect(flow.start).toHaveBeenCalledWith({ provisionAccount: false });
|
|
115
|
+
});
|
|
116
|
+
|
|
60
117
|
it("uses existing-account sign-in when provisioning is unavailable", () => {
|
|
61
118
|
const onConnect = vi.fn();
|
|
62
119
|
const flow = {
|
|
@@ -182,6 +239,120 @@ describe("BuilderConnectPopover before the status read resolves", () => {
|
|
|
182
239
|
expect(onConnect).toHaveBeenCalledWith(true);
|
|
183
240
|
});
|
|
184
241
|
|
|
242
|
+
it("shows one sign-in action when Builder reports an existing account", () => {
|
|
243
|
+
const onConnect = vi.fn();
|
|
244
|
+
const flow = {
|
|
245
|
+
connecting: false,
|
|
246
|
+
start: vi.fn(),
|
|
247
|
+
statusResolved: true,
|
|
248
|
+
agentNativeProvisioningEnabled: true,
|
|
249
|
+
accountExists: true,
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
render(
|
|
253
|
+
React.createElement(
|
|
254
|
+
BuilderConnectPopover,
|
|
255
|
+
{
|
|
256
|
+
flow,
|
|
257
|
+
onConnect,
|
|
258
|
+
contentTestId: "consent",
|
|
259
|
+
primaryTestId: "create",
|
|
260
|
+
secondaryTestId: "sign-in",
|
|
261
|
+
},
|
|
262
|
+
trigger(),
|
|
263
|
+
),
|
|
264
|
+
);
|
|
265
|
+
expect(document.querySelector("[data-testid='consent']")).toBeNull();
|
|
266
|
+
click(connectButton());
|
|
267
|
+
|
|
268
|
+
const consent = document.querySelector("[data-testid='consent']");
|
|
269
|
+
expect(consent?.textContent).toContain("builderActivateTitle");
|
|
270
|
+
expect(consent?.querySelector("p[role='status']")?.textContent).toBe(
|
|
271
|
+
"You already have a Builder.io account",
|
|
272
|
+
);
|
|
273
|
+
expect(consent?.textContent).toContain("Included free");
|
|
274
|
+
expect(consent?.textContent).not.toContain(
|
|
275
|
+
"Included free with a Builder.io account",
|
|
276
|
+
);
|
|
277
|
+
expect(consent?.textContent).toContain("60 monthly Agent Credits");
|
|
278
|
+
expect(consent?.textContent).toContain("+ 2 more services");
|
|
279
|
+
const services = consent?.querySelector<HTMLElement>(
|
|
280
|
+
"[data-testid='builder-included-services']",
|
|
281
|
+
);
|
|
282
|
+
const servicesToggle = services?.querySelector<HTMLButtonElement>(
|
|
283
|
+
"button[aria-expanded]",
|
|
284
|
+
);
|
|
285
|
+
expect(servicesToggle?.getAttribute("aria-expanded")).toBe("false");
|
|
286
|
+
expect(
|
|
287
|
+
Array.from(
|
|
288
|
+
servicesToggle?.querySelectorAll(":scope > span > span") ?? [],
|
|
289
|
+
).map((line) => line.textContent),
|
|
290
|
+
).toEqual([
|
|
291
|
+
"Included free",
|
|
292
|
+
"60 monthly Agent Credits",
|
|
293
|
+
"+ 2 more services",
|
|
294
|
+
]);
|
|
295
|
+
expect(
|
|
296
|
+
consent?.querySelector<HTMLButtonElement>("[data-testid='create']")
|
|
297
|
+
?.textContent,
|
|
298
|
+
).toBe("agentChat.onboarding.builderSignInWithAccount");
|
|
299
|
+
expect(
|
|
300
|
+
consent?.querySelector<HTMLButtonElement>("[data-testid='sign-in']"),
|
|
301
|
+
).toBeNull();
|
|
302
|
+
expect(
|
|
303
|
+
consent?.querySelector<HTMLButtonElement>("[data-testid='create'] svg"),
|
|
304
|
+
).toBeNull();
|
|
305
|
+
expect(consent?.textContent).not.toContain("agentChat.auth.logIn");
|
|
306
|
+
|
|
307
|
+
click(servicesToggle!);
|
|
308
|
+
expect(servicesToggle?.getAttribute("aria-expanded")).toBe("true");
|
|
309
|
+
click(consent?.querySelector("[data-testid='create']") as HTMLElement);
|
|
310
|
+
expect(onConnect).toHaveBeenCalledWith(false);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it("reopens the same account choices when activation finds an existing account", () => {
|
|
314
|
+
const flow = {
|
|
315
|
+
connecting: false,
|
|
316
|
+
start: vi.fn(),
|
|
317
|
+
statusResolved: true,
|
|
318
|
+
agentNativeProvisioningEnabled: true,
|
|
319
|
+
accountExists: false,
|
|
320
|
+
};
|
|
321
|
+
const props = {
|
|
322
|
+
flow,
|
|
323
|
+
contentTestId: "consent",
|
|
324
|
+
primaryTestId: "create",
|
|
325
|
+
secondaryTestId: "sign-in",
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
render(React.createElement(BuilderConnectPopover, props, trigger()));
|
|
329
|
+
click(connectButton());
|
|
330
|
+
click(
|
|
331
|
+
document.querySelector(
|
|
332
|
+
"[data-testid='consent'] [data-testid='create']",
|
|
333
|
+
) as HTMLElement,
|
|
334
|
+
);
|
|
335
|
+
expect(flow.start).toHaveBeenCalledWith({ provisionAccount: true });
|
|
336
|
+
|
|
337
|
+
render(
|
|
338
|
+
React.createElement(
|
|
339
|
+
BuilderConnectPopover,
|
|
340
|
+
{ ...props, flow: { ...flow, accountExists: true } },
|
|
341
|
+
trigger(),
|
|
342
|
+
),
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
const consent = document.querySelector("[data-testid='consent']");
|
|
346
|
+
expect(consent?.querySelector("p[role='status']")?.textContent).toBe(
|
|
347
|
+
"You already have a Builder.io account",
|
|
348
|
+
);
|
|
349
|
+
expect(consent?.querySelector("[data-testid='create']")).not.toBeNull();
|
|
350
|
+
expect(consent?.querySelector("[data-testid='sign-in']")).toBeNull();
|
|
351
|
+
|
|
352
|
+
click(consent?.querySelector("[data-testid='create']") as HTMLElement);
|
|
353
|
+
expect(flow.start).toHaveBeenLastCalledWith({ provisionAccount: false });
|
|
354
|
+
});
|
|
355
|
+
|
|
185
356
|
it("stacks the create and sign-in buttons together with the terms below them", () => {
|
|
186
357
|
const flow = {
|
|
187
358
|
connecting: false,
|
|
@@ -225,9 +396,7 @@ describe("BuilderConnectPopover before the status read resolves", () => {
|
|
|
225
396
|
p.querySelector("a"),
|
|
226
397
|
);
|
|
227
398
|
expect(create && signIn && terms).toBeTruthy();
|
|
228
|
-
expect(consent?.textContent).toContain(
|
|
229
|
-
"Included free with a Builder.io account",
|
|
230
|
-
);
|
|
399
|
+
expect(consent?.textContent).toContain("Included free");
|
|
231
400
|
expect(consent?.textContent).toContain("60 monthly Agent Credits");
|
|
232
401
|
expect(signIn?.parentElement).toBe(create?.parentElement);
|
|
233
402
|
expect(create!.compareDocumentPosition(signIn!)).toBe(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
+
import { useOnboarding } from "@agent-native/core/client/onboarding/use-onboarding";
|
|
2
3
|
import { Button } from "@agent-native/toolkit/ui/button";
|
|
3
4
|
import {
|
|
4
5
|
Popover,
|
|
@@ -6,9 +7,12 @@ import {
|
|
|
6
7
|
PopoverTrigger,
|
|
7
8
|
} from "@agent-native/toolkit/ui/popover";
|
|
8
9
|
import { Spinner } from "@agent-native/toolkit/ui/spinner";
|
|
9
|
-
import { IconArrowRight } from "@tabler/icons-react";
|
|
10
10
|
import React, { useEffect, useRef, useState } from "react";
|
|
11
11
|
|
|
12
|
+
import {
|
|
13
|
+
BuilderIncludedBenefitsDisclosure,
|
|
14
|
+
getBuilderIncludedCapabilities,
|
|
15
|
+
} from "../onboarding/BuilderIncludedServices.js";
|
|
12
16
|
import type { BuilderConnectFlow } from "./useBuilderStatus.js";
|
|
13
17
|
|
|
14
18
|
type BuilderConnectTrigger = React.ReactElement<{
|
|
@@ -19,13 +23,12 @@ type BuilderConnectTrigger = React.ReactElement<{
|
|
|
19
23
|
|
|
20
24
|
export interface BuilderConnectPopoverProps {
|
|
21
25
|
flow: Pick<BuilderConnectFlow, "connecting" | "start"> & {
|
|
26
|
+
accountExists?: boolean;
|
|
22
27
|
cancel?: BuilderConnectFlow["cancel"];
|
|
23
28
|
agentNativeProvisioningEnabled?: boolean;
|
|
24
|
-
accountExists?: boolean;
|
|
25
29
|
retry?: () => boolean | void;
|
|
26
30
|
statusResolved?: boolean;
|
|
27
31
|
statusReadSettledCount?: number;
|
|
28
|
-
canConnect?: BuilderConnectFlow["canConnect"];
|
|
29
32
|
provisionAccount?: boolean;
|
|
30
33
|
};
|
|
31
34
|
children: BuilderConnectTrigger;
|
|
@@ -49,30 +52,31 @@ export function BuilderConnectPopover({
|
|
|
49
52
|
}: BuilderConnectPopoverProps) {
|
|
50
53
|
const t = useT();
|
|
51
54
|
const [open, setOpen] = useState(false);
|
|
55
|
+
const provisioningAttemptRef = useRef(false);
|
|
52
56
|
const capabilityResolved = flow.statusResolved === true;
|
|
53
57
|
const showPopover =
|
|
54
58
|
(defaultProvisionAccount && !capabilityResolved) ||
|
|
55
59
|
(capabilityResolved && flow.agentNativeProvisioningEnabled === true);
|
|
56
|
-
const accountExists = capabilityResolved && flow.accountExists;
|
|
57
|
-
const initiatedByThisTriggerRef = useRef(false);
|
|
58
60
|
const [queuedClick, setQueuedClick] = useState<{ settledAt: number } | null>(
|
|
59
61
|
null,
|
|
60
62
|
);
|
|
61
63
|
const settledCount = flow.statusReadSettledCount ?? 0;
|
|
62
64
|
|
|
63
65
|
useEffect(() => {
|
|
64
|
-
if (accountExists &&
|
|
65
|
-
|
|
66
|
+
if (flow.accountExists && provisioningAttemptRef.current) {
|
|
67
|
+
provisioningAttemptRef.current = false;
|
|
66
68
|
setOpen(true);
|
|
69
|
+
} else if (!flow.connecting) {
|
|
70
|
+
provisioningAttemptRef.current = false;
|
|
67
71
|
}
|
|
68
|
-
}, [accountExists]);
|
|
72
|
+
}, [flow.accountExists, flow.connecting]);
|
|
69
73
|
|
|
70
74
|
const start = (provisionAccount?: boolean) => {
|
|
71
75
|
const shouldProvision =
|
|
72
76
|
provisionAccount ??
|
|
73
77
|
(flow.agentNativeProvisioningEnabled === true &&
|
|
74
78
|
(defaultProvisionAccount || flow.provisionAccount === true));
|
|
75
|
-
|
|
79
|
+
if (shouldProvision) provisioningAttemptRef.current = true;
|
|
76
80
|
setOpen(false);
|
|
77
81
|
if (onConnect) {
|
|
78
82
|
onConnect(shouldProvision);
|
|
@@ -139,11 +143,11 @@ export function BuilderConnectPopover({
|
|
|
139
143
|
if (!showPopover) {
|
|
140
144
|
return cancelAction ? (
|
|
141
145
|
<span className="inline-flex max-w-full items-center gap-2">
|
|
142
|
-
{trigger}
|
|
146
|
+
<span className="contents">{trigger}</span>
|
|
143
147
|
{cancelAction}
|
|
144
148
|
</span>
|
|
145
149
|
) : (
|
|
146
|
-
trigger
|
|
150
|
+
<span className="contents">{trigger}</span>
|
|
147
151
|
);
|
|
148
152
|
}
|
|
149
153
|
|
|
@@ -151,60 +155,50 @@ export function BuilderConnectPopover({
|
|
|
151
155
|
<Popover open={open} onOpenChange={setOpen}>
|
|
152
156
|
<PopoverTrigger asChild>{trigger}</PopoverTrigger>
|
|
153
157
|
<PopoverContent
|
|
154
|
-
align="
|
|
155
|
-
side="
|
|
156
|
-
sideOffset={
|
|
158
|
+
align="center"
|
|
159
|
+
side="right"
|
|
160
|
+
sideOffset={8}
|
|
157
161
|
aria-labelledby="builder-connect-popover-title"
|
|
158
162
|
data-testid={contentTestId}
|
|
159
|
-
className="z-[330] w-80 max-w-[calc(100vw-2rem)] p-3 text-left"
|
|
163
|
+
className="z-[330] max-h-[min(640px,calc(100dvh-2rem),var(--radix-popover-content-available-height))] w-80 max-w-[calc(100vw-2rem)] overflow-y-auto p-3 text-left"
|
|
160
164
|
>
|
|
161
165
|
<div className="space-y-2.5">
|
|
162
166
|
<h2
|
|
163
167
|
id="builder-connect-popover-title"
|
|
164
168
|
className="text-sm font-semibold text-foreground"
|
|
165
169
|
>
|
|
166
|
-
{
|
|
167
|
-
? t("agentChat.onboarding.builderAccountExistsTitle")
|
|
168
|
-
: t("agentChat.onboarding.builderActivateTitle")}
|
|
170
|
+
{t("agentChat.onboarding.builderActivateTitle")}
|
|
169
171
|
</h2>
|
|
170
|
-
<p
|
|
171
|
-
{accountExists
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
172
|
+
<p
|
|
173
|
+
role={flow.accountExists ? "status" : undefined}
|
|
174
|
+
className="text-xs leading-5 text-muted-foreground"
|
|
175
|
+
>
|
|
176
|
+
{flow.accountExists
|
|
177
|
+
? t("agentChat.onboarding.builderAccountExistsTitle", {
|
|
178
|
+
defaultValue: "You already have a Builder.io account",
|
|
179
|
+
})
|
|
180
|
+
: t("agentChat.onboarding.builderActivationDescription", {
|
|
181
|
+
defaultValue:
|
|
182
|
+
"Create or connect a Builder.io account in one click to get free credits.",
|
|
183
|
+
})}
|
|
176
184
|
</p>
|
|
177
|
-
<
|
|
178
|
-
<p className="text-[13px] font-semibold text-foreground">
|
|
179
|
-
{t("agentChat.onboarding.builderIncludedFreeWithAccount", {
|
|
180
|
-
defaultValue: "Included free with a Builder.io account",
|
|
181
|
-
})}
|
|
182
|
-
</p>
|
|
183
|
-
<p className="text-xs font-medium text-emerald-700 dark:text-emerald-400">
|
|
184
|
-
{t("agentChat.onboarding.builderMonthlyCredits", {
|
|
185
|
-
defaultValue: "60 monthly Agent Credits",
|
|
186
|
-
})}
|
|
187
|
-
</p>
|
|
188
|
-
</div>
|
|
185
|
+
<BuilderConnectIncludedServices />
|
|
189
186
|
<div className="flex flex-col gap-2">
|
|
190
187
|
<Button
|
|
191
188
|
type="button"
|
|
192
189
|
data-testid={primaryTestId}
|
|
193
190
|
className="w-full"
|
|
194
|
-
onClick={() => start(accountExists
|
|
191
|
+
onClick={() => start(!flow.accountExists)}
|
|
195
192
|
disabled={flow.connecting}
|
|
196
193
|
>
|
|
197
194
|
{flow.connecting ? <Spinner aria-hidden /> : null}
|
|
198
|
-
{accountExists
|
|
199
|
-
? t("agentChat.
|
|
195
|
+
{flow.accountExists
|
|
196
|
+
? t("agentChat.onboarding.builderSignInWithAccount")
|
|
200
197
|
: flow.connecting
|
|
201
198
|
? t("agentChat.onboarding.builderActivating")
|
|
202
199
|
: t("agentChat.onboarding.builderCreateAndActivate")}
|
|
203
|
-
{!accountExists && !flow.connecting ? (
|
|
204
|
-
<IconArrowRight aria-hidden />
|
|
205
|
-
) : null}
|
|
206
200
|
</Button>
|
|
207
|
-
{!accountExists
|
|
201
|
+
{!flow.accountExists ? (
|
|
208
202
|
<Button
|
|
209
203
|
type="button"
|
|
210
204
|
variant="secondary"
|
|
@@ -215,31 +209,29 @@ export function BuilderConnectPopover({
|
|
|
215
209
|
>
|
|
216
210
|
{t("agentChat.onboarding.builderExistingAccount")}
|
|
217
211
|
</Button>
|
|
218
|
-
)}
|
|
212
|
+
) : null}
|
|
219
213
|
</div>
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
</p>
|
|
242
|
-
)}
|
|
214
|
+
<p className="text-[11px] leading-4 text-muted-foreground">
|
|
215
|
+
{t("agentChat.onboarding.builderConsentPrefix")}{" "}
|
|
216
|
+
<a
|
|
217
|
+
href="https://www.builder.io/legal/terms"
|
|
218
|
+
target="_blank"
|
|
219
|
+
rel="noreferrer"
|
|
220
|
+
className="underline underline-offset-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
221
|
+
>
|
|
222
|
+
{t("agentChat.onboarding.builderTerms")}
|
|
223
|
+
</a>{" "}
|
|
224
|
+
{t("agentChat.onboarding.builderConsentAnd")}{" "}
|
|
225
|
+
<a
|
|
226
|
+
href="https://www.builder.io/legal/privacy"
|
|
227
|
+
target="_blank"
|
|
228
|
+
rel="noreferrer"
|
|
229
|
+
className="underline underline-offset-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
230
|
+
>
|
|
231
|
+
{t("agentChat.onboarding.builderPrivacy")}
|
|
232
|
+
</a>
|
|
233
|
+
.
|
|
234
|
+
</p>
|
|
243
235
|
</div>
|
|
244
236
|
</PopoverContent>
|
|
245
237
|
</Popover>
|
|
@@ -254,3 +246,31 @@ export function BuilderConnectPopover({
|
|
|
254
246
|
popover
|
|
255
247
|
);
|
|
256
248
|
}
|
|
249
|
+
|
|
250
|
+
function BuilderConnectIncludedServices() {
|
|
251
|
+
const t = useT();
|
|
252
|
+
const { profile, loading, error } = useOnboarding();
|
|
253
|
+
const capabilities = profile
|
|
254
|
+
? getBuilderIncludedCapabilities(profile.capabilities)
|
|
255
|
+
: [];
|
|
256
|
+
|
|
257
|
+
return (
|
|
258
|
+
<BuilderIncludedBenefitsDisclosure
|
|
259
|
+
capabilities={capabilities}
|
|
260
|
+
includedLabel={t("agentChat.onboarding.builderIncludedFree", {
|
|
261
|
+
defaultValue: "Included free",
|
|
262
|
+
})}
|
|
263
|
+
creditsLabel={t("agentChat.onboarding.builderMonthlyCredits", {
|
|
264
|
+
defaultValue: "60 monthly Agent Credits",
|
|
265
|
+
})}
|
|
266
|
+
loading={loading}
|
|
267
|
+
loadingLabel={t("agentChat.common.loading")}
|
|
268
|
+
error={
|
|
269
|
+
error || (!loading && !profile)
|
|
270
|
+
? t("agentChat.common.chunkLoadFailed")
|
|
271
|
+
: null
|
|
272
|
+
}
|
|
273
|
+
testId="builder-included-services"
|
|
274
|
+
/>
|
|
275
|
+
);
|
|
276
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
+
import { Button } from "@agent-native/toolkit/ui/button";
|
|
1
3
|
import { cloneElement, lazy, Suspense } from "react";
|
|
2
4
|
|
|
3
5
|
import { LazyChunkErrorBoundary } from "../shared/LazyChunkErrorBoundary.js";
|
|
@@ -15,6 +17,50 @@ export { LazyChunkRetryFallback } from "../shared/LazyChunkRetryFallback.js";
|
|
|
15
17
|
export function DeferredBuilderConnectPopover(
|
|
16
18
|
props: BuilderConnectPopoverProps,
|
|
17
19
|
) {
|
|
20
|
+
const t = useT();
|
|
21
|
+
if (
|
|
22
|
+
props.flow.statusResolved === true &&
|
|
23
|
+
props.flow.agentNativeProvisioningEnabled !== true
|
|
24
|
+
) {
|
|
25
|
+
// Keep OAuth in the trusted click and avoid loading popover UI for sign-in-only flows.
|
|
26
|
+
const trigger = cloneElement(props.children, {
|
|
27
|
+
"aria-busy": undefined,
|
|
28
|
+
onClick: (event) => {
|
|
29
|
+
if (props.flow.connecting) {
|
|
30
|
+
event.preventDefault();
|
|
31
|
+
event.stopPropagation();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
props.children.props.onClick?.(event);
|
|
35
|
+
props.onTriggerClick?.(event);
|
|
36
|
+
if (event.defaultPrevented) return;
|
|
37
|
+
if (props.onConnect) props.onConnect(false);
|
|
38
|
+
else props.flow.start({ provisionAccount: false });
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
const cancelAction =
|
|
42
|
+
props.flow.connecting && props.flow.cancel ? (
|
|
43
|
+
<Button
|
|
44
|
+
type="button"
|
|
45
|
+
variant="ghost"
|
|
46
|
+
size="sm"
|
|
47
|
+
className="shrink-0"
|
|
48
|
+
onClick={props.flow.cancel}
|
|
49
|
+
>
|
|
50
|
+
{t("common.cancel")}
|
|
51
|
+
</Button>
|
|
52
|
+
) : null;
|
|
53
|
+
|
|
54
|
+
return cancelAction ? (
|
|
55
|
+
<span className="inline-flex max-w-full items-center gap-2">
|
|
56
|
+
<span className="contents">{trigger}</span>
|
|
57
|
+
{cancelAction}
|
|
58
|
+
</span>
|
|
59
|
+
) : (
|
|
60
|
+
<span className="contents">{trigger}</span>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
18
64
|
return (
|
|
19
65
|
<LazyChunkErrorBoundary fallback={<LazyChunkRetryFallback />}>
|
|
20
66
|
<Suspense
|
|
@@ -85,14 +85,11 @@ vi.mock("@agent-native/core/client/oauth-popup", () => ({
|
|
|
85
85
|
}));
|
|
86
86
|
|
|
87
87
|
vi.mock("../deferred-builder-connect-popover.js", () => ({
|
|
88
|
-
// The real popover asks whether to create an account, then calls onConnect.
|
|
89
88
|
DeferredBuilderConnectPopover: ({
|
|
90
89
|
children,
|
|
91
|
-
onConnect,
|
|
92
90
|
}: {
|
|
93
91
|
children: React.ReactElement<{ onClick?: () => void }>;
|
|
94
|
-
|
|
95
|
-
}) => React.cloneElement(children, { onClick: () => onConnect?.(false) }),
|
|
92
|
+
}) => React.cloneElement(children, { onClick: () => {} }),
|
|
96
93
|
}));
|
|
97
94
|
|
|
98
95
|
vi.mock("../shell/context.js", () => ({
|
|
@@ -388,15 +385,9 @@ describe("ModelSettingsPage", () => {
|
|
|
388
385
|
expect(buttons(row("provider-personal-builder"))).toEqual([
|
|
389
386
|
"Use Builder.io",
|
|
390
387
|
]);
|
|
391
|
-
|
|
392
|
-
(
|
|
393
|
-
|
|
394
|
-
).click();
|
|
395
|
-
});
|
|
396
|
-
expect(state.builder.start).toHaveBeenCalledWith({
|
|
397
|
-
provisionAccount: false,
|
|
398
|
-
scope: "personal",
|
|
399
|
-
});
|
|
388
|
+
expect(
|
|
389
|
+
row("provider-personal-builder").querySelector("button")?.disabled,
|
|
390
|
+
).toBe(false);
|
|
400
391
|
expect(row("provider-personal-anthropic").textContent).toContain(
|
|
401
392
|
"••••1234 · 2 models",
|
|
402
393
|
);
|
|
@@ -669,17 +660,10 @@ describe("ModelSettingsPage", () => {
|
|
|
669
660
|
expect(
|
|
670
661
|
document.querySelector('[data-testid="provider-dialog"]'),
|
|
671
662
|
).not.toBeNull();
|
|
672
|
-
|
|
673
|
-
(
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
) as HTMLElement
|
|
677
|
-
).click();
|
|
678
|
-
});
|
|
679
|
-
expect(state.builder.start).toHaveBeenCalledWith({
|
|
680
|
-
provisionAccount: false,
|
|
681
|
-
scope: "org",
|
|
682
|
-
});
|
|
663
|
+
const builderButton = [...empty.querySelectorAll("button")].find(
|
|
664
|
+
(button) => button.textContent === "Use Builder.io",
|
|
665
|
+
);
|
|
666
|
+
expect(builderButton?.disabled).toBe(false);
|
|
683
667
|
});
|
|
684
668
|
|
|
685
669
|
it("tells a restricted member with no provider to ask an admin", async () => {
|
|
@@ -265,6 +265,11 @@ describe("useBuilderStatus", () => {
|
|
|
265
265
|
|
|
266
266
|
expect(fetchMock).toHaveBeenCalledWith(
|
|
267
267
|
"/_agent-native/connection-status/builder",
|
|
268
|
+
expect.objectContaining({
|
|
269
|
+
headers: {
|
|
270
|
+
"x-agent-native-preview-origin": "http://localhost:3000",
|
|
271
|
+
},
|
|
272
|
+
}),
|
|
268
273
|
);
|
|
269
274
|
});
|
|
270
275
|
|
|
@@ -127,6 +127,11 @@ export function useBuilderStatus({
|
|
|
127
127
|
try {
|
|
128
128
|
const res = await fetch(
|
|
129
129
|
agentNativePath("/_agent-native/connection-status/builder"),
|
|
130
|
+
{
|
|
131
|
+
headers: {
|
|
132
|
+
"x-agent-native-preview-origin": window.location.origin,
|
|
133
|
+
},
|
|
134
|
+
},
|
|
130
135
|
);
|
|
131
136
|
if (!res.ok) {
|
|
132
137
|
keepLastGoodStatus(`Builder status unavailable (${res.status})`);
|
|
@@ -926,6 +931,9 @@ export function useBuilderConnectFlow(
|
|
|
926
931
|
);
|
|
927
932
|
}
|
|
928
933
|
const r = await fetch(statusUrl.href, {
|
|
934
|
+
headers: {
|
|
935
|
+
"x-agent-native-preview-origin": window.location.origin,
|
|
936
|
+
},
|
|
929
937
|
signal: signal ?? ownController?.signal,
|
|
930
938
|
});
|
|
931
939
|
if (!r.ok) return null;
|
|
@@ -261,34 +261,31 @@ describe("agent-native shell surface tokens", () => {
|
|
|
261
261
|
/\.agent-sidebar-panel\[data-agent-sidebar-animation="drawer"\][\s\S]*?box-shadow: var\(--agent-kit-drawer-elevation\);/s,
|
|
262
262
|
);
|
|
263
263
|
expect(tokens).toMatch(
|
|
264
|
-
|
|
264
|
+
/:is\(\.dark, :root\[data-theme="dark"\]:not\(\.light\)\)\s*\{[\s\S]*?--agent-kit-shadow-color: var\(--background\);[\s\S]*?--agent-kit-drawer-elevation:/s,
|
|
265
265
|
);
|
|
266
266
|
expect(css).not.toContain("hsl(var(--foreground) / 0.07)");
|
|
267
267
|
expect(css).not.toContain("hsl(var(--foreground) / 0.12)");
|
|
268
268
|
expect(css).not.toContain("hsl(var(--agent-shadow)");
|
|
269
269
|
expect(tokens).toContain("--agent-kit-shadow-color: var(--foreground);");
|
|
270
270
|
expect(tokens).toMatch(
|
|
271
|
-
|
|
271
|
+
/:is\(\.dark, :root\[data-theme="dark"\]:not\(\.light\)\)\s*\{[\s\S]*?--agent-kit-shadow-color: var\(--background\);[\s\S]*?--agent-kit-composer-elevation:[\s\S]*?hsl\(var\(--agent-kit-shadow-color\) \/ 0\.22\)/s,
|
|
272
272
|
);
|
|
273
273
|
expect(css).toMatch(
|
|
274
274
|
/::view-transition-old\(agent-native-sidebar-drawer\),\s*::view-transition-new\(agent-native-sidebar-drawer\)[\s\S]*?height: 100%;/s,
|
|
275
275
|
);
|
|
276
276
|
});
|
|
277
277
|
|
|
278
|
-
it("gives the
|
|
278
|
+
it("gives the composer a quiet boundary in both themes", () => {
|
|
279
279
|
const tokens = readFileSync(
|
|
280
280
|
new URL("./tokens/agent-kit.css", import.meta.url),
|
|
281
281
|
{ encoding: "utf8" },
|
|
282
282
|
);
|
|
283
283
|
|
|
284
284
|
expect(tokens).toMatch(
|
|
285
|
-
/:root\s*\{[\s\S]*?--agent-kit-composer-border-
|
|
285
|
+
/:root\s*\{[\s\S]*?--agent-kit-composer-border-mix: 82%;[\s\S]*?--agent-kit-composer-focus-border-mix: 100%;[\s\S]*?--agent-kit-composer-border-color: color-mix\([\s\S]*?--agent-kit-composer-focus-border-color: color-mix\(/s,
|
|
286
286
|
);
|
|
287
287
|
expect(tokens).toMatch(
|
|
288
|
-
|
|
289
|
-
);
|
|
290
|
-
expect(tokens).toMatch(
|
|
291
|
-
/\.dark\s*\{[\s\S]*?--agent-kit-composer-border-color: transparent;[\s\S]*?--agent-kit-composer-focus-border-color: transparent;/s,
|
|
288
|
+
/:is\(\.dark, :root\[data-theme="dark"\]:not\(\.light\)\)\s*\{[\s\S]*?--agent-kit-composer-border-mix: 40%;[\s\S]*?--agent-kit-composer-focus-border-mix: 65%;[\s\S]*?--agent-kit-composer-border-color: color-mix\([\s\S]*?--agent-kit-composer-focus-border-color: color-mix\(/s,
|
|
292
289
|
);
|
|
293
290
|
});
|
|
294
291
|
|