@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.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +39 -0
- package/corpus/core/docs/content/locales/ar-SA/actions.md +7 -7
- package/corpus/core/docs/content/locales/ar-SA/template-plan.md +6 -4
- package/corpus/core/docs/content/locales/de-DE/actions.md +9 -9
- package/corpus/core/docs/content/locales/de-DE/template-plan.md +6 -4
- package/corpus/core/docs/content/locales/es-ES/actions.md +9 -9
- package/corpus/core/docs/content/locales/es-ES/template-plan.md +6 -4
- package/corpus/core/docs/content/locales/fr-FR/actions.md +9 -9
- package/corpus/core/docs/content/locales/fr-FR/template-plan.md +6 -4
- package/corpus/core/docs/content/locales/hi-IN/actions.md +9 -9
- package/corpus/core/docs/content/locales/hi-IN/template-plan.md +4 -4
- package/corpus/core/docs/content/locales/ja-JP/actions.md +9 -9
- package/corpus/core/docs/content/locales/ja-JP/template-plan.md +4 -4
- package/corpus/core/docs/content/locales/ko-KR/actions.md +9 -9
- package/corpus/core/docs/content/locales/ko-KR/template-plan.md +4 -4
- package/corpus/core/docs/content/locales/pt-BR/actions.md +9 -9
- package/corpus/core/docs/content/locales/pt-BR/template-plan.md +6 -4
- package/corpus/core/docs/content/locales/zh-CN/actions.md +9 -9
- package/corpus/core/docs/content/locales/zh-CN/template-plan.md +4 -4
- package/corpus/core/package.json +1 -1
- package/corpus/core/scripts/generate-og-font-data.mjs +9 -5
- package/corpus/core/src/client/AgentPanel.tsx +70 -1
- package/corpus/core/src/client/AssistantChat.tsx +1 -3
- package/corpus/core/src/client/ErrorBoundary.tsx +151 -10
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +0 -62
- package/corpus/core/src/client/composer/TiptapComposer.tsx +6 -13
- package/corpus/core/src/server/og-fonts-data.ts +7 -4
- package/corpus/core/src/server/og-fonts.ts +10 -3
- package/corpus/core/src/server/social-og-image.ts +45 -6
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +199 -19
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +51 -31
- package/corpus/templates/analytics/app/components/layout/DashboardHeader.tsx +26 -16
- package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -2
- package/corpus/templates/analytics/app/components/layout/HeaderActions.tsx +8 -1
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +2 -5
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +172 -107
- package/corpus/templates/analytics/app/i18n-data.ts +1076 -5
- package/corpus/templates/analytics/app/pages/Settings.tsx +2 -2
- package/corpus/templates/analytics/app/pages/adhoc/AdhocRouter.tsx +1 -21
- package/corpus/templates/analytics/app/pages/adhoc/DashboardSkeleton.tsx +35 -0
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -23
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +3 -26
- package/corpus/templates/analytics/changelog/2026-06-24-analytics-navigation-command-palette-and-settings-now-honor-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-daily-dashboard-charts-now-use-local-day-buckets-and-show-th.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-dashboard-loading-placeholders-now-span-the-available-page-w.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-first-party-dashboard-dates-now-align-to-pacific-time-for-da.md +6 -0
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +19 -7
- package/corpus/templates/assets/app/components/layout/Header.tsx +0 -2
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +0 -2
- package/corpus/templates/calendar/app/pages/CalendarView.tsx +0 -2
- package/corpus/templates/chat/app/components/layout/Header.tsx +1 -6
- package/corpus/templates/clips/app/components/layout/Header.tsx +1 -6
- package/corpus/templates/clips/app/hooks/use-library.ts +2 -0
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +3 -1
- package/corpus/templates/clips/changelog/2026-06-24-archive-and-spaces-navigation-is-more-resilient-when-sidebar.md +6 -0
- package/corpus/templates/content/app/components/layout/Header.tsx +0 -2
- package/corpus/templates/design/app/components/layout/Header.tsx +1 -6
- package/corpus/templates/forms/app/components/layout/Header.tsx +1 -6
- package/corpus/templates/macros/app/components/layout/Header.tsx +1 -6
- package/corpus/templates/mail/app/components/email/CodeBlockLangPicker.tsx +4 -2
- package/corpus/templates/mail/app/components/email/ComposeBubbleToolbar.tsx +18 -12
- package/corpus/templates/mail/app/components/email/ComposeEditor.tsx +9 -5
- package/corpus/templates/mail/app/components/email/ComposeModal.tsx +36 -19
- package/corpus/templates/mail/app/components/email/EmailList.tsx +59 -55
- package/corpus/templates/mail/app/components/email/EmailListItem.tsx +7 -3
- package/corpus/templates/mail/app/components/email/EmailThread.tsx +25 -16
- package/corpus/templates/mail/app/components/email/InlineReplyComposer.tsx +25 -19
- package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +32 -17
- package/corpus/templates/mail/app/components/email/RecipientInput.tsx +26 -10
- package/corpus/templates/mail/app/components/email/SendLaterButton.tsx +5 -3
- package/corpus/templates/mail/app/components/email/SnoozeModal.tsx +4 -2
- package/corpus/templates/mail/app/components/email/SnoozePopover.tsx +9 -5
- package/corpus/templates/mail/app/components/email/extensions/ComposeImageBlock.tsx +4 -2
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +168 -86
- package/corpus/templates/mail/app/components/layout/SearchBar.tsx +4 -2
- package/corpus/templates/mail/app/i18n/ar-SA.ts +212 -0
- package/corpus/templates/mail/app/i18n/de-DE.ts +212 -0
- package/corpus/templates/mail/app/i18n/en-US.ts +212 -0
- package/corpus/templates/mail/app/i18n/es-ES.ts +212 -0
- package/corpus/templates/mail/app/i18n/fr-FR.ts +212 -0
- package/corpus/templates/mail/app/i18n/hi-IN.ts +212 -0
- package/corpus/templates/mail/app/i18n/ja-JP.ts +212 -0
- package/corpus/templates/mail/app/i18n/ko-KR.ts +212 -0
- package/corpus/templates/mail/app/i18n/pt-BR.ts +212 -0
- package/corpus/templates/mail/app/i18n/zh-CN.ts +211 -0
- package/corpus/templates/mail/changelog/2026-06-24-interface-language-support-now-covers-more-mail-controls-and.md +6 -0
- package/corpus/templates/plan/app/components/layout/Header.tsx +1 -6
- package/corpus/templates/slides/app/components/layout/Header.tsx +1 -6
- package/corpus/templates/videos/app/components/layout/Header.tsx +1 -6
- package/dist/client/AgentPanel.d.ts +5 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +23 -4
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +1 -3
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/ErrorBoundary.d.ts.map +1 -1
- package/dist/client/ErrorBoundary.js +128 -7
- package/dist/client/ErrorBoundary.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +1 -17
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +4 -0
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +5 -9
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/server/og-fonts-data.d.ts +1 -0
- package/dist/server/og-fonts-data.d.ts.map +1 -1
- package/dist/server/og-fonts-data.js +5 -4
- package/dist/server/og-fonts-data.js.map +1 -1
- package/dist/server/og-fonts.d.ts +1 -0
- package/dist/server/og-fonts.d.ts.map +1 -1
- package/dist/server/og-fonts.js +10 -4
- package/dist/server/og-fonts.js.map +1 -1
- package/dist/server/social-og-image.d.ts.map +1 -1
- package/dist/server/social-og-image.js +33 -6
- package/dist/server/social-og-image.js.map +1 -1
- package/docs/content/locales/ar-SA/actions.md +7 -7
- package/docs/content/locales/ar-SA/template-plan.md +6 -4
- package/docs/content/locales/de-DE/actions.md +9 -9
- package/docs/content/locales/de-DE/template-plan.md +6 -4
- package/docs/content/locales/es-ES/actions.md +9 -9
- package/docs/content/locales/es-ES/template-plan.md +6 -4
- package/docs/content/locales/fr-FR/actions.md +9 -9
- package/docs/content/locales/fr-FR/template-plan.md +6 -4
- package/docs/content/locales/hi-IN/actions.md +9 -9
- package/docs/content/locales/hi-IN/template-plan.md +4 -4
- package/docs/content/locales/ja-JP/actions.md +9 -9
- package/docs/content/locales/ja-JP/template-plan.md +4 -4
- package/docs/content/locales/ko-KR/actions.md +9 -9
- package/docs/content/locales/ko-KR/template-plan.md +4 -4
- package/docs/content/locales/pt-BR/actions.md +9 -9
- package/docs/content/locales/pt-BR/template-plan.md +6 -4
- package/docs/content/locales/zh-CN/actions.md +9 -9
- package/docs/content/locales/zh-CN/template-plan.md +4 -4
- 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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 />;
|
|
@@ -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
|
|
102
|
-
|
|
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 <=
|
|
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 <=
|
|
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 ${
|
|
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
|
-
|
|
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
|
-
|
|
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>
|
|
@@ -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="
|
|
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>
|
|
@@ -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="
|
|
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>
|