@agent-native/core 0.76.9 → 0.76.11

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 (137) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +39 -0
  3. package/corpus/core/docs/content/locales/ar-SA/actions.md +7 -7
  4. package/corpus/core/docs/content/locales/ar-SA/template-plan.md +6 -4
  5. package/corpus/core/docs/content/locales/de-DE/actions.md +9 -9
  6. package/corpus/core/docs/content/locales/de-DE/template-plan.md +6 -4
  7. package/corpus/core/docs/content/locales/es-ES/actions.md +9 -9
  8. package/corpus/core/docs/content/locales/es-ES/template-plan.md +6 -4
  9. package/corpus/core/docs/content/locales/fr-FR/actions.md +9 -9
  10. package/corpus/core/docs/content/locales/fr-FR/template-plan.md +6 -4
  11. package/corpus/core/docs/content/locales/hi-IN/actions.md +9 -9
  12. package/corpus/core/docs/content/locales/hi-IN/template-plan.md +4 -4
  13. package/corpus/core/docs/content/locales/ja-JP/actions.md +9 -9
  14. package/corpus/core/docs/content/locales/ja-JP/template-plan.md +4 -4
  15. package/corpus/core/docs/content/locales/ko-KR/actions.md +9 -9
  16. package/corpus/core/docs/content/locales/ko-KR/template-plan.md +4 -4
  17. package/corpus/core/docs/content/locales/pt-BR/actions.md +9 -9
  18. package/corpus/core/docs/content/locales/pt-BR/template-plan.md +6 -4
  19. package/corpus/core/docs/content/locales/zh-CN/actions.md +9 -9
  20. package/corpus/core/docs/content/locales/zh-CN/template-plan.md +4 -4
  21. package/corpus/core/package.json +1 -1
  22. package/corpus/core/scripts/generate-og-font-data.mjs +9 -5
  23. package/corpus/core/src/client/AgentPanel.tsx +70 -1
  24. package/corpus/core/src/client/AssistantChat.tsx +1 -3
  25. package/corpus/core/src/client/ErrorBoundary.tsx +151 -10
  26. package/corpus/core/src/client/MultiTabAssistantChat.tsx +0 -62
  27. package/corpus/core/src/client/composer/TiptapComposer.tsx +6 -13
  28. package/corpus/core/src/server/og-fonts-data.ts +7 -4
  29. package/corpus/core/src/server/og-fonts.ts +10 -3
  30. package/corpus/core/src/server/social-og-image.ts +45 -6
  31. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +199 -19
  32. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +51 -31
  33. package/corpus/templates/analytics/app/components/layout/DashboardHeader.tsx +26 -16
  34. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -2
  35. package/corpus/templates/analytics/app/components/layout/HeaderActions.tsx +8 -1
  36. package/corpus/templates/analytics/app/components/layout/Layout.tsx +2 -5
  37. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +172 -107
  38. package/corpus/templates/analytics/app/i18n-data.ts +1076 -5
  39. package/corpus/templates/analytics/app/pages/Settings.tsx +2 -2
  40. package/corpus/templates/analytics/app/pages/adhoc/AdhocRouter.tsx +1 -21
  41. package/corpus/templates/analytics/app/pages/adhoc/DashboardSkeleton.tsx +35 -0
  42. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -23
  43. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +3 -26
  44. package/corpus/templates/analytics/changelog/2026-06-24-analytics-navigation-command-palette-and-settings-now-honor-.md +6 -0
  45. package/corpus/templates/analytics/changelog/2026-06-24-daily-dashboard-charts-now-use-local-day-buckets-and-show-th.md +6 -0
  46. package/corpus/templates/analytics/changelog/2026-06-24-dashboard-loading-placeholders-now-span-the-available-page-w.md +6 -0
  47. package/corpus/templates/analytics/changelog/2026-06-24-first-party-dashboard-dates-now-align-to-pacific-time-for-da.md +6 -0
  48. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +19 -7
  49. package/corpus/templates/assets/app/components/layout/Header.tsx +0 -2
  50. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +0 -2
  51. package/corpus/templates/calendar/app/pages/CalendarView.tsx +0 -2
  52. package/corpus/templates/chat/app/components/layout/Header.tsx +1 -6
  53. package/corpus/templates/clips/app/components/layout/Header.tsx +1 -6
  54. package/corpus/templates/clips/app/hooks/use-library.ts +2 -0
  55. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +3 -1
  56. package/corpus/templates/clips/changelog/2026-06-24-archive-and-spaces-navigation-is-more-resilient-when-sidebar.md +6 -0
  57. package/corpus/templates/content/app/components/layout/Header.tsx +0 -2
  58. package/corpus/templates/design/app/components/layout/Header.tsx +1 -6
  59. package/corpus/templates/forms/app/components/layout/Header.tsx +1 -6
  60. package/corpus/templates/macros/app/components/layout/Header.tsx +1 -6
  61. package/corpus/templates/mail/app/components/email/CodeBlockLangPicker.tsx +4 -2
  62. package/corpus/templates/mail/app/components/email/ComposeBubbleToolbar.tsx +18 -12
  63. package/corpus/templates/mail/app/components/email/ComposeEditor.tsx +9 -5
  64. package/corpus/templates/mail/app/components/email/ComposeModal.tsx +36 -19
  65. package/corpus/templates/mail/app/components/email/EmailList.tsx +59 -55
  66. package/corpus/templates/mail/app/components/email/EmailListItem.tsx +7 -3
  67. package/corpus/templates/mail/app/components/email/EmailThread.tsx +25 -16
  68. package/corpus/templates/mail/app/components/email/InlineReplyComposer.tsx +25 -19
  69. package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +32 -17
  70. package/corpus/templates/mail/app/components/email/RecipientInput.tsx +26 -10
  71. package/corpus/templates/mail/app/components/email/SendLaterButton.tsx +5 -3
  72. package/corpus/templates/mail/app/components/email/SnoozeModal.tsx +4 -2
  73. package/corpus/templates/mail/app/components/email/SnoozePopover.tsx +9 -5
  74. package/corpus/templates/mail/app/components/email/extensions/ComposeImageBlock.tsx +4 -2
  75. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +168 -86
  76. package/corpus/templates/mail/app/components/layout/SearchBar.tsx +4 -2
  77. package/corpus/templates/mail/app/i18n/ar-SA.ts +212 -0
  78. package/corpus/templates/mail/app/i18n/de-DE.ts +212 -0
  79. package/corpus/templates/mail/app/i18n/en-US.ts +212 -0
  80. package/corpus/templates/mail/app/i18n/es-ES.ts +212 -0
  81. package/corpus/templates/mail/app/i18n/fr-FR.ts +212 -0
  82. package/corpus/templates/mail/app/i18n/hi-IN.ts +212 -0
  83. package/corpus/templates/mail/app/i18n/ja-JP.ts +212 -0
  84. package/corpus/templates/mail/app/i18n/ko-KR.ts +212 -0
  85. package/corpus/templates/mail/app/i18n/pt-BR.ts +212 -0
  86. package/corpus/templates/mail/app/i18n/zh-CN.ts +211 -0
  87. package/corpus/templates/mail/changelog/2026-06-24-interface-language-support-now-covers-more-mail-controls-and.md +6 -0
  88. package/corpus/templates/plan/app/components/layout/Header.tsx +1 -6
  89. package/corpus/templates/slides/app/components/layout/Header.tsx +1 -6
  90. package/corpus/templates/videos/app/components/layout/Header.tsx +1 -6
  91. package/dist/client/AgentPanel.d.ts +5 -1
  92. package/dist/client/AgentPanel.d.ts.map +1 -1
  93. package/dist/client/AgentPanel.js +23 -4
  94. package/dist/client/AgentPanel.js.map +1 -1
  95. package/dist/client/AssistantChat.d.ts +1 -3
  96. package/dist/client/AssistantChat.d.ts.map +1 -1
  97. package/dist/client/AssistantChat.js.map +1 -1
  98. package/dist/client/ErrorBoundary.d.ts.map +1 -1
  99. package/dist/client/ErrorBoundary.js +128 -7
  100. package/dist/client/ErrorBoundary.js.map +1 -1
  101. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  102. package/dist/client/MultiTabAssistantChat.js +1 -17
  103. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  104. package/dist/client/composer/TiptapComposer.d.ts +4 -0
  105. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  106. package/dist/client/composer/TiptapComposer.js +5 -9
  107. package/dist/client/composer/TiptapComposer.js.map +1 -1
  108. package/dist/server/og-fonts-data.d.ts +1 -0
  109. package/dist/server/og-fonts-data.d.ts.map +1 -1
  110. package/dist/server/og-fonts-data.js +5 -4
  111. package/dist/server/og-fonts-data.js.map +1 -1
  112. package/dist/server/og-fonts.d.ts +1 -0
  113. package/dist/server/og-fonts.d.ts.map +1 -1
  114. package/dist/server/og-fonts.js +10 -4
  115. package/dist/server/og-fonts.js.map +1 -1
  116. package/dist/server/social-og-image.d.ts.map +1 -1
  117. package/dist/server/social-og-image.js +33 -6
  118. package/dist/server/social-og-image.js.map +1 -1
  119. package/docs/content/locales/ar-SA/actions.md +7 -7
  120. package/docs/content/locales/ar-SA/template-plan.md +6 -4
  121. package/docs/content/locales/de-DE/actions.md +9 -9
  122. package/docs/content/locales/de-DE/template-plan.md +6 -4
  123. package/docs/content/locales/es-ES/actions.md +9 -9
  124. package/docs/content/locales/es-ES/template-plan.md +6 -4
  125. package/docs/content/locales/fr-FR/actions.md +9 -9
  126. package/docs/content/locales/fr-FR/template-plan.md +6 -4
  127. package/docs/content/locales/hi-IN/actions.md +9 -9
  128. package/docs/content/locales/hi-IN/template-plan.md +4 -4
  129. package/docs/content/locales/ja-JP/actions.md +9 -9
  130. package/docs/content/locales/ja-JP/template-plan.md +4 -4
  131. package/docs/content/locales/ko-KR/actions.md +9 -9
  132. package/docs/content/locales/ko-KR/template-plan.md +4 -4
  133. package/docs/content/locales/pt-BR/actions.md +9 -9
  134. package/docs/content/locales/pt-BR/template-plan.md +6 -4
  135. package/docs/content/locales/zh-CN/actions.md +9 -9
  136. package/docs/content/locales/zh-CN/template-plan.md +4 -4
  137. package/package.json +1 -1
