@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.
Files changed (48) hide show
  1. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +108 -121
  2. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +87 -220
  3. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +83 -221
  4. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +324 -460
  5. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +57 -247
  6. package/corpus/templates/clips/app/components/library/library-layout.tsx +15 -48
  7. package/corpus/templates/clips/changelog/2026-09-10-open-mcp-connections-in-new-tabs.md +1 -0
  8. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +84 -94
  9. package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +1 -1
  10. package/corpus/templates/crm/app/components/layout/CrmSidebar.tsx +108 -296
  11. package/corpus/templates/design/app/components/layout/Sidebar.tsx +55 -212
  12. package/corpus/templates/factory/app/components/layout/Sidebar.tsx +72 -260
  13. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +143 -362
  14. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +64 -159
  15. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +152 -165
  16. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +82 -207
  17. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +61 -234
  18. package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +73 -225
  19. package/dist/automation/index.d.ts +1 -1
  20. package/dist/client/EnvironmentBadge.d.ts +7 -4
  21. package/dist/client/EnvironmentBadge.js +26 -18
  22. package/dist/client/FeedbackButton.js +23 -8
  23. package/dist/client/app-providers.js +1 -1
  24. package/dist/client/auth/AuthPage.js +0 -38
  25. package/dist/client/components/icons/AgentNativeIcon.js +1 -1
  26. package/dist/client/index.d.ts +1 -0
  27. package/dist/client/index.js +1 -0
  28. package/dist/client/ui/AppSidebar.d.ts +15 -0
  29. package/dist/client/ui/AppSidebar.js +34 -0
  30. package/dist/client/ui/index.d.ts +1 -0
  31. package/dist/client/ui/index.js +1 -0
  32. package/dist/collab/awareness.d.ts +2 -2
  33. package/dist/collab/struct-routes.d.ts +1 -1
  34. package/dist/config.d.ts +4 -0
  35. package/dist/config.js +19 -3
  36. package/dist/progress/routes.d.ts +1 -1
  37. package/dist/provider-api/actions/custom-provider-registration.d.ts +9 -9
  38. package/dist/provider-api/actions/provider-api.d.ts +15 -15
  39. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  40. package/dist/resources/handlers.d.ts +1 -1
  41. package/dist/secrets/routes.d.ts +9 -9
  42. package/dist/server/beta-opt-out-html.js +2 -2
  43. package/dist/templates/chat/app/components/layout/Sidebar.tsx +57 -247
  44. package/dist/vite/client.js +4 -1
  45. package/docs/content/template-clips-anonymous-intake.mdx +7 -5
  46. package/docs/content/template-clips-developers.mdx +1 -1
  47. package/package.json +3 -3
  48. package/src/templates/chat/app/components/layout/Sidebar.tsx +57 -247
@@ -1,10 +1,14 @@
1
1
  import { DevDatabaseLink } from "@agent-native/core/client/db-admin";
2
2
  import { useActionQuery } from "@agent-native/core/client/hooks";
3
3
  import { useT } from "@agent-native/core/client/i18n";
4
- import { openCommandMenu } from "@agent-native/core/client/navigation";
5
4
  import { OrgSwitcher } from "@agent-native/core/client/org";
