@agent-native/core 0.178.1 → 0.178.2-nightly-20260910195009
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/corpus/templates/analytics/app/components/layout/Sidebar.tsx +108 -121
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +87 -220
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +83 -221
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +324 -460
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +57 -247
- package/corpus/templates/clips/app/components/library/library-layout.tsx +15 -48
- package/corpus/templates/clips/changelog/2026-09-10-open-mcp-connections-in-new-tabs.md +1 -0
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +84 -94
- package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +1 -1
- package/corpus/templates/crm/app/components/layout/CrmSidebar.tsx +108 -296
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +55 -212
- package/corpus/templates/factory/app/components/layout/Sidebar.tsx +72 -260
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +143 -362
- package/corpus/templates/macros/app/components/layout/AppLayout.tsx +64 -159
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +152 -165
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +82 -207
- package/corpus/templates/slides/app/components/layout/Sidebar.tsx +61 -234
- package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +73 -225
- package/dist/automation/index.d.ts +1 -1
- package/dist/client/EnvironmentBadge.d.ts +7 -4
- package/dist/client/EnvironmentBadge.js +26 -18
- package/dist/client/FeedbackButton.js +23 -8
- package/dist/client/app-providers.js +1 -1
- package/dist/client/auth/AuthPage.js +0 -38
- package/dist/client/components/icons/AgentNativeIcon.js +1 -1
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +1 -0
- package/dist/client/ui/AppSidebar.d.ts +15 -0
- package/dist/client/ui/AppSidebar.js +34 -0
- package/dist/client/ui/index.d.ts +1 -0
- package/dist/client/ui/index.js +1 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.js +19 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
- package/dist/provider-api/actions/provider-api.d.ts +15 -15
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/beta-opt-out-html.js +2 -2
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +57 -247
- package/dist/vite/client.js +4 -1
- package/docs/content/template-clips-anonymous-intake.mdx +7 -5
- package/docs/content/template-clips-developers.mdx +1 -1
- package/package.json +3 -3
- package/src/templates/chat/app/components/layout/Sidebar.tsx +57 -247
|
@@ -1,36 +1,27 @@
|
|
|
1
1
|
import { useT } from "@agent-native/core/client/i18n";
|
|
2
2
|
import { openCommandMenu } from "@agent-native/core/client/navigation";
|
|
3
3
|
import { OrgSwitcher } from "@agent-native/core/client/org";
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
AppSidebar,
|
|
6
|
+
FeedbackButton,
|
|
7
|
+
type AppSidebarItemDefinition,
|
|
8
|
+
} from "@agent-native/core/client/ui";
|
|
6
9
|
import {
|
|
7
10
|
IconCheckbox,
|
|
8
11
|
IconForms,
|
|
9
12
|
IconInbox,
|
|
10
|
-
IconLayoutSidebarLeftCollapse,
|
|
11
|
-
IconLayoutSidebarLeftExpand,
|
|
12
13
|
IconSearch,
|
|
13
14
|
IconSettings,
|
|
14
15
|
} from "@tabler/icons-react";
|
|
15
|
-
import {
|
|
16
|
+
import { useLocation } from "react-router";
|
|
16
17
|
|
|
18
|
+
import { Button } from "@/components/ui/button";
|
|
17
19
|
import {
|
|
18
20
|
Tooltip,
|
|
19
21
|
TooltipContent,
|
|
20
22
|
TooltipTrigger,
|
|
21
23
|
} from "@/components/ui/tooltip";
|
|
22
24
|
import { APP_TITLE } from "@/lib/app-config";
|
|
23
|
-
import { cn } from "@/lib/utils";
|
|
24
|
-
|
|
25
|
-
const NAV_ITEMS = [
|
|
26
|
-
{ icon: IconInbox, labelKey: "sidebar.navInbox", href: "/inbox" },
|
|
27
|
-
{ icon: IconCheckbox, labelKey: "sidebar.navTasks", href: "/tasks" },
|
|
28
|
-
{ icon: IconForms, labelKey: "sidebar.navFields", href: "/fields" },
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
const BOTTOM_NAV_ITEMS = [
|
|
32
|
-
{ icon: IconSettings, labelKey: "header.pageSettings", href: "/settings" },
|
|
33
|
-
];
|
|
34
25
|
|
|
35
26
|
interface SidebarProps {
|
|
36
27
|
collapsed?: boolean;
|
|
@@ -45,228 +36,85 @@ export function Sidebar({
|
|
|
45
36
|
}: SidebarProps) {
|
|
46
37
|
const t = useT();
|
|
47
38
|
const location = useLocation();
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
39
|
+
|
|
40
|
+
const items: AppSidebarItemDefinition[] = [
|
|
41
|
+
{
|
|
42
|
+
to: "/inbox",
|
|
43
|
+
label: t("sidebar.navInbox"),
|
|
44
|
+
icon: IconInbox,
|
|
45
|
+
active: location.pathname.startsWith("/inbox"),
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
to: "/tasks",
|
|
49
|
+
label: t("sidebar.navTasks"),
|
|
50
|
+
icon: IconCheckbox,
|
|
51
|
+
active: location.pathname.startsWith("/tasks"),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
to: "/fields",
|
|
55
|
+
label: t("sidebar.navFields"),
|
|
56
|
+
icon: IconForms,
|
|
57
|
+
active: location.pathname.startsWith("/fields"),
|
|
58
|
+
},
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
const secondaryItems: AppSidebarItemDefinition[] = [
|
|
62
|
+
{
|
|
63
|
+
to: "/settings",
|
|
64
|
+
label: t("header.pageSettings"),
|
|
65
|
+
icon: IconSettings,
|
|
66
|
+
active: location.pathname.startsWith("/settings"),
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
const feedbackButton = (
|
|
71
|
+
<FeedbackButton variant={collapsed ? "icon" : "sidebar"} side="right" />
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const orgSwitcher = (
|
|
75
|
+
<OrgSwitcher
|
|
76
|
+
compact={collapsed}
|
|
77
|
+
reserveSpace
|
|
78
|
+
// Tasks does not mount /agent, so the default link would 404.
|
|
79
|
+
agentPath={null}
|
|
80
|
+
className={
|
|
81
|
+
collapsed
|
|
82
|
+
? "!size-9 !p-0 [&>svg]:!size-4 !bg-transparent !text-primary hover:!bg-accent/60 hover:!text-primary"
|
|
83
|
+
: "min-w-0 flex-1 !bg-transparent !text-primary hover:!bg-accent/60 hover:!text-primary"
|
|
84
|
+
}
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
|
|
89
88
|
const searchButton = (
|
|
90
89
|
<Tooltip>
|
|
91
90
|
<TooltipTrigger asChild>
|
|
92
|
-
<
|
|
91
|
+
<Button
|
|
93
92
|
type="button"
|
|
93
|
+
variant="ghost"
|
|
94
|
+
size="icon"
|
|
95
|
+
className="size-9 shrink-0 text-primary hover:bg-accent/60 hover:text-primary"
|
|
94
96
|
onClick={openCommandMenu}
|
|
95
97
|
aria-label={t("sidebar.search")}
|
|
96
|
-
className="flex size-8 items-center justify-center rounded-md text-sidebar-foreground/65 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
97
98
|
>
|
|
98
99
|
<IconSearch className="size-4" />
|
|
99
|
-
</
|
|
100
|
+
</Button>
|
|
100
101
|
</TooltipTrigger>
|
|
101
102
|
<TooltipContent side="right">{t("sidebar.search")}</TooltipContent>
|
|
102
103
|
</Tooltip>
|
|
103
104
|
);
|
|
104
|
-
const feedbackButton = (
|
|
105
|
-
<FeedbackButton
|
|
106
|
-
variant={collapsed ? "icon" : "sidebar"}
|
|
107
|
-
className={collapsed ? "size-8" : "min-w-0"}
|
|
108
|
-
side="right"
|
|
109
|
-
/>
|
|
110
|
-
);
|
|
111
105
|
|
|
112
106
|
return (
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
>
|
|
126
|
-
<Link
|
|
127
|
-
to="/tasks"
|
|
128
|
-
onClick={(event) => {
|
|
129
|
-
if (
|
|
130
|
-
!collapsible ||
|
|
131
|
-
!onCollapsedChange ||
|
|
132
|
-
event.metaKey ||
|
|
133
|
-
event.ctrlKey ||
|
|
134
|
-
event.shiftKey ||
|
|
135
|
-
event.altKey ||
|
|
136
|
-
event.button !== 0
|
|
137
|
-
) {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
event.preventDefault();
|
|
141
|
-
onCollapsedChange(!collapsed);
|
|
142
|
-
}}
|
|
143
|
-
className={cn(
|
|
144
|
-
"flex min-w-0 items-center rounded outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
145
|
-
collapsed ? "size-7 justify-center" : "flex-1 gap-3",
|
|
146
|
-
)}
|
|
147
|
-
aria-label={
|
|
148
|
-
collapsible && onCollapsedChange
|
|
149
|
-
? collapsed
|
|
150
|
-
? t("sidebar.expandSidebar")
|
|
151
|
-
: t("sidebar.collapseSidebar")
|
|
152
|
-
: collapsed
|
|
153
|
-
? APP_TITLE
|
|
154
|
-
: undefined
|
|
155
|
-
}
|
|
156
|
-
>
|
|
157
|
-
<AgentNativeIcon
|
|
158
|
-
aria-hidden="true"
|
|
159
|
-
className="h-3.5 w-6 shrink-0 text-sidebar-accent-foreground"
|
|
160
|
-
/>
|
|
161
|
-
<div className={cn("min-w-0", collapsed && "sr-only")}>
|
|
162
|
-
<p className="truncate text-sm font-semibold text-sidebar-accent-foreground">
|
|
163
|
-
{APP_TITLE}
|
|
164
|
-
</p>
|
|
165
|
-
</div>
|
|
166
|
-
</Link>
|
|
167
|
-
</div>
|
|
168
|
-
|
|
169
|
-
<nav
|
|
170
|
-
className={cn(
|
|
171
|
-
"flex-1 overflow-y-auto",
|
|
172
|
-
collapsed ? "px-0 py-2" : "px-2 py-3",
|
|
173
|
-
)}
|
|
174
|
-
>
|
|
175
|
-
<div className={cn("grid", collapsed ? "gap-0" : "gap-1")}>
|
|
176
|
-
{NAV_ITEMS.map((item) => {
|
|
177
|
-
const Icon = item.icon;
|
|
178
|
-
const isActive = location.pathname.startsWith(item.href);
|
|
179
|
-
const label = t(item.labelKey);
|
|
180
|
-
const link = (
|
|
181
|
-
<Link
|
|
182
|
-
to={item.href}
|
|
183
|
-
className={navClass({ isActive })}
|
|
184
|
-
aria-current={isActive ? "page" : undefined}
|
|
185
|
-
aria-label={collapsed ? label : undefined}
|
|
186
|
-
>
|
|
187
|
-
<Icon className="size-4 shrink-0" />
|
|
188
|
-
<span className={collapsed ? "sr-only" : "truncate"}>
|
|
189
|
-
{label}
|
|
190
|
-
</span>
|
|
191
|
-
</Link>
|
|
192
|
-
);
|
|
193
|
-
return collapsed ? (
|
|
194
|
-
<Tooltip key={item.href}>
|
|
195
|
-
<TooltipTrigger asChild>{link}</TooltipTrigger>
|
|
196
|
-
<TooltipContent side="right">{label}</TooltipContent>
|
|
197
|
-
</Tooltip>
|
|
198
|
-
) : (
|
|
199
|
-
<div key={item.href}>{link}</div>
|
|
200
|
-
);
|
|
201
|
-
})}
|
|
202
|
-
</div>
|
|
203
|
-
</nav>
|
|
204
|
-
|
|
205
|
-
<div
|
|
206
|
-
className={cn(
|
|
207
|
-
"mt-auto shrink-0",
|
|
208
|
-
collapsed && "border-t border-sidebar-border py-2",
|
|
209
|
-
)}
|
|
210
|
-
>
|
|
211
|
-
<nav
|
|
212
|
-
className={cn(
|
|
213
|
-
"grid gap-1",
|
|
214
|
-
collapsed
|
|
215
|
-
? "px-1 py-1 empty:hidden"
|
|
216
|
-
: "border-t border-sidebar-border px-3 py-2 empty:hidden",
|
|
217
|
-
)}
|
|
218
|
-
>
|
|
219
|
-
{BOTTOM_NAV_ITEMS.map((item) => {
|
|
220
|
-
const Icon = item.icon;
|
|
221
|
-
const isActive = location.pathname.startsWith(item.href);
|
|
222
|
-
return (
|
|
223
|
-
<Link
|
|
224
|
-
key={item.href}
|
|
225
|
-
to={item.href}
|
|
226
|
-
aria-label={collapsed ? t(item.labelKey) : undefined}
|
|
227
|
-
className={cn(
|
|
228
|
-
"flex items-center rounded-md text-sm",
|
|
229
|
-
collapsed ? "h-9 justify-center px-0" : "gap-3 px-3 py-2",
|
|
230
|
-
isActive
|
|
231
|
-
? "bg-sidebar-accent text-sidebar-accent-foreground"
|
|
232
|
-
: "text-sidebar-foreground hover:bg-sidebar-accent/65 hover:text-sidebar-accent-foreground",
|
|
233
|
-
)}
|
|
234
|
-
>
|
|
235
|
-
<Icon className="size-4 shrink-0" />
|
|
236
|
-
<span className={collapsed ? "sr-only" : "truncate"}>
|
|
237
|
-
{t(item.labelKey)}
|
|
238
|
-
</span>
|
|
239
|
-
</Link>
|
|
240
|
-
);
|
|
241
|
-
})}
|
|
242
|
-
</nav>
|
|
243
|
-
|
|
244
|
-
<div
|
|
245
|
-
className={cn(
|
|
246
|
-
collapsed
|
|
247
|
-
? "px-1 py-1"
|
|
248
|
-
: "border-t border-sidebar-border px-3 py-2",
|
|
249
|
-
)}
|
|
250
|
-
>
|
|
251
|
-
<OrgSwitcher
|
|
252
|
-
reserveSpace
|
|
253
|
-
// Tasks does not mount /agent, so the default link would 404.
|
|
254
|
-
agentPath={null}
|
|
255
|
-
className={
|
|
256
|
-
collapsed
|
|
257
|
-
? "h-8 justify-center px-0 [&>span]:sr-only [&>svg:last-child]:hidden"
|
|
258
|
-
: undefined
|
|
259
|
-
}
|
|
260
|
-
/>
|
|
261
|
-
</div>
|
|
262
|
-
|
|
263
|
-
<SidebarFooterActions
|
|
264
|
-
collapsed={collapsed}
|
|
265
|
-
feedback={feedbackButton}
|
|
266
|
-
search={searchButton}
|
|
267
|
-
collapse={collapseButton}
|
|
268
|
-
/>
|
|
269
|
-
</div>
|
|
270
|
-
</aside>
|
|
107
|
+
<AppSidebar
|
|
108
|
+
collapsed={collapsed}
|
|
109
|
+
collapsible={collapsible}
|
|
110
|
+
onCollapsedChange={onCollapsedChange}
|
|
111
|
+
brandName={APP_TITLE}
|
|
112
|
+
brandHref="/tasks"
|
|
113
|
+
items={items}
|
|
114
|
+
secondaryItems={secondaryItems}
|
|
115
|
+
feedback={feedbackButton}
|
|
116
|
+
orgSwitcher={orgSwitcher}
|
|
117
|
+
footerExtras={searchButton}
|
|
118
|
+
/>
|
|
271
119
|
);
|
|
272
120
|
}
|
|
@@ -186,8 +186,8 @@ export declare function createAutomationCallbackHandler(runtime: AutomationRunti
|
|
|
186
186
|
duplicate?: undefined;
|
|
187
187
|
eventId?: undefined;
|
|
188
188
|
} | {
|
|
189
|
-
error?: undefined;
|
|
190
189
|
accepted: boolean;
|
|
191
190
|
duplicate: boolean;
|
|
192
191
|
eventId: string;
|
|
192
|
+
error?: undefined;
|
|
193
193
|
}>;
|
|
@@ -5,13 +5,16 @@ export declare function isAgentNativeDesktopUserAgent(userAgent: string | undefi
|
|
|
5
5
|
export declare function resolveEnvironmentChannel(config: AgentNativeConfig, hostname: string | undefined): Extract<AgentNativeDeploymentEnvironment, "local" | "beta" | "production"> | null;
|
|
6
6
|
export declare function isBetaOptOutActive(value: string | number | null | undefined, now?: number): boolean;
|
|
7
7
|
export type EnvironmentBadgePlacement = "fixed" | "inline";
|
|
8
|
+
export interface EnvironmentBadgeProps {
|
|
9
|
+
placement?: EnvironmentBadgePlacement;
|
|
10
|
+
showProduction?: boolean;
|
|
11
|
+
badgeText?: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
8
14
|
/**
|
|
9
15
|
* Environment indicator and first-party hosted lane switcher. Beta is
|
|
10
16
|
* intentionally visible before authentication so a visitor can always leave
|
|
11
17
|
* beta from the sign-in page. Production remains an internal auto-redirect
|
|
12
18
|
* lane for authenticated staff.
|
|
13
19
|
*/
|
|
14
|
-
export declare function EnvironmentBadge({ placement, showProduction, }?:
|
|
15
|
-
placement?: EnvironmentBadgePlacement;
|
|
16
|
-
showProduction?: boolean;
|
|
17
|
-
}): import("react").JSX.Element | null;
|
|
20
|
+
export declare function EnvironmentBadge({ placement, showProduction, badgeText, className, }?: EnvironmentBadgeProps): import("react").JSX.Element | null;
|
|
@@ -117,8 +117,10 @@ const environmentBadgePlacementClasses = {
|
|
|
117
117
|
function EnvironmentLink({ label, href }) {
|
|
118
118
|
return (_jsx(Button, { asChild: true, className: "w-full justify-center", size: "sm", variant: "outline", children: _jsx("a", { href: href, children: label }) }));
|
|
119
119
|
}
|
|
120
|
-
function EnvironmentBadgeContent({ environment, placement, targets, }) {
|
|
120
|
+
function EnvironmentBadgeContent({ environment, placement, targets, badgeText, className, }) {
|
|
121
121
|
const [isHidden, setIsHidden] = useState(false);
|
|
122
|
+
const { session } = useSession();
|
|
123
|
+
const isBuilder = isBuilderIoEmployee(session?.email);
|
|
122
124
|
if (typeof window === "undefined")
|
|
123
125
|
return null;
|
|
124
126
|
if (isHidden)
|
|
@@ -128,18 +130,24 @@ function EnvironmentBadgeContent({ environment, placement, targets, }) {
|
|
|
128
130
|
const productionHref = buildEnvironmentOptOutUrl(currentHref, targets.productionHost);
|
|
129
131
|
if (environment === "beta" ? !productionHref : !betaHref)
|
|
130
132
|
return null;
|
|
131
|
-
const label =
|
|
133
|
+
const label = badgeText ?? "alpha";
|
|
132
134
|
const title = environment === "beta"
|
|
133
|
-
?
|
|
135
|
+
? `You're on Agent-Native ${label.charAt(0).toUpperCase() + label.slice(1)}`
|
|
134
136
|
: "You're on Agent-Native Production";
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
137
|
+
const badgeClasses = cn(environmentBadgePlacementClasses[placement], environment === "beta"
|
|
138
|
+
? "border-primary/80"
|
|
139
|
+
: "border-border/80 bg-background/95 text-foreground", className);
|
|
140
|
+
if (!isBuilder) {
|
|
141
|
+
return (_jsx("div", { "aria-label": title, className: cn(badgeClasses, "inline-flex items-center justify-center select-none", environment === "beta"
|
|
142
|
+
? "border-primary/80 bg-primary text-primary-foreground"
|
|
143
|
+
: "border-border/80 bg-background/95 text-foreground"), role: "status", children: label }));
|
|
144
|
+
}
|
|
145
|
+
return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { "aria-label": `Open ${title.toLowerCase()} switcher`, className: badgeClasses, size: "sm", variant: environment === "beta" ? "default" : "outline", children: label }) }), _jsxs(PopoverContent, { align: "start", className: "w-[280px] p-5", side: placement === "inline" ? "bottom" : "top", sideOffset: 8, children: [_jsx("div", { className: "mb-1 text-sm font-semibold leading-5", children: title }), _jsx("div", { className: "mb-4 text-sm text-muted-foreground", children: "Choose where you want to continue." }), _jsxs("div", { className: "grid gap-2", children: [environment === "beta" ? (_jsx(EnvironmentLink, { href: productionHref, label: "Switch to production" })) : (_jsx(EnvironmentLink, { href: betaHref, label: "Go to beta" })), _jsx(Button, { className: "mt-2 -mb-2 w-full justify-center text-muted-foreground", onClick: () => setIsHidden(true), size: "sm", type: "button", variant: "ghost", children: "Hide badge" })] })] })] }));
|
|
138
146
|
}
|
|
139
|
-
function LocalEnvironmentBadge({ placement, }) {
|
|
140
|
-
return (_jsx("div", { "aria-label": "Local development environment", className: cn(environmentBadgePlacementClasses[placement], "inline-flex items-center justify-center border border-border/80 bg-background/95 text-foreground"), role: "status", children:
|
|
147
|
+
function LocalEnvironmentBadge({ placement, badgeText = "alpha", className, }) {
|
|
148
|
+
return (_jsx("div", { "aria-label": "Local development environment", className: cn(environmentBadgePlacementClasses[placement], "inline-flex items-center justify-center border border-border/80 bg-background/95 text-foreground select-none", className), role: "status", children: badgeText }));
|
|
141
149
|
}
|
|
142
|
-
function ProductionEnvironmentBadge({ placement, targets, }) {
|
|
150
|
+
function ProductionEnvironmentBadge({ placement, targets, badgeText, className, }) {
|
|
143
151
|
const { session, status } = useSession();
|
|
144
152
|
const isEligible = typeof window !== "undefined" &&
|
|
145
153
|
window.parent === window &&
|
|
@@ -174,9 +182,7 @@ function ProductionEnvironmentBadge({ placement, targets, }) {
|
|
|
174
182
|
});
|
|
175
183
|
window.location.replace(betaHref);
|
|
176
184
|
}, [isEligible, session?.email, status, targets.betaHost]);
|
|
177
|
-
|
|
178
|
-
return null;
|
|
179
|
-
return (_jsx(EnvironmentBadgeContent, { environment: "production", placement: placement, targets: targets }));
|
|
185
|
+
return (_jsx(EnvironmentBadgeContent, { environment: "production", placement: placement, targets: targets, badgeText: badgeText, className: className }));
|
|
180
186
|
}
|
|
181
187
|
/**
|
|
182
188
|
* Environment indicator and first-party hosted lane switcher. Beta is
|
|
@@ -184,12 +190,13 @@ function ProductionEnvironmentBadge({ placement, targets, }) {
|
|
|
184
190
|
* beta from the sign-in page. Production remains an internal auto-redirect
|
|
185
191
|
* lane for authenticated staff.
|
|
186
192
|
*/
|
|
187
|
-
export function EnvironmentBadge({ placement = "fixed", showProduction = true, } = {}) {
|
|
193
|
+
export function EnvironmentBadge({ placement = "fixed", showProduction = true, badgeText, className, } = {}) {
|
|
188
194
|
const [hydrated, setHydrated] = useState(false);
|
|
189
195
|
const config = useMemo(injectedAgentNativeConfig, []);
|
|
190
196
|
const hostname = typeof window === "undefined" ? undefined : window.location.hostname;
|
|
191
197
|
const environment = resolveEnvironmentChannel(config, hostname);
|
|
192
198
|
const targets = resolveEnvironmentTargets(hostname);
|
|
199
|
+
const resolvedBadgeText = badgeText ?? config.deployment?.badgeText ?? config.badgeText ?? "alpha";
|
|
193
200
|
useEffect(() => {
|
|
194
201
|
setHydrated(true);
|
|
195
202
|
}, []);
|
|
@@ -200,14 +207,15 @@ export function EnvironmentBadge({ placement = "fixed", showProduction = true, }
|
|
|
200
207
|
return null;
|
|
201
208
|
}
|
|
202
209
|
if (environment === "local") {
|
|
203
|
-
return _jsx(LocalEnvironmentBadge, { placement: placement });
|
|
210
|
+
return (_jsx(LocalEnvironmentBadge, { placement: placement, badgeText: resolvedBadgeText, className: className }));
|
|
211
|
+
}
|
|
212
|
+
if (!targets) {
|
|
213
|
+
return (_jsx("div", { "aria-label": "Development environment", className: cn(environmentBadgePlacementClasses[placement], "inline-flex items-center justify-center border border-border/80 bg-background/95 text-foreground select-none", className), role: "status", children: resolvedBadgeText }));
|
|
204
214
|
}
|
|
205
|
-
if (!targets)
|
|
206
|
-
return null;
|
|
207
215
|
if (environment === "beta") {
|
|
208
|
-
return (_jsx(EnvironmentBadgeContent, { environment: "beta", placement: placement, targets: targets }));
|
|
216
|
+
return (_jsx(EnvironmentBadgeContent, { environment: "beta", placement: placement, targets: targets, badgeText: resolvedBadgeText, className: className }));
|
|
209
217
|
}
|
|
210
218
|
if (!showProduction)
|
|
211
219
|
return null;
|
|
212
|
-
return _jsx(ProductionEnvironmentBadge, { placement: placement, targets: targets });
|
|
220
|
+
return (_jsx(ProductionEnvironmentBadge, { placement: placement, targets: targets, badgeText: resolvedBadgeText, className: className }));
|
|
213
221
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
3
3
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
4
|
-
import {
|
|
4
|
+
import { IconCheck, IconMessageCircle } from "@tabler/icons-react";
|
|
5
5
|
import { useState, useEffect, useRef, useCallback, } from "react";
|
|
6
6
|
import { DEFAULT_LOCALE } from "../localization/shared.js";
|
|
7
7
|
import { getFeedbackClientContext } from "./feedback-context.js";
|
|
@@ -15,7 +15,7 @@ function isSyntheticAgentNativeAnonymousEmail(value) {
|
|
|
15
15
|
}
|
|
16
16
|
const FEEDBACK_COPY = {
|
|
17
17
|
"en-US": {
|
|
18
|
-
label: "
|
|
18
|
+
label: "Send feedback",
|
|
19
19
|
placeholder: "What's working, what's broken, or what would you change?",
|
|
20
20
|
submit: "Send feedback",
|
|
21
21
|
submitting: "Sending...",
|
|
@@ -261,9 +261,19 @@ function clientHostname() {
|
|
|
261
261
|
return location?.hostname;
|
|
262
262
|
}
|
|
263
263
|
function isFirstPartyHostname(hostname) {
|
|
264
|
-
const normalized = hostname?.trim().toLowerCase();
|
|
264
|
+
const normalized = hostname?.trim().toLowerCase().split(":")[0];
|
|
265
265
|
return (normalized === FIRST_PARTY_HOSTNAME ||
|
|
266
|
-
normalized?.endsWith(`.${FIRST_PARTY_HOSTNAME}`) === true
|
|
266
|
+
normalized?.endsWith(`.${FIRST_PARTY_HOSTNAME}`) === true ||
|
|
267
|
+
normalized?.endsWith(".netlify.app") === true ||
|
|
268
|
+
normalized?.endsWith(".builder.io") === true);
|
|
269
|
+
}
|
|
270
|
+
function isLocalDevHostname(hostname) {
|
|
271
|
+
const normalized = hostname?.trim().toLowerCase().split(":")[0];
|
|
272
|
+
return (normalized === "localhost" ||
|
|
273
|
+
normalized === "127.0.0.1" ||
|
|
274
|
+
normalized === "[::1]" ||
|
|
275
|
+
normalized === "0.0.0.0" ||
|
|
276
|
+
normalized?.endsWith(".local") === true);
|
|
267
277
|
}
|
|
268
278
|
function isLegacyFeedbackPageUrl(value, hostname) {
|
|
269
279
|
const hasScheme = /^[a-z][a-z\d+.-]*:/i.test(value);
|
|
@@ -284,7 +294,11 @@ export function resolveFeedbackUrl(url, hostname = clientHostname()) {
|
|
|
284
294
|
}
|
|
285
295
|
if (url !== undefined)
|
|
286
296
|
return null;
|
|
287
|
-
|
|
297
|
+
// Local template/dev hosts are first-party too — otherwise the sidebar
|
|
298
|
+
// feedback row vanishes on 127.0.0.1 even though every app wires it.
|
|
299
|
+
return isFirstPartyHostname(hostname) || isLocalDevHostname(hostname)
|
|
300
|
+
? FIRST_PARTY_FEEDBACK_URL
|
|
301
|
+
: null;
|
|
288
302
|
}
|
|
289
303
|
export function FeedbackButton(props) {
|
|
290
304
|
const [mounted, setMounted] = useState(false);
|
|
@@ -392,13 +406,14 @@ function FeedbackPopoverButton({ variant = "sidebar", label, url, className, sid
|
|
|
392
406
|
trigger = (_jsx(PopoverPrimitive.Trigger, { asChild: true, children: customTrigger }));
|
|
393
407
|
}
|
|
394
408
|
else if (variant === "icon") {
|
|
395
|
-
trigger = (_jsx(TooltipPrimitive.Provider, { delayDuration: 200, children: _jsxs(TooltipPrimitive.Root, { children: [_jsx(TooltipPrimitive.Trigger, { asChild: true, children: _jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": resolvedLabel, className: cn("flex
|
|
409
|
+
trigger = (_jsx(TooltipPrimitive.Provider, { delayDuration: 200, children: _jsxs(TooltipPrimitive.Root, { children: [_jsx(TooltipPrimitive.Trigger, { asChild: true, children: _jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": resolvedLabel, className: cn("flex size-9 items-center justify-center rounded-md bg-transparent text-primary hover:bg-accent/60 hover:text-primary", className), children: _jsx(IconMessageCircle, { className: "size-4 shrink-0 text-primary" }) }) }) }), _jsx(TooltipPrimitive.Portal, { children: _jsx(TooltipPrimitive.Content, { sideOffset: 6, className: "z-[100040] overflow-hidden rounded-md border border-border bg-popover px-2 py-1 text-[11px] text-foreground shadow-md animate-in fade-in-0 zoom-in-95 origin-[var(--radix-tooltip-content-transform-origin)]", children: resolvedLabel }) })] }) }));
|
|
396
410
|
}
|
|
397
411
|
else if (variant === "outlined") {
|
|
398
|
-
trigger = (_jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsxs("button", { type: "button", "aria-label": resolvedLabel, className: cn("flex h-8 items-center gap-2 rounded-md border border-border bg-transparent px-3 text-sm text-muted-foreground transition hover:border-foreground/40 hover:text-foreground", className), children: [_jsx(
|
|
412
|
+
trigger = (_jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsxs("button", { type: "button", "aria-label": resolvedLabel, className: cn("flex h-8 items-center gap-2 rounded-md border border-border bg-transparent px-3 text-sm text-muted-foreground transition hover:border-foreground/40 hover:text-foreground", className), children: [_jsx(IconMessageCircle, { size: 14, stroke: 1.5 }), _jsx("span", { children: resolvedLabel })] }) }));
|
|
399
413
|
}
|
|
400
414
|
else {
|
|
401
|
-
|
|
415
|
+
// Sidebar variant matches Clips footer feedback row spacing/density.
|
|
416
|
+
trigger = (_jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsxs("button", { type: "button", className: cn("flex h-auto w-full items-center justify-start gap-2 rounded bg-transparent px-2 py-1.5 text-xs font-normal text-primary hover:bg-accent/60 hover:text-primary", className), children: [_jsx(IconMessageCircle, { className: "size-4 shrink-0 text-primary" }), _jsx("span", { children: resolvedLabel })] }) }));
|
|
402
417
|
}
|
|
403
418
|
const resolvedSide = side ?? (variant === "sidebar" ? "top" : "bottom");
|
|
404
419
|
const resolvedPlaceholder = placeholder ?? copy.placeholder;
|
|
@@ -169,7 +169,7 @@ function ProvidersInner({ queryClient, defaultTheme = "system", themeAttribute =
|
|
|
169
169
|
const localizedChildren = i18n === false ? (children) : (_jsx(AgentNativeI18nProvider, { ...(i18n ?? {}), children: children }));
|
|
170
170
|
return (_jsx(QueryClientProvider, { client: queryClient, children: _jsxs(ThemeProvider, { attribute: themeAttribute, defaultTheme: defaultTheme, enableSystem: true, disableTransitionOnChange: disableThemeTransitions, children: [_jsx(EmbeddedThemeSync, {}), _jsxs(TooltipProvider, { delayDuration: tooltipDelayDuration, children: [!disableWebMcp && _jsx(AgentNativeWebMcpActionRegistration, {}), localizedChildren, _jsx(DocumentTitleGuard, { fallbackTitle: documentTitleFallback }), _jsx(RuntimeConfigNotice, {}), _jsx(RoutedAppEnhancements, {}), showEnvironmentBadge ? (_jsx(EnvironmentBadge, { showProduction: showProductionEnvironmentBadge })) : null, toaster] })] }) }));
|
|
171
171
|
}
|
|
172
|
-
export function AppProviders({ queryClient, isPublicPath = false, clientOnlyFallback, sessionBypass = false, disableWebMcp = false, showEnvironmentBadge =
|
|
172
|
+
export function AppProviders({ queryClient, isPublicPath = false, clientOnlyFallback, sessionBypass = false, disableWebMcp = false, showEnvironmentBadge = false, defaultTheme, themeAttribute, tooltipDelayDuration, toaster, disableThemeTransitions, i18n, documentTitleFallback, children, }) {
|
|
173
173
|
const fallback = clientOnlyFallback ?? _jsx(DefaultSpinner, {});
|
|
174
174
|
if (isPublicPath) {
|
|
175
175
|
return (_jsx(ProvidersInner, { queryClient: queryClient, defaultTheme: defaultTheme, themeAttribute: themeAttribute, tooltipDelayDuration: tooltipDelayDuration, toaster: toaster, disableThemeTransitions: disableThemeTransitions, disableWebMcp: disableWebMcp, i18n: i18n, documentTitleFallback: documentTitleFallback, showProductionEnvironmentBadge: false, showEnvironmentBadge: showEnvironmentBadge, children: children }));
|
|
@@ -474,9 +474,6 @@ export function AuthPage(props) {
|
|
|
474
474
|
}, []);
|
|
475
475
|
const [googleBusy, setGoogleBusy] = React.useState(false);
|
|
476
476
|
const [magicLinkBusy, setMagicLinkBusy] = React.useState(false);
|
|
477
|
-
const [environmentVisible, setEnvironmentVisible] = React.useState(false);
|
|
478
|
-
const [environmentOpen, setEnvironmentOpen] = React.useState(false);
|
|
479
|
-
const [environmentProductionUrl, setEnvironmentProductionUrl] = React.useState("");
|
|
480
477
|
const [copiedLocalMode, setCopiedLocalMode] = React.useState(false);
|
|
481
478
|
const signupViewTrackedRef = React.useRef(false);
|
|
482
479
|
const pendingSignupPassword = React.useRef("");
|
|
@@ -888,30 +885,6 @@ export function AuthPage(props) {
|
|
|
888
885
|
// coercion-ok: beta controls are optional.
|
|
889
886
|
}
|
|
890
887
|
}, [localDevAllowed, props]);
|
|
891
|
-
React.useEffect(() => {
|
|
892
|
-
if (window.parent !== window)
|
|
893
|
-
return;
|
|
894
|
-
const hostname = window.location.hostname.toLowerCase().replace(/\.$/, "");
|
|
895
|
-
const productionHost = hostname.startsWith("beta.")
|
|
896
|
-
? hostname.slice("beta.".length)
|
|
897
|
-
: "";
|
|
898
|
-
if (!productionHost ||
|
|
899
|
-
props.environmentBetaHosts[productionHost] !== hostname) {
|
|
900
|
-
return;
|
|
901
|
-
}
|
|
902
|
-
try {
|
|
903
|
-
const productionUrl = new URL(window.location.href);
|
|
904
|
-
productionUrl.protocol = "https:";
|
|
905
|
-
productionUrl.hostname = productionHost;
|
|
906
|
-
productionUrl.port = "";
|
|
907
|
-
productionUrl.searchParams.set(props.betaOptOutQueryParam, String(Date.now() + props.betaOptOutDurationMs));
|
|
908
|
-
setEnvironmentProductionUrl(productionUrl.toString());
|
|
909
|
-
setEnvironmentVisible(true);
|
|
910
|
-
}
|
|
911
|
-
catch {
|
|
912
|
-
// coercion-ok: malformed host metadata cannot produce a useful switcher.
|
|
913
|
-
}
|
|
914
|
-
}, [props]);
|
|
915
888
|
const stopOAuthPolling = React.useCallback(() => {
|
|
916
889
|
if (oauthPollTimer.current !== null) {
|
|
917
890
|
window.clearInterval(oauthPollTimer.current);
|
|
@@ -1971,16 +1944,6 @@ export function AuthPage(props) {
|
|
|
1971
1944
|
localeOptions.map((option) => (React.createElement("button", { type: "button", className: "locale-menu-item", role: "menuitemradio", "aria-checked": localePreference === option.value, "data-locale-value": option.value, key: option.value, onClick: () => selectLocale(option.value) },
|
|
1972
1945
|
React.createElement("span", { className: "locale-menu-check", "aria-hidden": "true" }, "\u2713"),
|
|
1973
1946
|
React.createElement("span", null, option.label)))))));
|
|
1974
|
-
const environmentBadge = (React.createElement("div", { className: "environment-switcher", id: "environment-switcher", hidden: !environmentVisible },
|
|
1975
|
-
React.createElement("button", { type: "button", className: "environment-badge", id: "environment-badge", "aria-expanded": environmentOpen, "aria-controls": "environment-popover", onClick: () => setEnvironmentOpen((open) => !open) }, "beta"),
|
|
1976
|
-
React.createElement("div", { className: "environment-popover", id: "environment-popover", role: "dialog", "aria-labelledby": "environment-popover-title", hidden: !environmentOpen },
|
|
1977
|
-
React.createElement("div", { className: "environment-popover-title", id: "environment-popover-title" }, "You're on Agent-Native Beta"),
|
|
1978
|
-
React.createElement("div", { className: "environment-popover-copy" }, "Choose where you want to continue."),
|
|
1979
|
-
React.createElement("a", { className: "environment-production-link", id: "environment-production-link", href: environmentProductionUrl }, "Switch to production"),
|
|
1980
|
-
React.createElement("button", { type: "button", className: "environment-hide-badge", id: "environment-hide-badge", onClick: () => {
|
|
1981
|
-
setEnvironmentOpen(false);
|
|
1982
|
-
setEnvironmentVisible(false);
|
|
1983
|
-
} }, "Hide badge"))));
|
|
1984
1947
|
const marketingSurface = marketingCopy ? (React.createElement(MarketingHome, { appName: marketingCopy.appName, variant: "auth", background: marketingCopy.screenshotSrc ? null : (React.createElement(OceanBackground, { className: "auth-marketing-background" })), topRight: marketingCopy.learnMoreUrl ? (React.createElement("a", { className: "auth-marketing-learn-more", "data-auth-marketing-learn-more": "true", href: marketingCopy.learnMoreUrl, target: "_blank", rel: "noreferrer" },
|
|
1985
1948
|
React.createElement("span", null, t("newToApp").replace("{appName}", marketingCopy.appName.replace(/^Agent-Native\s+/i, ""))),
|
|
1986
1949
|
React.createElement("span", { "aria-hidden": "true" }, " - "),
|
|
@@ -2006,6 +1969,5 @@ export function AuthPage(props) {
|
|
|
2006
1969
|
React.createElement("span", { "data-i18n": "openSource" }, t("openSource")))))))) : (React.createElement("div", { className: "auth-centered" }, authCard));
|
|
2007
1970
|
return (React.createElement(React.Fragment, null,
|
|
2008
1971
|
localePicker,
|
|
2009
|
-
environmentBadge,
|
|
2010
1972
|
initialPrompt ? (React.createElement("div", { className: "auth-centered" }, authCard)) : (marketingSurface)));
|
|
2011
1973
|
}
|
|
@@ -6,5 +6,5 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
6
6
|
* surrounding text color.
|
|
7
7
|
*/
|
|
8
8
|
export function AgentNativeIcon({ size = 24, className, ...rest }) {
|
|
9
|
-
return (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 114 66", fill: "none", className: className, ...rest, children: [_jsx("path", { d: "M24.5537 65.7695H0L15.0859 39.4619L37.708 0L60.4912 39.4619H39.6396L24.5537 65.7695Z", fill: "currentColor" }), _jsx("path", { d: "M89.446 0H114L76.2921 65.7704H51.7383L89.446 0Z", fill: "currentColor" })] }));
|
|
9
|
+
return (_jsxs("svg", { "data-agent-native-icon": true, xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 114 66", fill: "none", className: className, ...rest, children: [_jsx("path", { d: "M24.5537 65.7695H0L15.0859 39.4619L37.708 0L60.4912 39.4619H39.6396L24.5537 65.7695Z", fill: "currentColor" }), _jsx("path", { d: "M89.446 0H114L76.2921 65.7704H51.7383L89.446 0Z", fill: "currentColor" })] }));
|
|
10
10
|
}
|
package/dist/client/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export * from "./ui/index.js";
|
|
|
13
13
|
export { cn } from "@agent-native/toolkit/utils";
|
|
14
14
|
export { AgentNativeI18nProvider, LanguagePicker, getLocaleInitScript, isLocaleCode, isValidLocaleCode, localeDirection, localeMetadataFor, normalizeLocaleCode, normalizeLocalePreference, normalizeLocalizationPreference, resolveLocaleFromCandidates, resolveLocaleFromPreference, useFormatters, useLocale, useT, DEFAULT_LOCALE, LOCALE_HYDRATION_GLOBAL, LOCALE_METADATA, LOCALE_STORAGE_KEY, SUPPORTED_LOCALES, type AgentNativeI18nCatalog, type AgentNativeI18nProviderProps, type BuiltinLocaleCode, type LocaleCode, type LocaleHydrationPayload, type LocaleMessages, type LocaleMetadata, type LocalePreference, type LocalizationPreference, } from "./i18n.js";
|
|
15
15
|
export { AgentNativeIcon } from "./components/icons/AgentNativeIcon.js";
|
|
16
|
+
export { AppSidebar, AppSidebarHeader, AppSidebarNavItem, AppSidebarNavGroup, AppSidebarSection, AppSidebarFeedbackButton, AppSidebarFooter, useAppSidebar, type AppSidebarProps, type AppSidebarHeaderProps, type AppSidebarNavItemProps, type AppSidebarNavGroupProps, type AppSidebarSectionProps, type AppSidebarFeedbackButtonProps, type AppSidebarFooterProps, type AppSidebarItemDefinition, type AppSidebarContextValue, } from "./ui/AppSidebar.js";
|
|
16
17
|
export { FeatureFlagsEditor, evaluatedFeatureFlagValues, featureFlagValue, useFeatureFlag, useFeatureFlags, type FeatureFlagActor, type FeatureFlagMetadata, type FeatureFlagRules, type SetFeatureFlagInput, } from "./feature-flags/index.js";
|
|
17
18
|
export { ExperimentsSettings, useExperiment, useExperimentState, useExperiments, type ExperimentValues, type ExperimentsSettingsProps, } from "./experiments/index.js";
|
|
18
19
|
export { withBuilderUtmTrackingParams } from "../shared/builder-link-tracking.js";
|