@@ -17,8 +17,6 @@ export default function Settings() {
17
17
 
18
18
  return (
19
19
  <div className="space-y-6 max-w-2xl">
20
- <ChangelogSettingsCard markdown={changelog} />
21
-
22
20
  <Card className="bg-card border-border/50">
23
21
  <CardHeader>
24
22
  <CardTitle className="text-base">{t("settings.account")}</CardTitle>
@@ -92,6 +90,8 @@ export default function Settings() {
92
90
  <p>{t("settings.aboutUsage")}</p>
93
91
  </CardContent>
94
92
  </Card>
93
+
94
+ <ChangelogSettingsCard markdown={changelog} />
95
95
  </div>
96
96
  );
97
97
  }
@@ -1,9 +1,8 @@
1
1
  import { Suspense, lazy, useEffect } from "react";
2
2
  import { useParams } from "react-router";
3
- import { Card, CardContent, CardHeader } from "@/components/ui/card";
4
- import { Skeleton } from "@/components/ui/skeleton";
5
3
  import { dashboardComponents } from "./registry";
6
4
  import { incrementItemView } from "@/lib/item-popularity";
5
+ import { DashboardSkeleton } from "./DashboardSkeleton";
7
6
 
8
7
  const SqlDashboardPage = lazy(() => import("./sql-dashboard"));
9
8
 
@@ -11,25 +10,6 @@ const SqlDashboardPage = lazy(() => import("./sql-dashboard"));
11
10
  // Suspense → dashboard config load. Matches the real SqlChartCard shape (Card
12
11
  // chrome + title row + chart-body skeleton) so the user sees one continuous
13
12
  // skeleton state rather than four different ones morphing into each other.
14
- function DashboardSkeleton() {
15
- return (
16
- <div className="space-y-4">
17
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
18
- {[0, 1].map((i) => (
19
- <Card key={i} className="flex flex-col overflow-visible">
20
- <CardHeader className="pb-2 shrink-0">
21
- <Skeleton className="h-4 w-32" />
22
- </CardHeader>
23
- <CardContent className="flex flex-1 flex-col pt-0">
24
- <Skeleton className="w-full flex-1 min-h-[250px]" />
25
- </CardContent>
26
- </Card>
27
- ))}
28
- </div>
29
- </div>
30
- );
31
- }
32
-
33
13
  function SqlDashboardLoader() {
34
14
  return (
35
15
  <Suspense fallback={<DashboardSkeleton />}>
@@ -0,0 +1,35 @@
1
+ import type { CSSProperties } from "react";
2
+ import { Card, CardContent, CardHeader } from "@/components/ui/card";
3
+ import { Skeleton } from "@/components/ui/skeleton";
4
+
5
+ interface DashboardSkeletonProps {
6
+ columns?: number;
7
+ count?: number;
8
+ }
9
+
10
+ export function DashboardSkeleton({
11
+ columns = 2,
12
+ count = 2,
13
+ }: DashboardSkeletonProps) {
14
+ return (
15
+ <div className="dashboard-grid-container space-y-4">
16
+ <div
17
+ className="dashboard-grid"
18
+ style={{ "--dash-cols": columns } as CSSProperties}
19
+ >
20
+ {Array.from({ length: count }, (_, i) => (
21
+ <div key={i} className="dashboard-grid-cell h-full">
22
+ <Card className="flex h-full flex-col overflow-visible">
23
+ <CardHeader className="pb-2 shrink-0">
24
+ <Skeleton className="h-4 w-32" />
25
+ </CardHeader>
26
+ <CardContent className="flex flex-1 flex-col pt-0">
27
+ <Skeleton className="w-full flex-1 min-h-[250px]" />
28
+ </CardContent>
29
+ </Card>
30
+ </div>
31
+ ))}
32
+ </div>
33
+ </div>
34
+ );
35
+ }
@@ -3,7 +3,7 @@ import { useSearchParams, useNavigate } from "react-router";
3
3
  import { useQuery, useQueryClient } from "@tanstack/react-query";
4
4
  import { Button } from "@/components/ui/button";
5
5
  import { Input } from "@/components/ui/input";
6
- import { Card, CardContent, CardHeader } from "@/components/ui/card";
6
+ import { Card, CardContent } from "@/components/ui/card";
7
7
  import {
8
8
  Dialog,
9
9
  DialogContent,
@@ -21,7 +21,6 @@ import {
21
21
  AlertDialogHeader,
22
22
  AlertDialogTitle,
23
23
  } from "@/components/ui/alert-dialog";
24
- import { Skeleton } from "@/components/ui/skeleton";
25
24
  import {
26
25
  IconPlus,
27
26
  IconTrash,
@@ -82,6 +81,7 @@ import {
82
81
  TooltipContent,
83
82
  TooltipTrigger,
84
83
  } from "@/components/ui/tooltip";
84
+ import { DashboardSkeleton } from "../DashboardSkeleton";
85
85
 
86
86
  export interface DashboardChart {
87
87
  id: string;
@@ -485,27 +485,7 @@ export default function ExplorerDashboardPage() {
485
485
  }
486
486
 
487
487
  if (!loaded) {
488
- // Match the eventual DashboardChartCard layout (Card chrome + title row +
489
- // chart-body skeleton) so the transition from "dashboard config loading"
490
- // to "queries loading" doesn't morph skeleton shape — the title text just
491
- // fills in. Otherwise the bare h-64 rectangles jump into Card-chromed
492
- // panels and the page visibly shifts.
493
- return (
494
- <div className="space-y-4">
495
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
496
- {[0, 1].map((i) => (
497
- <Card key={i} className="flex flex-col overflow-visible">
498
- <CardHeader className="pb-2 shrink-0">
499
- <Skeleton className="h-4 w-32" />
500
- </CardHeader>
501
- <CardContent className="flex flex-1 flex-col pt-0">
502
- <Skeleton className="w-full flex-1 min-h-[250px]" />
503
- </CardContent>
504
- </Card>
505
- ))}
506
- </div>
507
- </div>
508
- );
488
+ return <DashboardSkeleton />;
509
489
  }
510
490
 
511
491
  if (!dashboard) return null;
@@ -12,8 +12,7 @@ import { toast } from "sonner";
12
12
  import { Button } from "@/components/ui/button";
13
13
  import { Input } from "@/components/ui/input";
14
14
  import { Textarea } from "@/components/ui/textarea";
15
- import { Card, CardContent, CardHeader } from "@/components/ui/card";
16
- import { Skeleton } from "@/components/ui/skeleton";
15
+ import { Card, CardContent } from "@/components/ui/card";
17
16
  import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
18
17
  import {
19
18
  AlertDialog,
@@ -90,6 +89,7 @@ import {
90
89
  sqlDashboardPrefetchKey,
91
90
  type PrefetchSnapshot,
92
91
  } from "@/lib/prefetch-keys";
92
+ import { DashboardSkeleton } from "../DashboardSkeleton";
93
93
  import {
94
94
  resourceCanEdit,
95
95
  resourceCanManage,
@@ -1119,30 +1119,7 @@ export default function SqlDashboardPage() {
1119
1119
  }
1120
1120
 
1121
1121
  if (!loaded) {
1122
- // Match the eventual SqlChartCard layout exactly (Card chrome + title row +
1123
- // chart-body skeleton) so the transition from "dashboard config loading" to
1124
- // "queries loading" doesn't morph the skeleton's shape — only the title
1125
- // text fills in. Otherwise the bare h-64 rectangles jump into Card-chromed
1126
- // panels and the page visibly shifts.
1127
- return (
1128
- <div className="dashboard-grid-container space-y-4">
1129
- <div
1130
- className="dashboard-grid"
1131
- style={{ "--dash-cols": 2 } as React.CSSProperties}
1132
- >
1133
- {[0, 1].map((i) => (
1134
- <Card key={i} className="flex flex-col overflow-visible">
1135
- <CardHeader className="pb-2 shrink-0">
1136
- <Skeleton className="h-4 w-32" />
1137
- </CardHeader>
1138
- <CardContent className="flex flex-1 flex-col pt-0">
1139
- <Skeleton className="w-full flex-1 min-h-[250px]" />
1140
- </CardContent>
1141
- </Card>
1142
- ))}
1143
- </div>
1144
- </div>
1145
- );
1122
+ return <DashboardSkeleton />;
1146
1123
  }
1147
1124
 
1148
1125
  if (!dashboard) return <BlankDashboard />;
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-06-24
4
+ ---
5
+
6
+ Analytics navigation, command palette, and settings now honor the selected interface language.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-06-24
4
+ ---
5
+
6
+ Daily dashboard charts now show the in-progress day as a dashed segment.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-06-24
4
+ ---
5
+
6
+ Dashboard loading placeholders now span the available page width.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-06-24
4
+ ---
5
+
6
+ First-party dashboard dates now align to Pacific time for daily activity and retention panels.
@@ -98,8 +98,20 @@ function fixed(sql: string): (window?: MetricWindow) => string {
98
98
 
99
99
  const TEMPLATE_EXPR =
100
100
  "COALESCE(NULLIF(template, ''), NULLIF(properties::jsonb ->> 'templateId', ''), NULLIF(properties::jsonb ->> 'agent_native_template', ''), NULLIF(properties::jsonb ->> 'agentNativeTemplate', ''), NULLIF(app, ''), NULLIF(properties::jsonb ->> 'agent_native_app', ''), NULLIF(properties::jsonb ->> 'agentNativeApp', ''), 'unknown')";
101
- const DASHBOARD_TIME_RANGE_FILTER =
102
- "('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD')))";
101
+ const LOCAL_EVENT_DATE_SQL = "substr(timestamp, 1, 10)";
102
+
103
+ function daysAgoSql(days: number): string {
104
+ const unit = days === 1 ? "day" : "days";
105
+ return `to_char(CURRENT_DATE - INTERVAL '${days} ${unit}', 'YYYY-MM-DD')`;
106
+ }
107
+
108
+ function dashboardTimeRangeFilter(dateExpr = LOCAL_EVENT_DATE_SQL): string {
109
+ return `('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND ${dateExpr} >= ${daysAgoSql(7)}) OR ('{{timeRange}}' = '30d' AND ${dateExpr} >= ${daysAgoSql(30)}) OR ('{{timeRange}}' = '90d' AND ${dateExpr} >= ${daysAgoSql(90)}) OR ('{{timeRange}}' = '180d' AND ${dateExpr} >= ${daysAgoSql(180)}) OR ('{{timeRange}}' = '365d' AND ${dateExpr} >= ${daysAgoSql(365)}))`;
110
+ }
111
+
112
+ const DASHBOARD_TIME_RANGE_FILTER = dashboardTimeRangeFilter();
113
+ const DASHBOARD_EVENT_DATE_RANGE_FILTER =
114
+ dashboardTimeRangeFilter("event_date");
103
115
  const DASHBOARD_EMAIL_FILTER =
104
116
  "('{{emailFilter}}' IN ('', 'all') OR ('{{emailFilter}}' = 'exclude_builder' AND lower(coalesce(user_id, '')) NOT LIKE '%@builder.io') OR ('{{emailFilter}}' = 'only_builder' AND lower(coalesce(user_id, '')) LIKE '%@builder.io'))";
105
117
  export const FIRST_PARTY_DASHBOARD_FILTERS: FirstPartyDashboardFilter[] = [
@@ -143,11 +155,11 @@ export function usesFirstPartyDashboardFilters(sql: string): boolean {
143
155
 
144
156
  const TOTAL_SIGNUPS_SQL = `SELECT COUNT(*) AS signups FROM analytics_events WHERE event_name = 'signup' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER}`;
145
157
  const SIGNUPS_OVER_TIME_SQL = `WITH offsets AS (SELECT (ROW_NUMBER() OVER (ORDER BY timestamp) - 1)::int AS n FROM analytics_events LIMIT 800), signup_events AS (SELECT substr(timestamp, 1, 10) AS date, ${TEMPLATE_EXPR} AS template FROM analytics_events WHERE event_name = 'signup' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER}), bounds AS (SELECT MIN(date::date) AS start_date, MAX(date::date) AS end_date FROM signup_events), dates AS (SELECT to_char(bounds.start_date + offsets.n, 'YYYY-MM-DD') AS date FROM bounds CROSS JOIN offsets WHERE bounds.start_date IS NOT NULL AND bounds.start_date + offsets.n <= bounds.end_date), templates AS (SELECT DISTINCT template FROM signup_events), daily AS (SELECT date, template, COUNT(*) AS count FROM signup_events GROUP BY date, template) SELECT dates.date, templates.template, COALESCE(daily.count, 0) AS count FROM dates CROSS JOIN templates LEFT JOIN daily ON daily.date = dates.date AND daily.template = templates.template ORDER BY dates.date, templates.template`;
146
- const ONE_DAY_RETENTION_BY_TEMPLATE_SQL = `WITH base AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, ${TEMPLATE_EXPR} AS template, substr(timestamp, 1, 10) AS event_date, user_id FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ${DASHBOARD_EMAIL_FILTER}), first_seen AS (SELECT user_key, template, MIN(event_date) AS cohort_date FROM base GROUP BY user_key, template), cohorts AS (SELECT user_key, template, cohort_date FROM first_seen WHERE cohort_date <= to_char(CURRENT_DATE - INTERVAL '1 day', 'YYYY-MM-DD') AND ('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD')))) SELECT c.cohort_date AS date, c.template, COALESCE(COUNT(DISTINCT c.user_key) FILTER (WHERE b.event_date = to_char(c.cohort_date::date + INTERVAL '1 day', 'YYYY-MM-DD'))::float / NULLIF(COUNT(DISTINCT c.user_key), 0), 0) AS rate FROM cohorts c LEFT JOIN base b ON b.user_key = c.user_key AND b.template = c.template GROUP BY c.cohort_date, c.template ORDER BY c.cohort_date, c.template`;
147
- const SEVEN_DAY_RETENTION_BY_TEMPLATE_SQL = `WITH base AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, ${TEMPLATE_EXPR} AS template, substr(timestamp, 1, 10) AS event_date, user_id FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ${DASHBOARD_EMAIL_FILTER}), first_seen AS (SELECT user_key, template, MIN(event_date) AS cohort_date FROM base GROUP BY user_key, template), cohorts AS (SELECT user_key, template, cohort_date FROM first_seen WHERE cohort_date <= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD') AND ('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD')))) SELECT c.cohort_date AS date, c.template, COALESCE(COUNT(DISTINCT c.user_key) FILTER (WHERE b.event_date = to_char(c.cohort_date::date + INTERVAL '7 days', 'YYYY-MM-DD'))::float / NULLIF(COUNT(DISTINCT c.user_key), 0), 0) AS rate FROM cohorts c LEFT JOIN base b ON b.user_key = c.user_key AND b.template = c.template GROUP BY c.cohort_date, c.template ORDER BY c.cohort_date, c.template`;
158
+ const ONE_DAY_RETENTION_BY_TEMPLATE_SQL = `WITH base AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, ${TEMPLATE_EXPR} AS template, substr(timestamp, 1, 10) AS event_date, user_id FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ${DASHBOARD_EMAIL_FILTER}), first_seen AS (SELECT user_key, template, MIN(event_date) AS cohort_date FROM base GROUP BY user_key, template), cohorts AS (SELECT user_key, template, cohort_date FROM first_seen WHERE cohort_date <= ${daysAgoSql(1)} AND ${dashboardTimeRangeFilter("cohort_date")}) SELECT c.cohort_date AS date, c.template, COALESCE(COUNT(DISTINCT c.user_key) FILTER (WHERE b.event_date = to_char(c.cohort_date::date + INTERVAL '1 day', 'YYYY-MM-DD'))::float / NULLIF(COUNT(DISTINCT c.user_key), 0), 0) AS rate FROM cohorts c LEFT JOIN base b ON b.user_key = c.user_key AND b.template = c.template GROUP BY c.cohort_date, c.template ORDER BY c.cohort_date, c.template`;
159
+ const SEVEN_DAY_RETENTION_BY_TEMPLATE_SQL = `WITH base AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, ${TEMPLATE_EXPR} AS template, substr(timestamp, 1, 10) AS event_date, user_id FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ${DASHBOARD_EMAIL_FILTER}), first_seen AS (SELECT user_key, template, MIN(event_date) AS cohort_date FROM base GROUP BY user_key, template), cohorts AS (SELECT user_key, template, cohort_date FROM first_seen WHERE cohort_date <= ${daysAgoSql(7)} AND ${dashboardTimeRangeFilter("cohort_date")}) SELECT c.cohort_date AS date, c.template, COALESCE(COUNT(DISTINCT c.user_key) FILTER (WHERE b.event_date = to_char(c.cohort_date::date + INTERVAL '7 days', 'YYYY-MM-DD'))::float / NULLIF(COUNT(DISTINCT c.user_key), 0), 0) AS rate FROM cohorts c LEFT JOIN base b ON b.user_key = c.user_key AND b.template = c.template GROUP BY c.cohort_date, c.template ORDER BY c.cohort_date, c.template`;
148
160
  const SIGNUPS_BY_TEMPLATE_SQL = `SELECT ${TEMPLATE_EXPR} AS template, COUNT(*) AS count FROM analytics_events WHERE event_name = 'signup' AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY ${TEMPLATE_EXPR} ORDER BY count DESC`;
149
161
  const DAU_BY_TEMPLATE_SQL = `SELECT substr(timestamp, 1, 10) AS date, ${TEMPLATE_EXPR} AS template, COUNT(DISTINCT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, ''))) AS users FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY substr(timestamp, 1, 10), ${TEMPLATE_EXPR} ORDER BY date, template`;
150
- const WAU_BY_TEMPLATE_SQL = `WITH base AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, ${TEMPLATE_EXPR} AS template, substr(timestamp, 1, 10) AS event_date, user_id FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ${DASHBOARD_EMAIL_FILTER}), days AS (SELECT DISTINCT event_date AS date FROM base WHERE ${DASHBOARD_TIME_RANGE_FILTER.split("substr(timestamp, 1, 10)").join("event_date")}) SELECT d.date, b.template, COUNT(DISTINCT b.user_key) AS users FROM days d JOIN base b ON b.event_date >= to_char(d.date::date - INTERVAL '6 days', 'YYYY-MM-DD') AND b.event_date <= d.date GROUP BY d.date, b.template ORDER BY d.date, b.template`;
162
+ const WAU_BY_TEMPLATE_SQL = `WITH base AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, ${TEMPLATE_EXPR} AS template, substr(timestamp, 1, 10) AS event_date, user_id FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ${DASHBOARD_EMAIL_FILTER}), days AS (SELECT DISTINCT event_date AS date FROM base WHERE ${DASHBOARD_EVENT_DATE_RANGE_FILTER}) SELECT d.date, b.template, COUNT(DISTINCT b.user_key) AS users FROM days d JOIN base b ON b.event_date >= to_char(d.date::date - INTERVAL '6 days', 'YYYY-MM-DD') AND b.event_date <= d.date GROUP BY d.date, b.template ORDER BY d.date, b.template`;
151
163
 
152
164
  /**
153
165
  * Catalog entries. Order here is the default panel order when a caller passes
@@ -498,7 +510,7 @@ const ENTRIES: FirstPartyMetric[] = [
498
510
  width: 1,
499
511
  windowed: false,
500
512
  buildSql: fixed(
501
- "WITH user_days AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, COUNT(DISTINCT substr(timestamp, 1, 10)) AS active_days FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND substr(timestamp, 1, 10) >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD'))) AND ('{{emailFilter}}' IN ('', 'all') OR ('{{emailFilter}}' = 'exclude_builder' AND lower(coalesce(user_id, '')) NOT LIKE '%@builder.io') OR ('{{emailFilter}}' = 'only_builder' AND lower(coalesce(user_id, '')) LIKE '%@builder.io')) GROUP BY COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, ''))) SELECT COUNT(*) AS count FROM user_days WHERE active_days >= 2",
513
+ `WITH user_days AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, COUNT(DISTINCT substr(timestamp, 1, 10)) AS active_days FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} GROUP BY COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, ''))) SELECT COUNT(*) AS count FROM user_days WHERE active_days >= 2`,
502
514
  ),
503
515
  config: {
504
516
  yKey: "count",
@@ -515,7 +527,7 @@ const ENTRIES: FirstPartyMetric[] = [
515
527
  width: 3,
516
528
  windowed: false,
517
529
  buildSql: fixed(
518
- "WITH base AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, substr(timestamp, 1, 10) AS event_date, user_id FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ('{{emailFilter}}' IN ('', 'all') OR ('{{emailFilter}}' = 'exclude_builder' AND lower(coalesce(user_id, '')) NOT LIKE '%@builder.io') OR ('{{emailFilter}}' = 'only_builder' AND lower(coalesce(user_id, '')) LIKE '%@builder.io'))), first_seen AS (SELECT user_key, MIN(event_date) AS cohort_date FROM base GROUP BY user_key), cohorts AS (SELECT user_key, cohort_date FROM first_seen WHERE cohort_date <= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD') AND ('{{timeRange}}' IN ('', 'all') OR ('{{timeRange}}' = '7d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '7 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '30d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '30 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '90d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '90 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '180d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '180 days', 'YYYY-MM-DD')) OR ('{{timeRange}}' = '365d' AND cohort_date >= to_char(CURRENT_DATE - INTERVAL '365 days', 'YYYY-MM-DD')))), retention AS (SELECT c.cohort_date AS date, '1d retention' AS period, COALESCE(COUNT(DISTINCT c.user_key) FILTER (WHERE b.event_date = to_char(c.cohort_date::date + INTERVAL '1 day', 'YYYY-MM-DD'))::float / NULLIF(COUNT(DISTINCT c.user_key), 0), 0) AS rate FROM cohorts c LEFT JOIN base b ON b.user_key = c.user_key GROUP BY c.cohort_date UNION ALL SELECT c.cohort_date AS date, '7d retention' AS period, COALESCE(COUNT(DISTINCT c.user_key) FILTER (WHERE b.event_date = to_char(c.cohort_date::date + INTERVAL '7 days', 'YYYY-MM-DD'))::float / NULLIF(COUNT(DISTINCT c.user_key), 0), 0) AS rate FROM cohorts c LEFT JOIN base b ON b.user_key = c.user_key GROUP BY c.cohort_date) SELECT date, period, rate FROM retention ORDER BY date, period",
530
+ `WITH base AS (SELECT COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) AS user_key, substr(timestamp, 1, 10) AS event_date, user_id FROM analytics_events WHERE COALESCE(NULLIF(user_id, ''), NULLIF(anonymous_id, '')) IS NOT NULL AND ${DASHBOARD_EMAIL_FILTER}), first_seen AS (SELECT user_key, MIN(event_date) AS cohort_date FROM base GROUP BY user_key), cohorts AS (SELECT user_key, cohort_date FROM first_seen WHERE cohort_date <= ${daysAgoSql(7)} AND ${dashboardTimeRangeFilter("cohort_date")}), retention AS (SELECT c.cohort_date AS date, '1d retention' AS period, COALESCE(COUNT(DISTINCT c.user_key) FILTER (WHERE b.event_date = to_char(c.cohort_date::date + INTERVAL '1 day', 'YYYY-MM-DD'))::float / NULLIF(COUNT(DISTINCT c.user_key), 0), 0) AS rate FROM cohorts c LEFT JOIN base b ON b.user_key = c.user_key GROUP BY c.cohort_date UNION ALL SELECT c.cohort_date AS date, '7d retention' AS period, COALESCE(COUNT(DISTINCT c.user_key) FILTER (WHERE b.event_date = to_char(c.cohort_date::date + INTERVAL '7 days', 'YYYY-MM-DD'))::float / NULLIF(COUNT(DISTINCT c.user_key), 0), 0) AS rate FROM cohorts c LEFT JOIN base b ON b.user_key = c.user_key GROUP BY c.cohort_date) SELECT date, period, rate FROM retention ORDER BY date, period`,
519
531
  ),
520
532
  config: {
521
533
  xKey: "date",
@@ -1,7 +1,6 @@
1
1
  import { useLocation } from "react-router";
2
2
  import {
3
3
  AgentToggleButton,
4
- LanguagePicker,
5
4
  useActionQuery,
6
5
  useT,
7
6
  } from "@agent-native/core/client";
@@ -55,7 +54,6 @@ export function Header() {
55
54
  </div>
56
55
  <div className="flex items-center gap-2 shrink-0">
57
56
  {actions}
58
- <LanguagePicker variant="icon" />
59
57
  {showAgentToggle ? <AgentToggleButton /> : null}
60
58
  </div>
61
59
  </header>
@@ -12,7 +12,6 @@ import { Button } from "@/components/ui/button";
12
12
  import {
13
13
  AgentSidebar,
14
14
  AgentToggleButton,
15
- LanguagePicker,
16
15
  NotificationsBell,
17
16
  useAppearanceSync,
18
17
  } from "@agent-native/core/client";
@@ -288,7 +287,6 @@ export function AppLayout({ children }: AppLayoutProps) {
288
287
  </div>
289
288
  <div className="flex shrink-0 items-center gap-2">
290
289
  {headerControls?.right}
291
- <LanguagePicker variant="icon" />
292
290
  {!isMobile && (
293
291
  <NotificationsBell emptyDescription="Calendar can pop browser alerts while this app is open. Clips desktop handles fuller meeting prompts with one-click notes." />
294
292
  )}
@@ -72,7 +72,6 @@ import { useQueryClient } from "@tanstack/react-query";
72
72
  import {
73
73
  AgentToggleButton,
74
74
  agentNativePath,
75
- LanguagePicker,
76
75
  NotificationsBell,
77
76
  } from "@agent-native/core/client";
78
77
  import { useIsMobile } from "@/hooks/use-mobile";
@@ -1416,7 +1415,6 @@ export default function CalendarView() {
1416
1415
  emptyDescription="Calendar can pop browser alerts while this app is open. Clips desktop handles fuller meeting prompts with one-click notes."
1417
1416
  />
1418
1417
  )}
1419
- <LanguagePicker variant="icon" />
1420
1418
  <CreateEventPopover
1421
1419
  open={createDialogOpen}
1422
1420
  onOpenChange={(open) => {
@@ -1,11 +1,7 @@
1
1
  import { useLocation } from "react-router";
2
2
  import { IconMenu2 } from "@tabler/icons-react";
3
3
  import { useHeaderTitle, useHeaderActions } from "./HeaderActions";
4
- import {
5
- AgentToggleButton,
6
- LanguagePicker,
7
- useT,
8
- } from "@agent-native/core/client";
4
+ import { AgentToggleButton, useT } from "@agent-native/core/client";
9
5
  import { APP_TITLE } from "@/lib/app-config";
10
6
 
11
7
  const pageTitleKeys: Record<string, string> = {
@@ -52,7 +48,6 @@ export function Header({ onOpenMobileSidebar }: HeaderProps) {
52
48
  </div>
53
49
  <div className="flex items-center gap-2 shrink-0">
54
50
  {actions}
55
- <LanguagePicker variant="icon" />
56
51
  <AgentToggleButton />
57
52
  </div>
58
53
  </header>
@@ -1,10 +1,6 @@
1
1
  import { useLocation } from "react-router";
2
2
  import { useHeaderTitle, useHeaderActions } from "./HeaderActions";
3
- import {
4
- AgentToggleButton,
5
- LanguagePicker,
6
- useT,
7
- } from "@agent-native/core/client";
3
+ import { AgentToggleButton, useT } from "@agent-native/core/client";
8
4
 
9
5
  const pageTitleKeys: Record<string, string> = {
10
6
  "/": "navigation.library",
@@ -44,7 +40,6 @@ export function Header() {
44
40
  </div>
45
41
  <div className="flex items-center gap-2 shrink-0">
46
42
  {actions}
47
- <LanguagePicker variant="icon" />
48
43
  <AgentToggleButton />
49
44
  </div>
50
45
  </header>
@@ -101,6 +101,8 @@ export function useRecordingsCount(
101
101
  { ...args, countOnly: true } as any,
102
102
  {
103
103
  select: (data: any) => (typeof data?.total === "number" ? data.total : 0),
104
+ retry: false,
105
+ throwOnError: false,
104
106
  },
105
107
  );
106
108
  }
@@ -630,7 +630,7 @@ export default function SettingsIndexRoute() {
630
630
  </h1>
631
631
  </PageHeader>
632
632
  <div className="mx-auto w-full max-w-6xl p-6">
633
- <div className="grid gap-6 2xl:grid-cols-[minmax(0,1fr)_360px]">
633
+ <div className="space-y-6">
634
634
  <div className="min-w-0 space-y-6">
635
635
  <p className="text-sm text-muted-foreground">
636
636
  {t("settings.intro")}
@@ -1248,6 +1248,8 @@ export default function SettingsIndexRoute() {
1248
1248
  </Button>
1249
1249
  </div>
1250
1250
  </div>
1251
+ </div>
1252
+ <div className="mt-6">
1251
1253
  <CompactChangelogAside />
1252
1254
  </div>
1253
1255
  </div>
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-06-24
4
+ ---
5
+
6
+ Archive and spaces navigation is more resilient when sidebar count loading fails.
@@ -3,7 +3,6 @@ import type { ReactNode } from "react";
3
3
  import { useHeaderTitle, useHeaderActions } from "./HeaderActions";
4
4
  import {
5
5
  AgentToggleButton,
6
- LanguagePicker,
7
6
  NotificationsBell,
8
7
  } from "@agent-native/core/client";
9
8
 
@@ -42,7 +41,6 @@ export function Header({ sidebarTrigger }: HeaderProps) {
42
41
  </div>
43
42
  <div className="flex items-center gap-2 shrink-0">
44
43
  {actions}
45
- <LanguagePicker variant="icon" />
46
44
  <NotificationsBell />
47
45
  <AgentToggleButton />
48
46
  </div>
@@ -1,9 +1,5 @@
1
1
  import { useLocation } from "react-router";
2
- import {
3
- LanguagePicker,
4
- useActionQuery,
5
- useT,
6
- } from "@agent-native/core/client";
2
+ import { useActionQuery, useT } from "@agent-native/core/client";
7
3
  import { useHeaderTitle, useHeaderActions } from "./HeaderActions";
8
4
  import { AgentToggleButton } from "@agent-native/core/client";
9
5
  import { RunsTray } from "@agent-native/core/client/progress";
@@ -54,7 +50,6 @@ export function Header() {
54
50
  </div>
55
51
  <div className="flex items-center gap-2 shrink-0">
56
52
  {actions}
57
- <LanguagePicker variant="icon" />
58
53
  <RunsTray pollMs={1500} />
59
54
  <AgentToggleButton />
60
55
  </div>
@@ -1,10 +1,6 @@
1
1
  import { useLocation } from "react-router";
2
2
  import { useHeaderTitle, useHeaderActions } from "./HeaderActions";
3
- import {
4
- AgentToggleButton,
5
- LanguagePicker,
6
- useT,
7
- } from "@agent-native/core/client";
3
+ import { AgentToggleButton, useT } from "@agent-native/core/client";
8
4
 
9
5
  const pageTitles: Record<string, string> = {
10
6
  "/": "header.forms",
@@ -42,7 +38,6 @@ export function Header() {
42
38
  </div>
43
39
  <div className="flex items-center gap-2 shrink-0">
44
40
  {actions}
45
- <LanguagePicker variant="icon" />
46
41
  <AgentToggleButton />
47
42
  </div>
48
43
  </header>
@@ -1,10 +1,6 @@
1
1
  import { useLocation } from "react-router";
2
2
  import { IconMenu2 } from "@tabler/icons-react";
3
- import {
4
- AgentToggleButton,
5
- LanguagePicker,
6
- useT,
7
- } from "@agent-native/core/client";
3
+ import { AgentToggleButton, useT } from "@agent-native/core/client";
8
4
  import { useHeaderTitle, useHeaderActions } from "./HeaderActions";
9
5
 
10
6
  const pageTitles: Record<string, string> = {
@@ -49,7 +45,6 @@ export function Header({ onOpenSidebar }: HeaderProps) {
49
45
  </div>
50
46
  <div className="flex shrink-0 items-center gap-2">
51
47
  {actions}
52
- <LanguagePicker variant="icon" />
53
48
  <AgentToggleButton />
54
49
  </div>
55
50
  </header>
@@ -7,6 +7,7 @@ import {
7
7
  SelectTrigger,
8
8
  SelectValue,
9
9
  } from "@/components/ui/select";
10
+ import { useT } from "@agent-native/core/client";
10
11
 
11
12
  const LANGUAGES = [
12
13
  { value: "", label: "Plain text" },
@@ -34,6 +35,7 @@ interface CodeBlockLangPickerProps {
34
35
  }
35
36
 
36
37
  export function CodeBlockLangPicker({ editor }: CodeBlockLangPickerProps) {
38
+ const t = useT();
37
39
  const [position, setPosition] = useState<{
38
40
  top: number;
39
41
  right: number;
@@ -122,12 +124,12 @@ export function CodeBlockLangPicker({ editor }: CodeBlockLangPickerProps) {
122
124
  className="code-lang-select h-7 w-auto min-w-[100px] text-xs"
123
125
  onMouseDown={(e) => e.stopPropagation()}
124
126
  >
125
- <SelectValue placeholder="Plain text" />
127
+ <SelectValue placeholder={t("mail.compose.plainText")} />
126
128
  </SelectTrigger>
127
129
  <SelectContent>
128
130
  {LANGUAGES.map((l) => (
129
131
  <SelectItem key={l.value || "__plain"} value={l.value || "__plain"}>
130
- {l.label}
132
+ {l.value ? l.label : t("mail.compose.plainText")}
131
133
  </SelectItem>
132
134
  ))}
133
135
  </SelectContent>