@agent-native/core 0.141.5 → 0.141.7
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/templates/analytics/.agents/skills/dashboard-management/SKILL.md +3 -14
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +20 -8
- package/corpus/templates/analytics/.agents/skills/prometheus/SKILL.md +5 -5
- package/corpus/templates/analytics/AGENTS.md +2 -2
- package/corpus/templates/analytics/actions/compose-dashboard.ts +1 -1
- package/corpus/templates/analytics/actions/get-first-party-analytics-health.ts +15 -1
- package/corpus/templates/analytics/actions/migrate-first-party-analytics-to-bigquery.ts +135 -0
- package/corpus/templates/analytics/actions/navigate.ts +1 -1
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +2 -2
- package/corpus/templates/analytics/actions/update-dashboard.ts +0 -1
- package/corpus/templates/analytics/actions/view-screen.ts +0 -20
- package/corpus/templates/analytics/app/components/layout/Header.tsx +0 -1
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +5 -5
- package/corpus/templates/analytics/app/i18n-data.ts +330 -90
- package/corpus/templates/analytics/app/pages/Agents.tsx +0 -3
- package/corpus/templates/analytics/app/pages/DataSources.tsx +66 -30
- package/corpus/templates/analytics/app/pages/Settings.tsx +22 -43
- package/corpus/templates/analytics/app/pages/settings/settings-search.ts +23 -20
- package/corpus/templates/analytics/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/analytics/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/analytics/app/routes/team.tsx +1 -1
- package/corpus/templates/analytics/changelog/2026-08-05-historical-analytics-rollups-now-repair-automatically-after-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-05-settings-no-longer-includes-an-unnecessary-about-section.md +6 -0
- package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +1 -1
- package/corpus/templates/analytics/netlify.toml +4 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +109 -0
- package/corpus/templates/analytics/scripts/first-party-analytics-bigquery.sql +104 -0
- package/corpus/templates/analytics/server/jobs/analytics-rollup-backfill.ts +342 -0
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +0 -2
- package/corpus/templates/analytics/server/lib/analytics-rollup-lock.ts +8 -0
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +11 -29
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +55 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +1058 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-health.ts +151 -46
- package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +15 -9
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +59 -17
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +1 -3
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +2 -4
- package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +61 -0
- package/corpus/templates/analytics/server/plugins/db.ts +58 -187
- package/corpus/templates/analytics/server/routes/api/analytics-rollups/backfill.post.ts +53 -0
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +8 -6
- package/corpus/templates/assets/.agents/skills/library-management/SKILL.md +16 -1
- package/corpus/templates/assets/AGENTS.md +1 -0
- package/corpus/templates/assets/actions/_helpers.ts +12 -0
- package/corpus/templates/assets/actions/generate-image.ts +9 -3
- package/corpus/templates/assets/actions/import-style-from-url.ts +115 -0
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +3 -1
- package/corpus/templates/assets/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/assets/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/assets/app/routes/settings.tsx +5 -0
- package/corpus/templates/assets/app/routes/team.tsx +1 -1
- package/corpus/templates/assets/changelog/2026-08-05-brand-kits-can-import-a-website-s-hydrated-visual-language-a.md +6 -0
- package/corpus/templates/assets/changelog/2026-08-05-generated-images-now-hand-off-embeddable-previews-to-other-w.md +6 -0
- package/corpus/templates/assets/server/lib/generation.ts +58 -0
- package/corpus/templates/assets/shared/api.ts +12 -0
- package/corpus/templates/brain/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/brain/app/routes/team.tsx +1 -1
- package/corpus/templates/brain/app/routes.ts +1 -1
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +3 -1
- package/corpus/templates/calendar/app/routes/_app.extensions._index.tsx +1 -1
- package/corpus/templates/calendar/app/routes/_app.settings.$.tsx +1 -0
- package/corpus/templates/calendar/app/routes/_app.team.tsx +1 -1
- package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/chat/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/chat/app/root.tsx +1 -1
- package/corpus/templates/chat/app/routes/agent.tsx +7 -7
- package/corpus/templates/chat/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/chat/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/chat/app/routes/team.tsx +1 -1
- package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +1 -1
- package/corpus/templates/clips/app/components/recorder/storage-setup-card.tsx +1 -1
- package/corpus/templates/clips/app/routes/_app.extensions._index.tsx +1 -1
- package/corpus/templates/clips/app/routes/_app.settings.$.tsx +1 -0
- package/corpus/templates/clips/changelog/2026-08-05-clips-overlays-now-use-clean-surfaces-without-clipped-shadow.md +6 -0
- package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +2 -2
- package/corpus/templates/clips/desktop/src/styles.css +3 -54
- package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +3 -3
- package/corpus/templates/content/app/routes/_app.extensions._index.tsx +1 -1
- package/corpus/templates/content/app/routes/_app.settings.$.tsx +1 -0
- package/corpus/templates/content/app/routes/_app.team.tsx +1 -1
- package/corpus/templates/content/e2e/global-setup.ts +1 -1
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +6 -1
- package/corpus/templates/design/actions/analyze-brand-assets.ts +7 -7
- package/corpus/templates/design/actions/get-design-system.ts +3 -1
- package/corpus/templates/design/actions/import-from-url.ts +6 -5
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +2 -2
- package/corpus/templates/design/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/design/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/design/app/routes/team.tsx +1 -1
- package/corpus/templates/design/changelog/2026-08-05-missing-design-systems-now-return-a-clear-not-found-response.md +6 -0
- package/corpus/templates/design/changelog/2026-08-05-website-url-imports-now-capture-hydrated-browser-computed-de.md +6 -0
- package/corpus/templates/design/e2e/global-setup.ts +1 -1
- package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/dispatch/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/team.tsx +1 -1
- package/corpus/templates/factory/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/factory/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/factory/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/factory/app/routes/team.tsx +1 -1
- package/corpus/templates/forms/app/routes/_app.extensions._index.tsx +1 -1
- package/corpus/templates/forms/app/routes/_app.settings.$.tsx +1 -0
- package/corpus/templates/forms/app/routes/_app.team.tsx +1 -1
- package/corpus/templates/forms/shared/navigation.ts +1 -1
- package/corpus/templates/macros/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/macros/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/macros/app/routes/team.tsx +1 -1
- package/corpus/templates/mail/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/mail/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/plan/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/plan/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/plan/app/routes/team.tsx +1 -1
- package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +3 -1
- package/corpus/templates/slides/actions/analyze-brand-assets.ts +7 -7
- package/corpus/templates/slides/actions/import-from-url.ts +6 -6
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +2 -2
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +3 -0
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1 -1
- package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +9 -3
- package/corpus/templates/slides/app/context/DeckContext.tsx +71 -20
- package/corpus/templates/slides/app/global.css +6 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +5 -5
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +9 -5
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +17 -0
- package/corpus/templates/slides/app/pages/Index.tsx +16 -5
- package/corpus/templates/slides/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/slides/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/slides/app/routes/team.tsx +1 -1
- package/corpus/templates/slides/changelog/2026-08-05-failed-deck-creation-and-reference-uploads-now-recover-clean.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-05-new-presentation-prompts-now-clearly-describe-presentation-g.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-05-slides-recover-completed-generation-results-after-a-sync-hic.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-05-website-url-imports-now-capture-hydrated-browser-computed-st.md +6 -0
- package/corpus/templates/tasks/app/components/layout/Header.tsx +3 -1
- package/corpus/templates/tasks/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/tasks/app/routes/settings.$.tsx +1 -0
- package/dist/agent/engine/ai-sdk-engine.js +49 -3
- package/dist/agent/production-agent.d.ts +1 -0
- package/dist/agent/production-agent.js +8 -0
- package/dist/agent/types.d.ts +7 -0
- package/dist/client/AssistantChat.js +1 -1
- package/dist/client/agent-chat-adapter.d.ts +1 -1
- package/dist/client/agent-chat-adapter.js +30 -3
- package/dist/client/agent-page/AgentWorkspaceContent.d.ts +1 -1
- package/dist/client/agent-page/AgentWorkspaceContent.js +13 -13
- package/dist/client/chat/run-recovery.d.ts +2 -1
- package/dist/client/chat/run-recovery.js +14 -3
- package/dist/client/embed-auth.js +6 -2
- package/dist/client/error-format.d.ts +1 -0
- package/dist/client/error-format.js +16 -2
- package/dist/client/integrations/IntegrationsPanel.js +40 -6
- package/dist/client/org/OrgSwitcher.js +2 -2
- package/dist/client/org/TeamPage.js +92 -72
- package/dist/client/require-session.d.ts +1 -1
- package/dist/client/require-session.js +3 -3
- package/dist/client/resources/use-mcp-servers.d.ts +5 -0
- package/dist/client/resources/use-mcp-servers.js +36 -0
- package/dist/client/settings/AccountSettingsCard.js +40 -35
- package/dist/client/settings/AutomationsSection.js +1 -1
- package/dist/client/settings/DemoModeSection.d.ts +3 -1
- package/dist/client/settings/DemoModeSection.js +4 -1
- package/dist/client/settings/ExtensionsSettingsContent.js +1 -1
- package/dist/client/settings/SchedulingTimezoneField.d.ts +3 -1
- package/dist/client/settings/SchedulingTimezoneField.js +9 -5
- package/dist/client/settings/SettingsPanel.d.ts +4 -1
- package/dist/client/settings/SettingsPanel.js +21 -21
- package/dist/client/settings/SettingsTabsPage.d.ts +2 -2
- package/dist/client/settings/SettingsTabsPage.js +98 -45
- package/dist/client/settings/VoiceTranscriptionSection.js +6 -1
- package/dist/client/settings/useSettingsPanelController.js +47 -8
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/ingestion/website.d.ts +30 -0
- package/dist/localization/default-messages.d.ts +5 -0
- package/dist/localization/default-messages.js +5 -0
- package/dist/mcp-client/oauth-routes.js +1 -1
- package/dist/mcp-client/routes.d.ts +1 -0
- package/dist/mcp-client/routes.js +49 -0
- package/dist/navigation/index.js +16 -5
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +13 -13
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/scripts/call-agent.js +11 -0
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.js +9 -7
- package/dist/server/identity-sso.js +2 -1
- package/dist/server/onboarding-html.js +57 -34
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/server/workspace-provider-oauth.js +1 -1
- package/dist/setup-connections/onboarding.js +1 -1
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/shared/sign-in-journey.d.ts +5 -2
- package/dist/shared/sign-in-journey.js +10 -4
- package/dist/templates/chat/app/components/layout/Layout.tsx +1 -1
- package/dist/templates/chat/app/hooks/use-navigation-state.ts +1 -1
- package/dist/templates/chat/app/root.tsx +1 -1
- package/dist/templates/chat/app/routes/agent.tsx +7 -7
- package/dist/templates/chat/app/routes/extensions._index.tsx +1 -1
- package/dist/templates/chat/app/routes/settings.$.tsx +1 -0
- package/dist/templates/chat/app/routes/team.tsx +1 -1
- package/dist/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +37 -6
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +4 -2
- package/docs/content/authentication.mdx +4 -5
- package/docs/content/template-analytics-developers.mdx +1 -1
- package/docs/content/template-calendar-developers.mdx +1 -1
- package/docs/content/template-chat-developers.mdx +2 -2
- package/docs/content/template-content-developers.mdx +1 -1
- package/docs/content/template-mail-developers.mdx +1 -1
- package/docs/content/template-plan-developers.mdx +1 -1
- package/docs/content/toolkit-command-navigation.mdx +6 -6
- package/docs/content/toolkit-org-team.mdx +1 -1
- package/docs/content/toolkit-settings.mdx +8 -8
- package/docs/content/toolkit-setup-connections.mdx +1 -1
- package/package.json +1 -1
- package/src/templates/chat/app/components/layout/Layout.tsx +1 -1
- package/src/templates/chat/app/hooks/use-navigation-state.ts +1 -1
- package/src/templates/chat/app/root.tsx +1 -1
- package/src/templates/chat/app/routes/agent.tsx +7 -7
- package/src/templates/chat/app/routes/extensions._index.tsx +1 -1
- package/src/templates/chat/app/routes/settings.$.tsx +1 -0
- package/src/templates/chat/app/routes/team.tsx +1 -1
- package/src/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +37 -6
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +4 -2
- package/corpus/templates/analytics/.agents/skills/dashboard-management/references/template-catalog-and-demo.md +0 -62
- package/corpus/templates/analytics/actions/install-dashboard-template.ts +0 -369
- package/corpus/templates/analytics/actions/list-dashboard-templates.ts +0 -47
- package/corpus/templates/analytics/actions/list-native-v2-dashboard-templates.ts +0 -34
- package/corpus/templates/analytics/app/routes/catalog.tsx +0 -240
- package/corpus/templates/analytics/changelog/2026-08-05-historical-analytics-rollups-stay-complete-and-atomic.md +0 -6
- package/corpus/templates/analytics/changelog/2026-08-05-historical-rollups-stay-complete-while-live-events-arrive.md +0 -6
- package/src/templates/default/actions/navigate.spec.ts +0 -53
|
@@ -489,9 +489,6 @@ export default function AgentsPage() {
|
|
|
489
489
|
</p>
|
|
490
490
|
</div>
|
|
491
491
|
<div className="flex shrink-0 items-center gap-2">
|
|
492
|
-
<Button variant="outline" size="sm" asChild>
|
|
493
|
-
<Link to="/catalog">{t("agents.openCatalog")}</Link>
|
|
494
|
-
</Button>
|
|
495
492
|
{canManageOrg ? (
|
|
496
493
|
<DropdownMenu>
|
|
497
494
|
<DropdownMenuTrigger asChild>
|
|
@@ -120,11 +120,19 @@ interface GitHubOAuthStatus {
|
|
|
120
120
|
|
|
121
121
|
interface FirstPartyAnalyticsHealthResponse {
|
|
122
122
|
status: "healthy" | "monitor" | "recommend_bigquery" | "unavailable";
|
|
123
|
+
externalBackendRecommendation?: "none" | "connect" | "use" | "unknown";
|
|
123
124
|
metrics: {
|
|
124
125
|
eventCount: number;
|
|
125
126
|
slowQueryCount24h: number;
|
|
126
127
|
maxQueryDurationMs24h: number;
|
|
127
128
|
};
|
|
129
|
+
externalBackends?: Array<{
|
|
130
|
+
id: "bigquery" | "amplitude";
|
|
131
|
+
label: string;
|
|
132
|
+
role: "warehouse" | "product-analytics";
|
|
133
|
+
configured: boolean | null;
|
|
134
|
+
setupLink: string;
|
|
135
|
+
}>;
|
|
128
136
|
bigQuery: {
|
|
129
137
|
configured: boolean | null;
|
|
130
138
|
};
|
|
@@ -1615,23 +1623,25 @@ function FirstPartyAnalyticsCard() {
|
|
|
1615
1623
|
});
|
|
1616
1624
|
const health = rawHealth as FirstPartyAnalyticsHealthResponse | undefined;
|
|
1617
1625
|
const healthStatus = isHealthError ? "unavailable" : health?.status;
|
|
1618
|
-
const
|
|
1619
|
-
const
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1626
|
+
const externalBackends = health?.externalBackends ?? [];
|
|
1627
|
+
const externalBackendConfigured = externalBackends.some(
|
|
1628
|
+
(backend) => backend.configured === true,
|
|
1629
|
+
);
|
|
1630
|
+
const recommendsExternalBackend = healthStatus === "recommend_bigquery";
|
|
1631
|
+
const healthTitleKey = recommendsExternalBackend
|
|
1632
|
+
? externalBackendConfigured
|
|
1633
|
+
? "analyticsBackend.connectedTitle"
|
|
1634
|
+
: "analyticsBackend.recommendationTitle"
|
|
1635
|
+
: null;
|
|
1636
|
+
const healthDescriptionKey = recommendsExternalBackend
|
|
1637
|
+
? externalBackendConfigured
|
|
1638
|
+
? "analyticsBackend.connectedDescription"
|
|
1639
|
+
: "analyticsBackend.recommendationDescription"
|
|
1640
|
+
: healthStatus === "monitor"
|
|
1641
|
+
? "analyticsBackend.monitorDescription"
|
|
1642
|
+
: healthStatus === "healthy"
|
|
1643
|
+
? "analyticsBackend.healthyDescription"
|
|
1644
|
+
: "analyticsBackend.unavailableDescription";
|
|
1635
1645
|
|
|
1636
1646
|
const createKey = useActionMutation("create-analytics-public-key", {
|
|
1637
1647
|
onSuccess: (result: any) => {
|
|
@@ -1681,7 +1691,7 @@ function FirstPartyAnalyticsCard() {
|
|
|
1681
1691
|
<div className="flex shrink-0 items-center gap-2">
|
|
1682
1692
|
{isLoading ? (
|
|
1683
1693
|
<Skeleton className="h-4 w-20 rounded-full" />
|
|
1684
|
-
) :
|
|
1694
|
+
) : recommendsExternalBackend ? (
|
|
1685
1695
|
<span
|
|
1686
1696
|
className="flex min-w-0 items-center gap-1.5 text-xs font-medium text-amber-500"
|
|
1687
1697
|
title={healthTitleKey ? t(healthTitleKey) : undefined}
|
|
@@ -1690,13 +1700,13 @@ function FirstPartyAnalyticsCard() {
|
|
|
1690
1700
|
<span className="max-w-[12rem] truncate">
|
|
1691
1701
|
{healthTitleKey
|
|
1692
1702
|
? t(healthTitleKey)
|
|
1693
|
-
: t("
|
|
1703
|
+
: t("analyticsBackend.recommendationTitle")}
|
|
1694
1704
|
</span>
|
|
1695
1705
|
</span>
|
|
1696
1706
|
) : connected ? (
|
|
1697
1707
|
<span className="flex items-center gap-1.5 text-xs text-emerald-500 font-medium whitespace-nowrap">
|
|
1698
1708
|
<IconCheck className="h-3.5 w-3.5" />
|
|
1699
|
-
{t("
|
|
1709
|
+
{t("analyticsBackend.configured")}
|
|
1700
1710
|
</span>
|
|
1701
1711
|
) : (
|
|
1702
1712
|
<span className="flex items-center gap-1.5 text-xs text-muted-foreground whitespace-nowrap">
|
|
@@ -1722,7 +1732,7 @@ function FirstPartyAnalyticsCard() {
|
|
|
1722
1732
|
) : (
|
|
1723
1733
|
<div
|
|
1724
1734
|
className={`rounded-md border p-3 text-xs ${
|
|
1725
|
-
|
|
1735
|
+
recommendsExternalBackend
|
|
1726
1736
|
? "border-amber-500/30 bg-amber-500/10"
|
|
1727
1737
|
: "border-border/50 bg-muted/20"
|
|
1728
1738
|
}`}
|
|
@@ -1731,7 +1741,7 @@ function FirstPartyAnalyticsCard() {
|
|
|
1731
1741
|
<div className="flex min-w-0 items-start gap-2">
|
|
1732
1742
|
<IconAlertCircle
|
|
1733
1743
|
className={`mt-px h-3.5 w-3.5 shrink-0 ${
|
|
1734
|
-
|
|
1744
|
+
recommendsExternalBackend
|
|
1735
1745
|
? "text-amber-500"
|
|
1736
1746
|
: "text-muted-foreground"
|
|
1737
1747
|
}`}
|
|
@@ -1747,15 +1757,41 @@ function FirstPartyAnalyticsCard() {
|
|
|
1747
1757
|
</p>
|
|
1748
1758
|
</div>
|
|
1749
1759
|
</div>
|
|
1750
|
-
{healthStatus === "recommend_bigquery" &&
|
|
1751
|
-
!bigQueryConfigured ? (
|
|
1752
|
-
<Button asChild size="sm" className="shrink-0 text-xs">
|
|
1753
|
-
<Link to="/data-sources?source=bigquery">
|
|
1754
|
-
{t("dataSources.bigQuerySetup")}
|
|
1755
|
-
</Link>
|
|
1756
|
-
</Button>
|
|
1757
|
-
) : null}
|
|
1758
1760
|
</div>
|
|
1761
|
+
{externalBackends.length > 0 && (
|
|
1762
|
+
<div className="mt-3 border-t border-border/30 pt-3">
|
|
1763
|
+
<div className="mb-2 text-muted-foreground">
|
|
1764
|
+
{t("analyticsBackend.options")}
|
|
1765
|
+
</div>
|
|
1766
|
+
<div className="flex flex-wrap gap-2">
|
|
1767
|
+
{externalBackends.map((backend) => {
|
|
1768
|
+
const statusLabel =
|
|
1769
|
+
backend.configured === true
|
|
1770
|
+
? t("analyticsBackend.configured")
|
|
1771
|
+
: backend.configured === false
|
|
1772
|
+
? t("analyticsBackend.setUp")
|
|
1773
|
+
: t("dataSources.statusUnknown");
|
|
1774
|
+
return (
|
|
1775
|
+
<Button
|
|
1776
|
+
asChild
|
|
1777
|
+
key={backend.id}
|
|
1778
|
+
size="sm"
|
|
1779
|
+
variant={
|
|
1780
|
+
backend.configured === true
|
|
1781
|
+
? "outline"
|
|
1782
|
+
: "default"
|
|
1783
|
+
}
|
|
1784
|
+
className="text-xs"
|
|
1785
|
+
>
|
|
1786
|
+
<Link to={backend.setupLink}>
|
|
1787
|
+
{backend.label} · {statusLabel}
|
|
1788
|
+
</Link>
|
|
1789
|
+
</Button>
|
|
1790
|
+
);
|
|
1791
|
+
})}
|
|
1792
|
+
</div>
|
|
1793
|
+
</div>
|
|
1794
|
+
)}
|
|
1759
1795
|
{health && healthStatus !== "unavailable" && (
|
|
1760
1796
|
<div className="mt-3 grid grid-cols-3 gap-2 border-t border-border/30 pt-3">
|
|
1761
1797
|
<div>
|
|
@@ -41,7 +41,6 @@ import { buildAnalyticsGeneralSettingsSearchEntries } from "./settings/settings-
|
|
|
41
41
|
|
|
42
42
|
export default function Settings() {
|
|
43
43
|
const t = useT();
|
|
44
|
-
const agentSettingsTabs = useAgentSettingsTabs();
|
|
45
44
|
const replayStorageStatus = useReplayStorageStatus();
|
|
46
45
|
const { data: analyticsPrefs, isLoading: analyticsPrefsLoading } =
|
|
47
46
|
useActionQuery<AnalyticsUserPrefs>("get-user-pref", {
|
|
@@ -122,6 +121,23 @@ export default function Settings() {
|
|
|
122
121
|
});
|
|
123
122
|
};
|
|
124
123
|
|
|
124
|
+
const agentAdditionalContent = (
|
|
125
|
+
<SettingsRow
|
|
126
|
+
id="bell-sound"
|
|
127
|
+
label={t("settings.bellSound")}
|
|
128
|
+
description={t("settings.bellSoundDescription")}
|
|
129
|
+
control={
|
|
130
|
+
<Switch
|
|
131
|
+
aria-label={t("settings.bellSound")}
|
|
132
|
+
checked={bellSoundEnabled}
|
|
133
|
+
disabled={analyticsPrefsLoading || saveAnalyticsPrefs.isPending}
|
|
134
|
+
onCheckedChange={saveBellSoundPreference}
|
|
135
|
+
/>
|
|
136
|
+
}
|
|
137
|
+
/>
|
|
138
|
+
);
|
|
139
|
+
const agentSettingsTabs = useAgentSettingsTabs({ agentAdditionalContent });
|
|
140
|
+
|
|
125
141
|
const extraTabs = useMemo<SettingsTabItem[]>(
|
|
126
142
|
() => [
|
|
127
143
|
{
|
|
@@ -130,7 +146,7 @@ export default function Settings() {
|
|
|
130
146
|
icon: IconBell,
|
|
131
147
|
keywords: "alerts rules notifications thresholds triggers monitoring",
|
|
132
148
|
content: (
|
|
133
|
-
<div className="
|
|
149
|
+
<div className="w-full">
|
|
134
150
|
<AlertRulesSettingsCard />
|
|
135
151
|
</div>
|
|
136
152
|
),
|
|
@@ -157,7 +173,7 @@ export default function Settings() {
|
|
|
157
173
|
extraTabs={extraTabs}
|
|
158
174
|
generalSearchEntries={generalSearchEntries}
|
|
159
175
|
general={
|
|
160
|
-
<div className="
|
|
176
|
+
<div className="w-full space-y-6">
|
|
161
177
|
<SettingsGroup className="bg-card border-border/50">
|
|
162
178
|
<SettingsRow
|
|
163
179
|
id="credentials"
|
|
@@ -171,18 +187,6 @@ export default function Settings() {
|
|
|
171
187
|
</Button>
|
|
172
188
|
}
|
|
173
189
|
/>
|
|
174
|
-
<SettingsRow
|
|
175
|
-
id="dashboard-templates"
|
|
176
|
-
label={t("settings.dashboardTemplates")}
|
|
177
|
-
description={t("settings.dashboardTemplatesDescription")}
|
|
178
|
-
control={
|
|
179
|
-
<Button variant="outline" size="sm" asChild>
|
|
180
|
-
<Link to="/catalog">
|
|
181
|
-
{t("settings.openDashboardTemplates")}
|
|
182
|
-
</Link>
|
|
183
|
-
</Button>
|
|
184
|
-
}
|
|
185
|
-
/>
|
|
186
190
|
<SettingsRow
|
|
187
191
|
id="language"
|
|
188
192
|
label={t("settings.languageTitle")}
|
|
@@ -207,21 +211,6 @@ export default function Settings() {
|
|
|
207
211
|
/>
|
|
208
212
|
}
|
|
209
213
|
/>
|
|
210
|
-
<SettingsRow
|
|
211
|
-
id="bell-sound"
|
|
212
|
-
label={t("settings.bellSound")}
|
|
213
|
-
description={t("settings.bellSoundDescription")}
|
|
214
|
-
control={
|
|
215
|
-
<Switch
|
|
216
|
-
aria-label={t("settings.bellSound")}
|
|
217
|
-
checked={bellSoundEnabled}
|
|
218
|
-
disabled={
|
|
219
|
-
analyticsPrefsLoading || saveAnalyticsPrefs.isPending
|
|
220
|
-
}
|
|
221
|
-
onCheckedChange={saveBellSoundPreference}
|
|
222
|
-
/>
|
|
223
|
-
}
|
|
224
|
-
/>
|
|
225
214
|
</SettingsGroup>
|
|
226
215
|
|
|
227
216
|
{replayStorageStatus.data?.configured ? (
|
|
@@ -242,29 +231,19 @@ export default function Settings() {
|
|
|
242
231
|
</CardContent>
|
|
243
232
|
</Card>
|
|
244
233
|
) : null}
|
|
245
|
-
|
|
246
|
-
<Card id="about" className="bg-card border-border/50 scroll-mt-16">
|
|
247
|
-
<CardHeader>
|
|
248
|
-
<CardTitle className="text-base">{t("settings.about")}</CardTitle>
|
|
249
|
-
</CardHeader>
|
|
250
|
-
<CardContent className="space-y-2 text-sm text-muted-foreground">
|
|
251
|
-
<p>{t("settings.aboutDescription")}</p>
|
|
252
|
-
<p>{t("settings.aboutUsage")}</p>
|
|
253
|
-
</CardContent>
|
|
254
|
-
</Card>
|
|
255
234
|
</div>
|
|
256
235
|
}
|
|
257
236
|
team={
|
|
258
|
-
<div className="
|
|
237
|
+
<div className="w-full">
|
|
259
238
|
<TeamPage
|
|
260
239
|
showTitle={false}
|
|
261
240
|
createOrgDescription="Set up a team to share dashboards and data sources with your colleagues."
|
|
262
|
-
className="
|
|
241
|
+
className="w-full"
|
|
263
242
|
/>
|
|
264
243
|
</div>
|
|
265
244
|
}
|
|
266
245
|
whatsNew={
|
|
267
|
-
<div className="
|
|
246
|
+
<div className="w-full">
|
|
268
247
|
<ChangelogSettingsCard markdown={changelog} />
|
|
269
248
|
</div>
|
|
270
249
|
}
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
getAgentSettingsSearchTabs,
|
|
3
3
|
type SettingsSearchEntry,
|
|
4
4
|
} from "@agent-native/core/client/settings";
|
|
5
|
+
import { buildSettingsRoute } from "@agent-native/core/navigation";
|
|
5
6
|
|
|
6
7
|
interface SettingsCommandItem {
|
|
7
8
|
id: string;
|
|
@@ -12,6 +13,20 @@ interface SettingsCommandItem {
|
|
|
12
13
|
|
|
13
14
|
type Translate = (key: string) => string;
|
|
14
15
|
|
|
16
|
+
function buildSettingsEntryRoute(tabId: string, section?: string): string {
|
|
17
|
+
const normalizedSection = section?.replace(/^#/, "").trim();
|
|
18
|
+
if (!normalizedSection || normalizedSection === tabId) {
|
|
19
|
+
return buildSettingsRoute(tabId);
|
|
20
|
+
}
|
|
21
|
+
if (normalizedSection.startsWith("agent:")) {
|
|
22
|
+
return buildSettingsRoute(normalizedSection);
|
|
23
|
+
}
|
|
24
|
+
if (normalizedSection.startsWith(`${tabId}:`)) {
|
|
25
|
+
return buildSettingsRoute(normalizedSection);
|
|
26
|
+
}
|
|
27
|
+
return buildSettingsRoute(`${tabId}:${normalizedSection}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
15
30
|
export function buildAnalyticsGeneralSettingsSearchEntries(
|
|
16
31
|
t: Translate,
|
|
17
32
|
replayStorageConfigured: boolean,
|
|
@@ -21,6 +36,7 @@ export function buildAnalyticsGeneralSettingsSearchEntries(
|
|
|
21
36
|
id: "analytics-account",
|
|
22
37
|
label: t("settings.account"),
|
|
23
38
|
keywords: "profile photo avatar email signed in identity",
|
|
39
|
+
tabId: "account",
|
|
24
40
|
hash: "account",
|
|
25
41
|
},
|
|
26
42
|
{
|
|
@@ -29,12 +45,6 @@ export function buildAnalyticsGeneralSettingsSearchEntries(
|
|
|
29
45
|
keywords: "data sources api keys manage credentials",
|
|
30
46
|
hash: "credentials",
|
|
31
47
|
},
|
|
32
|
-
{
|
|
33
|
-
id: "analytics-dashboard-templates",
|
|
34
|
-
label: t("settings.dashboardTemplates"),
|
|
35
|
-
keywords: "templates catalog dashboards",
|
|
36
|
-
hash: "dashboard-templates",
|
|
37
|
-
},
|
|
38
48
|
...(replayStorageConfigured
|
|
39
49
|
? [
|
|
40
50
|
{
|
|
@@ -57,18 +67,6 @@ export function buildAnalyticsGeneralSettingsSearchEntries(
|
|
|
57
67
|
keywords: "email notifications errors alerts javascript monitoring",
|
|
58
68
|
hash: "error-email-notifications",
|
|
59
69
|
},
|
|
60
|
-
{
|
|
61
|
-
id: "analytics-bell-sound",
|
|
62
|
-
label: t("settings.bellSound"),
|
|
63
|
-
keywords: "sound audio ding agent completion notification",
|
|
64
|
-
hash: "bell-sound",
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
id: "analytics-about",
|
|
68
|
-
label: t("settings.about"),
|
|
69
|
-
keywords: "about version info usage",
|
|
70
|
-
hash: "about",
|
|
71
|
-
},
|
|
72
70
|
];
|
|
73
71
|
}
|
|
74
72
|
|
|
@@ -118,18 +116,23 @@ export function buildAnalyticsSettingsCommandItems(
|
|
|
118
116
|
};
|
|
119
117
|
|
|
120
118
|
for (const tab of tabs) {
|
|
119
|
+
const entryHref = (entry: SettingsSearchEntry, tabId: string) => {
|
|
120
|
+
const hash = entry.hash?.replace(/^#/, "");
|
|
121
|
+
return buildSettingsEntryRoute(tabId, hash);
|
|
122
|
+
};
|
|
121
123
|
add({
|
|
122
124
|
id: `tab:${tab.id}`,
|
|
123
125
|
label: tab.label,
|
|
124
126
|
keywords: `${tab.keywords} settings`,
|
|
125
|
-
href:
|
|
127
|
+
href: buildSettingsRoute(tab.id),
|
|
126
128
|
});
|
|
127
129
|
for (const entry of tab.searchEntries ?? []) {
|
|
130
|
+
const tabId = entry.tabId ?? tab.id;
|
|
128
131
|
add({
|
|
129
132
|
id: entry.id,
|
|
130
133
|
label: entry.label,
|
|
131
134
|
keywords: `${entry.keywords ?? ""} ${entry.description ?? ""} ${tab.label} settings`,
|
|
132
|
-
href:
|
|
135
|
+
href: entryHref(entry, tabId),
|
|
133
136
|
});
|
|
134
137
|
}
|
|
135
138
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, meta } from "./settings.js";
|
|
@@ -173,7 +173,7 @@ Agent Native observability panels belong in the canonical Agent Native dashboard
|
|
|
173
173
|
(`agent-native-templates-first-party`), including generation metrics, explicit
|
|
174
174
|
feedback sentiment, optional inferred message sentiment, and separate
|
|
175
175
|
by-main-model breakdowns. Do not publish or install a separate observability
|
|
176
|
-
dashboard
|
|
176
|
+
dashboard.
|
|
177
177
|
|
|
178
178
|
Example dashboard panel:
|
|
179
179
|
|
|
@@ -22,6 +22,10 @@ const UPTIME_SCHEDULED_NAME = "uptime-monitor-cron";
|
|
|
22
22
|
const UPTIME_WORKER_NAME = "uptime-monitor-sweep-background";
|
|
23
23
|
const UPTIME_ROUTE_PATH = "/api/uptime-monitors/run";
|
|
24
24
|
const UPTIME_SCHEDULE = "* * * * *";
|
|
25
|
+
const ROLLUP_SCHEDULED_NAME = "analytics-rollup-backfill-cron";
|
|
26
|
+
const ROLLUP_WORKER_NAME = "analytics-rollup-backfill-background";
|
|
27
|
+
const ROLLUP_ROUTE_PATH = "/api/analytics-rollups/backfill";
|
|
28
|
+
const ROLLUP_SCHEDULE = "*/15 * * * *";
|
|
25
29
|
|
|
26
30
|
function ensureDir(dir: string) {
|
|
27
31
|
mkdirSync(dir, { recursive: true });
|
|
@@ -388,6 +392,105 @@ export const config = {
|
|
|
388
392
|
writeFileSync(path.join(dest, `${UPTIME_WORKER_NAME}.mjs`), source);
|
|
389
393
|
}
|
|
390
394
|
|
|
395
|
+
function emitRollupScheduledTrigger(token: string) {
|
|
396
|
+
const dest = path.join(FUNCTIONS_DIR, ROLLUP_SCHEDULED_NAME);
|
|
397
|
+
rmSync(dest, { recursive: true, force: true });
|
|
398
|
+
ensureDir(dest);
|
|
399
|
+
|
|
400
|
+
const source = `const WORKER_PATH = "/.netlify/functions/${ROLLUP_WORKER_NAME}";
|
|
401
|
+
const CRON_TOKEN = ${JSON.stringify(token)};
|
|
402
|
+
|
|
403
|
+
function siteOrigin(request) {
|
|
404
|
+
const configured = process.env.URL || process.env.DEPLOY_URL;
|
|
405
|
+
if (configured) return configured;
|
|
406
|
+
const url = new URL(request.url);
|
|
407
|
+
return url.origin;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export default async function handler(request) {
|
|
411
|
+
const url = new URL(WORKER_PATH, siteOrigin(request));
|
|
412
|
+
const response = await fetch(url.toString(), {
|
|
413
|
+
method: "POST",
|
|
414
|
+
headers: {
|
|
415
|
+
"content-type": "application/json",
|
|
416
|
+
"x-agent-native-analytics-rollup-cron": CRON_TOKEN,
|
|
417
|
+
},
|
|
418
|
+
body: JSON.stringify({ scheduled: true }),
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
if (!response.ok && response.status !== 202) {
|
|
422
|
+
console.error(
|
|
423
|
+
"[analytics-rollup-backfill-cron] Background backfill trigger failed:",
|
|
424
|
+
response.status,
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export const config = {
|
|
430
|
+
name: "analytics rollup backfill cron trigger",
|
|
431
|
+
generator: "agent-native analytics build",
|
|
432
|
+
schedule: ${JSON.stringify(ROLLUP_SCHEDULE)},
|
|
433
|
+
};
|
|
434
|
+
`;
|
|
435
|
+
|
|
436
|
+
writeFileSync(path.join(dest, `${ROLLUP_SCHEDULED_NAME}.mjs`), source);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function emitRollupBackgroundWorker(token: string) {
|
|
440
|
+
const dest = path.join(FUNCTIONS_DIR, ROLLUP_WORKER_NAME);
|
|
441
|
+
rmSync(dest, { recursive: true, force: true });
|
|
442
|
+
cloneServerBundleForFunction(SERVER_DIR, dest);
|
|
443
|
+
rmSync(path.join(dest, "server.mjs"), { force: true });
|
|
444
|
+
|
|
445
|
+
const source = `globalThis.__AGENT_NATIVE_BACKGROUND_RUNTIME__ = true;
|
|
446
|
+
globalThis.__AGENT_NATIVE_ANALYTICS_ROLLUP_BACKFILL_SCHEDULED_RUNTIME__ = true;
|
|
447
|
+
|
|
448
|
+
const CRON_TOKEN = ${JSON.stringify(token)};
|
|
449
|
+
const ROUTE_PATH = ${JSON.stringify(ROLLUP_ROUTE_PATH)};
|
|
450
|
+
let cachedHandler;
|
|
451
|
+
|
|
452
|
+
function timingSafeEquals(a, b) {
|
|
453
|
+
if (a.length !== b.length) return false;
|
|
454
|
+
let diff = 0;
|
|
455
|
+
for (let i = 0; i < a.length; i += 1) {
|
|
456
|
+
diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
457
|
+
}
|
|
458
|
+
return diff === 0;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
export default async function handler(request, context) {
|
|
462
|
+
const token = request.headers.get("x-agent-native-analytics-rollup-cron") || "";
|
|
463
|
+
if (!timingSafeEquals(token, CRON_TOKEN)) {
|
|
464
|
+
return new Response("Unauthorized", { status: 401 });
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
cachedHandler ??= (await import("./main.mjs")).default;
|
|
468
|
+
const url = new URL(request.url);
|
|
469
|
+
url.pathname = ROUTE_PATH;
|
|
470
|
+
url.search = "";
|
|
471
|
+
|
|
472
|
+
const rewritten = new Request(url.toString(), {
|
|
473
|
+
method: "POST",
|
|
474
|
+
headers: new Headers({ "content-type": "application/json" }),
|
|
475
|
+
body: JSON.stringify({ scheduled: true }),
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
return await cachedHandler(rewritten, context);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
export const config = {
|
|
482
|
+
name: "analytics rollup backfill background sweep",
|
|
483
|
+
generator: "agent-native analytics build",
|
|
484
|
+
background: true,
|
|
485
|
+
nodeBundler: "none",
|
|
486
|
+
includedFiles: ["**"],
|
|
487
|
+
preferStatic: false,
|
|
488
|
+
};
|
|
489
|
+
`;
|
|
490
|
+
|
|
491
|
+
writeFileSync(path.join(dest, `${ROLLUP_WORKER_NAME}.mjs`), source);
|
|
492
|
+
}
|
|
493
|
+
|
|
391
494
|
function isDirectRun(): boolean {
|
|
392
495
|
const entrypoint = process.argv[1];
|
|
393
496
|
return Boolean(
|
|
@@ -407,12 +510,15 @@ function main(): void {
|
|
|
407
510
|
const token = randomBytes(32).toString("hex");
|
|
408
511
|
const alertToken = randomBytes(32).toString("hex");
|
|
409
512
|
const uptimeToken = randomBytes(32).toString("hex");
|
|
513
|
+
const rollupToken = randomBytes(32).toString("hex");
|
|
410
514
|
emitScheduledTrigger(token);
|
|
411
515
|
emitBackgroundWorker(token);
|
|
412
516
|
emitAlertScheduledTrigger(alertToken);
|
|
413
517
|
emitAlertBackgroundWorker(alertToken);
|
|
414
518
|
emitUptimeScheduledTrigger(uptimeToken);
|
|
415
519
|
emitUptimeBackgroundWorker(uptimeToken);
|
|
520
|
+
emitRollupScheduledTrigger(rollupToken);
|
|
521
|
+
emitRollupBackgroundWorker(rollupToken);
|
|
416
522
|
console.log(
|
|
417
523
|
`[dashboard-report-cron] Emitted Netlify scheduled trigger "${SCHEDULED_NAME}" (${SCHEDULE}) and background worker "${WORKER_NAME}".`,
|
|
418
524
|
);
|
|
@@ -422,6 +528,9 @@ function main(): void {
|
|
|
422
528
|
console.log(
|
|
423
529
|
`[uptime-monitor-cron] Emitted Netlify scheduled trigger "${UPTIME_SCHEDULED_NAME}" (${UPTIME_SCHEDULE}) and background worker "${UPTIME_WORKER_NAME}".`,
|
|
424
530
|
);
|
|
531
|
+
console.log(
|
|
532
|
+
`[analytics-rollup-backfill-cron] Emitted Netlify scheduled trigger "${ROLLUP_SCHEDULED_NAME}" (${ROLLUP_SCHEDULE}) and background worker "${ROLLUP_WORKER_NAME}".`,
|
|
533
|
+
);
|
|
425
534
|
}
|
|
426
535
|
|
|
427
536
|
if (isDirectRun()) {
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
-- Builder.io production first-party Analytics warehouse.
|
|
2
|
+
-- Run this once with the authenticated Builder Google Cloud account:
|
|
3
|
+
-- bq query --use_legacy_sql=false < templates/analytics/scripts/first-party-analytics-bigquery.sql
|
|
4
|
+
--
|
|
5
|
+
-- The raw table is append-only. The query view removes retry duplicates by the
|
|
6
|
+
-- stable Postgres event id, and the two aggregate views preserve the existing
|
|
7
|
+
-- dashboard SQL names without writing rollups back to Neon.
|
|
8
|
+
|
|
9
|
+
CREATE SCHEMA IF NOT EXISTS `builder-3b0a2.analytics`
|
|
10
|
+
OPTIONS (location = "US");
|
|
11
|
+
|
|
12
|
+
CREATE TABLE IF NOT EXISTS `builder-3b0a2.analytics.first_party_analytics_events_raw` (
|
|
13
|
+
id STRING NOT NULL,
|
|
14
|
+
public_key_id STRING,
|
|
15
|
+
event_name STRING NOT NULL,
|
|
16
|
+
user_id STRING,
|
|
17
|
+
anonymous_id STRING,
|
|
18
|
+
user_key STRING,
|
|
19
|
+
session_id STRING,
|
|
20
|
+
timestamp TIMESTAMP NOT NULL,
|
|
21
|
+
event_date DATE,
|
|
22
|
+
received_at TIMESTAMP NOT NULL,
|
|
23
|
+
url STRING,
|
|
24
|
+
path STRING,
|
|
25
|
+
hostname STRING,
|
|
26
|
+
referrer STRING,
|
|
27
|
+
app STRING,
|
|
28
|
+
template STRING,
|
|
29
|
+
signed_in STRING,
|
|
30
|
+
properties STRING NOT NULL,
|
|
31
|
+
context STRING NOT NULL,
|
|
32
|
+
owner_email STRING NOT NULL,
|
|
33
|
+
org_id STRING
|
|
34
|
+
)
|
|
35
|
+
PARTITION BY event_date
|
|
36
|
+
CLUSTER BY owner_email, org_id, event_name, app;
|
|
37
|
+
|
|
38
|
+
CREATE OR REPLACE VIEW `builder-3b0a2.analytics.first_party_analytics_events_raw_query` AS
|
|
39
|
+
SELECT * EXCEPT (_row_number)
|
|
40
|
+
FROM (
|
|
41
|
+
SELECT
|
|
42
|
+
raw.*,
|
|
43
|
+
ROW_NUMBER() OVER (PARTITION BY id ORDER BY received_at DESC) AS _row_number
|
|
44
|
+
FROM `builder-3b0a2.analytics.first_party_analytics_events_raw` AS raw
|
|
45
|
+
)
|
|
46
|
+
WHERE _row_number = 1;
|
|
47
|
+
|
|
48
|
+
CREATE OR REPLACE VIEW `builder-3b0a2.analytics.first_party_analytics_events_raw_daily_rollups` AS
|
|
49
|
+
WITH tenant_events AS (
|
|
50
|
+
SELECT
|
|
51
|
+
CASE
|
|
52
|
+
WHEN org_id IS NOT NULL AND org_id <> '' THEN CONCAT('org:', org_id)
|
|
53
|
+
ELSE CONCAT('user:', owner_email)
|
|
54
|
+
END AS tenant_key,
|
|
55
|
+
owner_email,
|
|
56
|
+
org_id,
|
|
57
|
+
event_date,
|
|
58
|
+
event_name,
|
|
59
|
+
COALESCE(app, '') AS app,
|
|
60
|
+
COALESCE(template, '') AS template
|
|
61
|
+
FROM `builder-3b0a2.analytics.first_party_analytics_events_raw_query`
|
|
62
|
+
WHERE event_date IS NOT NULL
|
|
63
|
+
)
|
|
64
|
+
SELECT
|
|
65
|
+
TO_HEX(SHA256(CONCAT(
|
|
66
|
+
tenant_key, '|', CAST(event_date AS STRING), '|', event_name, '|', app,
|
|
67
|
+
'|', template
|
|
68
|
+
))) AS id,
|
|
69
|
+
tenant_key,
|
|
70
|
+
ANY_VALUE(owner_email) AS owner_email,
|
|
71
|
+
ANY_VALUE(org_id) AS org_id,
|
|
72
|
+
event_date,
|
|
73
|
+
event_name,
|
|
74
|
+
app,
|
|
75
|
+
template,
|
|
76
|
+
COUNT(*) AS event_count
|
|
77
|
+
FROM tenant_events
|
|
78
|
+
GROUP BY tenant_key, event_date, event_name, app, template;
|
|
79
|
+
|
|
80
|
+
CREATE OR REPLACE VIEW `builder-3b0a2.analytics.first_party_analytics_events_raw_user_days` AS
|
|
81
|
+
WITH tenant_user_days AS (
|
|
82
|
+
SELECT
|
|
83
|
+
CASE
|
|
84
|
+
WHEN org_id IS NOT NULL AND org_id <> '' THEN CONCAT('org:', org_id)
|
|
85
|
+
ELSE CONCAT('user:', owner_email)
|
|
86
|
+
END AS tenant_key,
|
|
87
|
+
owner_email,
|
|
88
|
+
org_id,
|
|
89
|
+
event_date,
|
|
90
|
+
user_key
|
|
91
|
+
FROM `builder-3b0a2.analytics.first_party_analytics_events_raw_query`
|
|
92
|
+
WHERE event_date IS NOT NULL AND user_key IS NOT NULL AND user_key <> ''
|
|
93
|
+
)
|
|
94
|
+
SELECT
|
|
95
|
+
TO_HEX(SHA256(CONCAT(
|
|
96
|
+
tenant_key, '|', CAST(event_date AS STRING), '|', user_key
|
|
97
|
+
))) AS id,
|
|
98
|
+
tenant_key,
|
|
99
|
+
ANY_VALUE(owner_email) AS owner_email,
|
|
100
|
+
ANY_VALUE(org_id) AS org_id,
|
|
101
|
+
event_date,
|
|
102
|
+
user_key
|
|
103
|
+
FROM tenant_user_days
|
|
104
|
+
GROUP BY tenant_key, event_date, user_key;
|