6
- import { FeedbackButton } from "@agent-native/core/client/ui";
7
- import { SidebarFooterActions } from "@agent-native/toolkit/app-shell";
5
+ import {
6
+ AppSidebar,
7
+ AppSidebarNavItem,
8
+ AppSidebarSection,
9
+ FeedbackButton,
10
+ type AppSidebarItemDefinition,
11
+ } from "@agent-native/core/client/ui";
8
12
  import {
9
13
  IconAlertTriangle,
10
14
  IconBuilding,
@@ -12,28 +16,19 @@ import {
12
16
  IconChecklist,
13
17
  IconLayoutBoard,
14
18
  IconLayoutDashboard,
15
- IconLayoutSidebarLeftCollapse,
16
- IconLayoutSidebarLeftExpand,
17
19
  IconList,
18
20
  IconMessageCircle,
19
21
  IconPencilCheck,
20
22
  IconRoute,
21
- IconSearch,
22
23
  IconSettings,
23
24
  IconStar,
24
25
  IconTable,
25
26
  IconUsers,
26
27
  } from "@tabler/icons-react";
27
28
  import { useEffect, useState } from "react";
28
- import { Link, NavLink, useLocation } from "react-router";
29
+ import { useLocation } from "react-router";
29
30
 
30
31
  import { Button } from "@/components/ui/button";
31
- import {
32
- Tooltip,
33
- TooltipContent,
34
- TooltipProvider,
35
- TooltipTrigger,
36
- } from "@/components/ui/tooltip";
37
32
  import { cn } from "@/lib/utils";
38
33
 
39
34
  import {
@@ -78,78 +73,6 @@ const footerNav = [
78
73
  },
79
74
  ];
80
75
 
81
- function itemClasses(isActive: boolean, collapsed: boolean) {
82
- return cn(
83
- "flex items-center rounded-md text-sm",
84
- collapsed ? "h-9 w-9 justify-center" : "h-8 gap-2 px-2",
85
- isActive
86
- ? "bg-sidebar-accent font-medium text-sidebar-accent-foreground"
87
- : "text-sidebar-foreground/80 hover:bg-sidebar-accent/50 hover:text-sidebar-accent-foreground",
88
- );
89
- }
90
-
91
- function CollapsibleTooltip({
92
- collapsed,
93
- label,
94
- children,
95
- }: {
96
- collapsed: boolean;
97
- label: string;
98
- children: React.ReactNode;
99
- }) {
100
- if (!collapsed) return <>{children}</>;
101
- return (
102
- <Tooltip delayDuration={0}>
103
- <TooltipTrigger asChild>{children}</TooltipTrigger>
104
- <TooltipContent side="right">{label}</TooltipContent>
105
- </Tooltip>
106
- );
107
- }
108
-
109
- function SidebarSection({
110
- heading,
111
- children,
112
- }: {
113
- heading: string;
114
- children: React.ReactNode;
115
- }) {
116
- return (
117
- <div className="mt-4 grid gap-0.5">
118
- <p className="px-2 pb-1 text-[11px] font-medium uppercase tracking-wide text-sidebar-foreground/50">
119
- {heading}
120
- </p>
121
- {children}
122
- </div>
123
- );
124
- }
125
-
126
- function ListRow({
127
- to,
128
- label,
129
- icon: Icon,
130
- collapsed,
131
- onNavigate,
132
- }: {
133
- to: string;
134
- label: string;
135
- icon: typeof IconList;
136
- collapsed: boolean;
137
- onNavigate?: () => void;
138
- }) {
139
- return (
140
- <CollapsibleTooltip collapsed={collapsed} label={label}>
141
- <NavLink
142
- to={to}
143
- onClick={onNavigate}
144
- className={({ isActive }) => itemClasses(isActive, collapsed)}
145
- >
146
- <Icon className="size-4 shrink-0" />
147
- {!collapsed && <span className="truncate">{label}</span>}
148
- </NavLink>
149
- </CollapsibleTooltip>
150
- );
151
- }
152
-
153
76
  export function CrmSidebar({ onNavigate }: { onNavigate?: () => void }) {
154
77
  const t = useT();
155
78
  const location = useLocation();
@@ -176,226 +99,115 @@ export function CrmSidebar({ onNavigate }: { onNavigate?: () => void }) {
176
99
  const views: CrmSidebarSavedView[] = normalizeCrmSavedViews(viewsQuery.data);
177
100
  const favorites = views.filter((view) => view.pinned);
178
101
  const unpinnedViews = views.filter((view) => !view.pinned);
179
- // An action that has not shipped yet and one that failed are the same 404 to
180
- // the browser, so surface the failure instead of rendering an empty section.
181
102
  const loadFailed = listsQuery.isError || viewsQuery.isError;
182
103
  const settled = !listsQuery.isPending && !viewsQuery.isPending;
183
104
 
184
- const collapseButton = (
185
- <Tooltip delayDuration={0}>
186
- <TooltipTrigger asChild>
187
- <button
188
- type="button"
189
- onClick={() => setCollapsed((value) => !value)}
190
- className="flex size-8 cursor-pointer items-center justify-center rounded-md text-muted-foreground hover:bg-sidebar-accent/50 hover:text-foreground"
191
- aria-label={
192
- collapsed
193
- ? t("navigation.expandSidebar")
194
- : t("navigation.collapseSidebar")
195
- }
196
- >
197
- {collapsed ? (
198
- <IconLayoutSidebarLeftExpand className="size-4 rtl:-scale-x-100" />
199
- ) : (
200
- <IconLayoutSidebarLeftCollapse className="size-4 rtl:-scale-x-100" />
201
- )}
202
- </button>
203
- </TooltipTrigger>
204
- <TooltipContent side="right">
205
- {collapsed
206
- ? t("navigation.expandSidebar")
207
- : t("navigation.collapseSidebar")}
208
- </TooltipContent>
209
- </Tooltip>
105
+ const items: AppSidebarItemDefinition[] = primaryNav.map((item) => ({
106
+ to: item.to,
107
+ label: t(item.labelKey),
108
+ icon: item.icon,
109
+ active: item.end
110
+ ? location.pathname === "/home"
111
+ : location.pathname.startsWith(item.to),
112
+ onClick: onNavigate,
113
+ }));
114
+
115
+ const secondaryItems: AppSidebarItemDefinition[] = footerNav.map((item) => ({
116
+ to: item.to,
117
+ label: t(item.labelKey),
118
+ icon: item.icon,
119
+ active: location.pathname.startsWith(item.to),
120
+ onClick: onNavigate,
121
+ }));
122
+
123
+ const feedbackButton = (
124
+ <FeedbackButton variant={collapsed ? "icon" : "sidebar"} side="right" />
210
125
  );
211
126
 
212
- const searchButton = (
213
- <Tooltip delayDuration={0}>
214
- <TooltipTrigger asChild>
215
- <button
216
- type="button"
217
- onClick={openCommandMenu}
218
- className="flex size-8 cursor-pointer items-center justify-center rounded-md text-muted-foreground hover:bg-sidebar-accent/50 hover:text-foreground"
219
- aria-label={t("navigation.search")}
220
- >
221
- <IconSearch className="size-4" />
222
- </button>
223
- </TooltipTrigger>
224
- <TooltipContent side="right">{t("navigation.search")}</TooltipContent>
225
- </Tooltip>
226
- );
127
+ const orgSwitcher = <OrgSwitcher compact={collapsed} reserveSpace />;
227
128
 
228
129
  return (
229
- <TooltipProvider>
230
- <nav
231
- className={cn(
232
- "flex h-full shrink-0 flex-col overflow-hidden border-r border-sidebar-border bg-sidebar py-3 text-sidebar-foreground transition-[width] duration-200 ease-out",
233
- collapsed ? "w-14 px-1.5" : "w-60 px-2",
234
- )}
235
- >
236
- <div
237
- className={cn(
238
- "flex h-8 items-center text-sm font-semibold tracking-tight text-sidebar-primary",
239
- collapsed ? "justify-center" : "px-2",
240
- )}
241
- >
242
- {collapsed ? <IconLayoutBoard className="size-4" /> : "CRM"}
243
- </div>
244
-
245
- <div className="mt-4 min-h-0 flex-1 overflow-y-auto">
246
- <div className="grid gap-0.5">
247
- {primaryNav.map((item) => {
248
- const Icon = item.icon;
249
- const label = t(item.labelKey);
250
- const isActive = item.end
251
- ? location.pathname === "/home"
252
- : location.pathname.startsWith(item.to);
253
- return (
254
- <CollapsibleTooltip
255
- key={item.to}
256
- collapsed={collapsed}
257
- label={label}
258
- >
259
- <Link
260
- to={item.to}
261
- onClick={onNavigate}
262
- aria-current={isActive ? "page" : undefined}
263
- className={itemClasses(isActive, collapsed)}
264
- >
265
- <Icon className="size-4 shrink-0" />
266
- {!collapsed && <span className="truncate">{label}</span>}
267
- </Link>
268
- </CollapsibleTooltip>
269
- );
270
- })}
271
- </div>
272
-
273
- {favorites.length > 0 && (
274
- <SidebarSection
275
- heading={collapsed ? "" : t("navigation.favorites")}
276
- >
277
- {favorites.map((view) => (
278
- <ListRow
279
- key={`favorite-${view.id}`}
280
- to={savedViewHref(view)}
281
- label={view.name}
282
- icon={IconStar}
283
- collapsed={collapsed}
284
- onNavigate={onNavigate}
285
- />
286
- ))}
287
- </SidebarSection>
288
- )}
289
-
290
- <SidebarSection
291
- heading={collapsed ? "" : t("navigation.listsAndViews")}
130
+ <AppSidebar
131
+ collapsed={collapsed}
132
+ onCollapsedChange={setCollapsed}
133
+ brandName="CRM"
134
+ brandHref="/home"
135
+ items={items}
136
+ secondaryItems={secondaryItems}
137
+ feedback={feedbackButton}
138
+ orgSwitcher={orgSwitcher}
139
+ footerExtras={<DevDatabaseLink />}
140
+ >
141
+ {favorites.length > 0 && (
142
+ <AppSidebarSection title={t("navigation.favorites")}>
143
+ {favorites.map((view) => (
144
+ <AppSidebarNavItem
145
+ key={`favorite-${view.id}`}
146
+ to={savedViewHref(view)}
147
+ label={view.name}
148
+ icon={IconStar}
149
+ onClick={onNavigate}
150
+ />
151
+ ))}
152
+ </AppSidebarSection>
153
+ )}
154
+
155
+ <AppSidebarSection title={t("navigation.listsAndViews")}>
156
+ {lists.map((list) => (
157
+ <AppSidebarNavItem
158
+ key={`list-${list.id}`}
159
+ to={`/lists/${encodeURIComponent(list.id)}`}
160
+ label={list.name}
161
+ icon={IconList}
162
+ onClick={onNavigate}
163
+ />
164
+ ))}
165
+ {unpinnedViews.map((view) => (
166
+ <AppSidebarNavItem
167
+ key={`view-${view.id}`}
168
+ to={savedViewHref(view)}
169
+ label={view.name}
170
+ icon={view.viewKind === "board" ? IconLayoutBoard : IconTable}
171
+ onClick={onNavigate}
172
+ />
173
+ ))}
174
+ {loadFailed ? (
175
+ <div
176
+ className={cn(
177
+ "flex items-center gap-2 rounded-md px-2 py-1.5 text-xs text-destructive",
178
+ collapsed && "justify-center px-0",
179
+ )}
292
180
  >
293
- {lists.map((list) => (
294
- <ListRow
295
- key={`list-${list.id}`}
296
- to={`/lists/${encodeURIComponent(list.id)}`}
297
- label={list.name}
298
- icon={IconList}
299
- collapsed={collapsed}
300
- onNavigate={onNavigate}
301
- />
302
- ))}
303
- {unpinnedViews.map((view) => (
304
- <ListRow
305
- key={`view-${view.id}`}
306
- to={savedViewHref(view)}
307
- label={view.name}
308
- icon={view.viewKind === "board" ? IconLayoutBoard : IconTable}
309
- collapsed={collapsed}
310
- onNavigate={onNavigate}
311
- />
312
- ))}
313
- {loadFailed ? (
314
- <div
315
- className={cn(
316
- "flex items-center gap-2 rounded-md px-2 py-1.5 text-xs text-destructive",
317
- collapsed && "justify-center px-0",
318
- )}
319
- >
320
- <IconAlertTriangle className="size-4 shrink-0" />
321
- {!collapsed && (
322
- <>
323
- <span className="min-w-0 flex-1">
324
- {t("navigation.listsLoadFailed")}
325
- </span>
326
- <Button
327
- type="button"
328
- variant="ghost"
329
- size="sm"
330
- className="h-6 px-2 text-xs"
331
- onClick={() => {
332
- void listsQuery.refetch();
333
- void viewsQuery.refetch();
334
- }}
335
- >
336
- {t("navigation.retry")}
337
- </Button>
338
- </>
339
- )}
340
- </div>
341
- ) : settled &&
342
- lists.length === 0 &&
343
- unpinnedViews.length === 0 &&
344
- !collapsed ? (
345
- <p className="px-2 py-1 text-xs text-sidebar-foreground/50">
346
- {t("navigation.listsEmpty")}
347
- </p>
348
- ) : null}
349
- </SidebarSection>
350
- </div>
351
-
352
- <div className="mt-2 shrink-0 border-t border-sidebar-border pt-2">
353
- <div className="grid gap-0.5">
354
- {footerNav.map((item) => {
355
- const Icon = item.icon;
356
- const label = t(item.labelKey);
357
- const isActive = location.pathname.startsWith(item.to);
358
- return (
359
- <CollapsibleTooltip
360
- key={item.to}
361
- collapsed={collapsed}
362
- label={label}
181
+ <IconAlertTriangle className="size-4 shrink-0" />
182
+ {!collapsed && (
183
+ <>
184
+ <span className="min-w-0 flex-1">
185
+ {t("navigation.listsLoadFailed")}
186
+ </span>
187
+ <Button
188
+ type="button"
189
+ variant="ghost"
190
+ size="sm"
191
+ className="h-6 px-2 text-xs"
192
+ onClick={() => {
193
+ void listsQuery.refetch();
194
+ void viewsQuery.refetch();
195
+ }}
363
196
  >
364
- <Link
365
- to={item.to}
366
- onClick={onNavigate}
367
- aria-current={isActive ? "page" : undefined}
368
- className={itemClasses(isActive, collapsed)}
369
- >
370
- <Icon className="size-4 shrink-0" />
371
- {!collapsed && <span className="truncate">{label}</span>}
372
- </Link>
373
- </CollapsibleTooltip>
374
- );
375
- })}
197
+ {t("navigation.retry")}
198
+ </Button>
199
+ </>
200
+ )}
376
201
  </div>
377
-
378
- {!collapsed && (
379
- <div className="mt-2 grid gap-2 px-1 empty:hidden">
380
- <OrgSwitcher reserveSpace />
381
- <DevDatabaseLink />
382
- </div>
383
- )}
384
-
385
- <SidebarFooterActions
386
- collapsed={collapsed}
387
- feedback={
388
- <FeedbackButton
389
- variant={collapsed ? "icon" : "sidebar"}
390
- side="right"
391
- className={collapsed ? "size-8" : "min-w-0"}
392
- />
393
- }
394
- search={searchButton}
395
- collapse={collapseButton}
396
- />
397
- </div>
398
- </nav>
399
- </TooltipProvider>
202
+ ) : settled &&
203
+ lists.length === 0 &&
204
+ unpinnedViews.length === 0 &&
205
+ !collapsed ? (
206
+ <p className="px-2 py-1 text-xs text-sidebar-foreground/50">
207
+ {t("navigation.listsEmpty")}
208
+ </p>
209
+ ) : null}
210
+ </AppSidebarSection>
211
+ </AppSidebar>
400
212
  );
401
213
  }