@agent-native/core 0.175.4 → 0.175.5-nightly-20260827015800
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/templates/analytics/actions/get-explorer-dashboard.ts +1 -0
- package/corpus/templates/analytics/app/components/auth/AuthProvider.tsx +8 -6
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +32 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +66 -7
- package/corpus/templates/analytics/app/lib/prefetch-keys.ts +10 -0
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +9 -7
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +10 -11
- package/corpus/templates/analytics/changelog/2026-08-24-feature-flag-changes-recover-from-temporary-workspace-direct.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-26-analytics-distinguishes-daily-from-weekly-activity-shows-sta.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-26-dashboard-metadata-now-shows-the-original-creator-separately.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-26-dashboard-names-stay-editable-when-the-analytics-sidebar-ref.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-26-fixed-the-agent-re-asking-dashboard-scope-questions-you-had-.md +6 -0
- package/corpus/templates/analytics/server/db/schema.ts +2 -0
- package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +8 -2
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +5 -0
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +6 -4
- package/corpus/templates/analytics/server/lib/migrate-analytics-artifacts.ts +19 -1
- package/corpus/templates/analytics/server/lib/workspace-feature-flags.ts +40 -9
- package/corpus/templates/analytics/server/plugins/db.ts +10 -0
- package/corpus/templates/analytics/server/routes/api/dashboard-agent-context.json.get.ts +1 -0
- package/corpus/templates/analytics/shared/feature-flags.ts +11 -1
- package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +2 -9
- package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +8 -7
- package/corpus/templates/clips/.agents/skills/recording/SKILL.md +9 -8
- package/corpus/templates/clips/actions/import-loom-recording.ts +1 -1
- package/corpus/templates/clips/actions/lib/loom-import-job.ts +52 -35
- package/corpus/templates/clips/actions/request-transcript.ts +6 -183
- package/corpus/templates/clips/app/components/clips-avatar.tsx +46 -0
- package/corpus/templates/clips/app/components/library/recording-card.tsx +8 -7
- package/corpus/templates/clips/app/components/library/space-card.tsx +8 -5
- package/corpus/templates/clips/app/components/meetings/attendee-stack.tsx +7 -8
- package/corpus/templates/clips/app/components/meetings/transcript-bubbles.tsx +19 -12
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +128 -94
- package/corpus/templates/clips/app/components/recorder/microphone-visualizer.tsx +25 -104
- package/corpus/templates/clips/app/components/workspace/members-list.tsx +8 -6
- package/corpus/templates/clips/app/components/workspace/notifications-list.tsx +8 -6
- package/corpus/templates/clips/app/components/workspace/top-creators-table.tsx +8 -6
- package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +8 -7
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +0 -26
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -4
- package/corpus/templates/clips/changelog/2026-08-26-detected-calls-no-longer-duplicate-meetings-or-strand-the-prompt.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +8 -10
- package/corpus/templates/clips/desktop/src/components/live-waveform.tsx +99 -0
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +248 -55
- package/corpus/templates/clips/desktop/src/lib/agent-steps.ts +477 -0
- package/corpus/templates/clips/desktop/src/lib/ask-sheet-layout.ts +71 -0
- package/corpus/templates/clips/desktop/src/lib/meeting-ask.ts +297 -0
- package/corpus/templates/clips/desktop/src/lib/url.ts +24 -0
- package/corpus/templates/clips/desktop/src/overlays/ask-steps.tsx +155 -0
- package/corpus/templates/clips/desktop/src/overlays/flow-bar.tsx +7 -81
- package/corpus/templates/clips/desktop/src/overlays/live-transcript.tsx +29 -2
- package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +80 -22
- package/corpus/templates/clips/desktop/src/overlays/record-pill.tsx +13 -53
- package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +1017 -82
- package/corpus/templates/clips/desktop/src/styles.css +796 -57
- package/corpus/templates/clips/desktop/src/tailwind.css +23 -2
- package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +1765 -219
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +6 -0
- package/corpus/templates/clips/desktop/src-tauri/src/meetings_watcher.rs +45 -30
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +5 -3
- package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +91 -0
- package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +123 -27
- package/corpus/templates/clips/server/lib/share-email-hero.ts +0 -3
- package/corpus/templates/clips/server/routes/_agent-native/google/callback.get.ts +16 -0
- package/corpus/templates/clips/shared/audio-meter.ts +145 -0
- package/corpus/templates/clips/shared/clips-ai-prefs.ts +0 -1
- package/corpus/templates/clips/shared/live-waveform.tsx +119 -0
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +44 -22
- package/corpus/templates/content/app/components/ui/avatar.tsx +1 -0
- package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +4 -1
- package/corpus/templates/design/app/hooks/use-question-flow.ts +9 -2
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +111 -37
- package/corpus/templates/design/changelog/2026-08-26-design-no-longer-asks-users-to-confirm-guided-questions-they-have-already-answered.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-26-signing-out-goes-straight-to-the-sign-in-page.md +5 -0
- package/corpus/templates/dispatch/server/lib/org-apps-directory.ts +96 -47
- package/corpus/templates/dispatch/server/plugins/org-apps-directory.ts +73 -29
- package/corpus/templates/factory/.env.example +6 -2
- package/corpus/templates/factory/AGENTS.md +3 -3
- package/corpus/templates/factory/README.md +4 -2
- package/corpus/templates/factory/server/connectors/credentials.ts +70 -4
- package/corpus/templates/mail/actions/get-email.ts +68 -21
- package/corpus/templates/mail/actions/get-thread.ts +92 -51
- package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +2 -9
- package/corpus/templates/mail/app/hooks/use-emails.ts +7 -4
- package/corpus/templates/mail/server/lib/mail-connector-catalog.ts +7 -4
- package/corpus/templates/plan/app/pages/PlansPage.tsx +23 -15
- package/corpus/templates/slides/actions/add-deck.ts +20 -0
- package/corpus/templates/slides/actions/create-deck.ts +17 -7
- package/corpus/templates/slides/actions/delete-deck.ts +45 -5
- package/corpus/templates/slides/actions/get-deck.ts +77 -11
- package/corpus/templates/slides/actions/patch-deck.ts +14 -2
- package/corpus/templates/slides/actions/save-deck.ts +20 -0
- package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +18 -7
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +38 -14
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +2 -2
- package/corpus/templates/slides/app/components/ui/avatar.tsx +1 -0
- package/corpus/templates/slides/server/handlers/decks.ts +10 -0
- package/corpus/templates/slides/shared/slide-ids.ts +133 -0
- package/corpus/templates/tasks/DEVELOPING.md +8 -0
- package/corpus/templates/tasks/drizzle.config.ts +3 -1
- package/corpus/templates/tasks/drizzle.local.config.ts +6 -0
- package/corpus/templates/tasks/package.json +2 -1
- package/corpus/templates/tasks/server/db/migrations/meta/0000_snapshot.json +234 -0
- package/corpus/templates/tasks/server/db/migrations/meta/_journal.json +13 -0
- package/corpus/templates/tasks/server/db/migrations.ts +110 -0
- package/corpus/templates/tasks/server/plugins/db.ts +3 -87
- package/dist/client/AssistantChat.js +3 -10
- package/dist/client/guided-questions.d.ts +11 -1
- package/dist/client/guided-questions.js +24 -7
- package/dist/client/hooks/index.d.ts +2 -1
- package/dist/client/hooks/index.js +2 -1
- package/dist/client/org/OrgSwitcher.js +3 -17
- package/dist/client/review/ReviewThreadPanel.js +4 -2
- package/dist/client/sign-out.d.ts +15 -0
- package/dist/client/sign-out.js +82 -0
- package/dist/client/use-action.d.ts +2 -0
- package/dist/client/use-action.js +4 -2
- package/dist/client/use-session.d.ts +23 -1
- package/dist/client/use-session.js +46 -0
- package/dist/collab/client.js +20 -5
- package/dist/collab/presence.d.ts +3 -1
- package/dist/collab/presence.js +48 -45
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/drizzle-config.d.ts +7 -0
- package/dist/db/drizzle-config.js +35 -9
- package/dist/db/drizzle-migrations.d.ts +28 -0
- package/dist/db/drizzle-migrations.js +81 -0
- package/dist/db/index.d.ts +1 -1
- package/dist/db/migrations.d.ts +13 -1
- package/dist/db/migrations.js +60 -31
- package/dist/db/schema.js +4 -1
- package/dist/deploy/build.d.ts +6 -0
- package/dist/deploy/build.js +41 -0
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/mcp/org-directory.d.ts +19 -7
- package/dist/mcp/org-directory.js +92 -68
- package/dist/observability/routes.d.ts +3 -3
- package/dist/org/context.d.ts +6 -0
- package/dist/org/context.js +22 -0
- package/dist/org/index.d.ts +1 -1
- package/dist/org/index.js +1 -1
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/resources/store.d.ts +12 -0
- package/dist/resources/store.js +55 -0
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-discovery.d.ts +18 -2
- package/dist/server/agent-discovery.js +191 -22
- package/dist/server/auth.js +3 -2
- package/dist/server/builder-browser.d.ts +0 -4
- package/dist/server/builder-browser.js +23 -8
- package/dist/server/email-template.d.ts +5 -0
- package/dist/server/email-template.js +14 -1
- package/dist/server/google-oauth.d.ts +18 -0
- package/dist/server/google-oauth.js +3 -3
- package/dist/server/onboarding-html.js +3 -3
- package/dist/server/poll.d.ts +4 -2
- package/dist/server/poll.js +8 -3
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/short-lived-token.d.ts +1 -1
- package/dist/server/short-lived-token.js +1 -1
- package/dist/shared/environment-lanes.d.ts +1 -0
- package/dist/shared/environment-lanes.js +1 -0
- package/dist/shared/google-profile-image.d.ts +2 -0
- package/dist/shared/google-profile-image.js +24 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +1 -0
- package/dist/sharing/actions/share-resource.js +14 -6
- package/dist/styles/agent-conversation.css +13 -0
- package/docs/content/creating-templates.mdx +10 -1
- package/docs/content/server-database.mdx +49 -3
- package/docs/content/server-plugins.mdx +39 -3
- package/docs/content/webmcp.mdx +2 -0
- package/package.json +2 -1
- package/corpus/templates/analytics/data/explorer-configs/_autosave.json +0 -18
- package/corpus/templates/analytics/data/explorer-configs/steve-chart.json +0 -18
- package/corpus/templates/analytics/data/explorer-dashboards/dashboard-1773260837897.json +0 -10
- package/corpus/templates/analytics/data/sync-config.json +0 -8
- package/corpus/templates/brain/data/sync-config.json +0 -1
- package/corpus/templates/calendar/data/availability.json +0 -32
- package/corpus/templates/calendar/data/settings.json +0 -6
- package/corpus/templates/calendar/data/sync-config.json +0 -10
- package/corpus/templates/chat/data/sync-config.json +0 -1
- package/corpus/templates/clips/data/sync-config.json +0 -1
- package/corpus/templates/clips/desktop/src/lib/audio-meter.ts +0 -80
- package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +0 -113
- package/corpus/templates/design/data/sync-config.json +0 -1
- package/corpus/templates/factory/data/sync-config.json +0 -1
- package/corpus/templates/forms/data/settings.json +0 -8
- package/corpus/templates/forms/data/sync-config.json +0 -3
- package/corpus/templates/macros/data/sync-config.json +0 -4
- package/corpus/templates/mail/data/emails.defaults.json +0 -1
- package/corpus/templates/mail/data/labels.defaults.json +0 -59
- package/corpus/templates/mail/data/settings.defaults.json +0 -9
- package/corpus/templates/mail/data/sync-config.json +0 -8
- package/corpus/templates/slides/data/sync-config.json +0 -8
- package/corpus/templates/tasks/data/sync-config.json +0 -1
- package/dist/templates/chat/data/.gitkeep +0 -0
- package/dist/templates/chat/data/sync-config.json +0 -1
- package/dist/templates/default/data/.gitkeep +0 -0
- package/dist/templates/default/data/sync-config.json +0 -1
- package/src/templates/chat/data/.gitkeep +0 -0
- package/src/templates/chat/data/sync-config.json +0 -1
- package/src/templates/default/data/.gitkeep +0 -0
- package/src/templates/default/data/sync-config.json +0 -1
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
signOut,
|
|
3
|
+
useSession,
|
|
4
|
+
type AuthSession,
|
|
5
|
+
} from "@agent-native/core/client/hooks";
|
|
3
6
|
import { createContext, useContext, type ReactNode } from "react";
|
|
4
7
|
|
|
5
8
|
interface AuthContextValue {
|
|
@@ -16,10 +19,9 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
|
|
16
19
|
const value: AuthContextValue = {
|
|
17
20
|
auth: session,
|
|
18
21
|
isLoading,
|
|
19
|
-
logout: () =>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}).then(() => location.reload()),
|
|
22
|
+
logout: () => {
|
|
23
|
+
void signOut();
|
|
24
|
+
},
|
|
23
25
|
};
|
|
24
26
|
|
|
25
27
|
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
|
|
@@ -628,6 +628,23 @@ function numericTooltipValue(value: unknown): number {
|
|
|
628
628
|
return Number.isFinite(numeric) ? numeric : Number.NEGATIVE_INFINITY;
|
|
629
629
|
}
|
|
630
630
|
|
|
631
|
+
function sumTooltipPayloadValues(
|
|
632
|
+
items: Array<{ value?: unknown }>,
|
|
633
|
+
): number | null {
|
|
634
|
+
let total = 0;
|
|
635
|
+
let hasNumericValue = false;
|
|
636
|
+
|
|
637
|
+
for (const item of items) {
|
|
638
|
+
const numeric =
|
|
639
|
+
typeof item.value === "number" ? item.value : Number(item.value);
|
|
640
|
+
if (!Number.isFinite(numeric)) continue;
|
|
641
|
+
hasNumericValue = true;
|
|
642
|
+
total += numeric;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
return hasNumericValue ? total : null;
|
|
646
|
+
}
|
|
647
|
+
|
|
631
648
|
function tooltipItemName(item: {
|
|
632
649
|
dataKey?: string | number;
|
|
633
650
|
name?: string | number;
|
|
@@ -1072,6 +1089,7 @@ export function ChartTooltip({
|
|
|
1072
1089
|
labelFormatter,
|
|
1073
1090
|
seriesNameFormatter,
|
|
1074
1091
|
valueFormatter,
|
|
1092
|
+
stacked,
|
|
1075
1093
|
}: {
|
|
1076
1094
|
active?: boolean;
|
|
1077
1095
|
payload?: Array<{
|
|
@@ -1085,6 +1103,7 @@ export function ChartTooltip({
|
|
|
1085
1103
|
labelFormatter?: (value: string) => string;
|
|
1086
1104
|
seriesNameFormatter?: (value: string) => string;
|
|
1087
1105
|
valueFormatter?: (value: number, name?: string | number) => string;
|
|
1106
|
+
stacked?: boolean;
|
|
1088
1107
|
}) {
|
|
1089
1108
|
const items = useMemo(
|
|
1090
1109
|
() =>
|
|
@@ -1099,6 +1118,13 @@ export function ChartTooltip({
|
|
|
1099
1118
|
isVisible,
|
|
1100
1119
|
coordinate,
|
|
1101
1120
|
);
|
|
1121
|
+
const stackedTotal = stacked ? sumTooltipPayloadValues(items) : null;
|
|
1122
|
+
const totalValue =
|
|
1123
|
+
stackedTotal != null && valueFormatter
|
|
1124
|
+
? valueFormatter(stackedTotal, items[0]?.name)
|
|
1125
|
+
: stackedTotal != null
|
|
1126
|
+
? String(stackedTotal)
|
|
1127
|
+
: null;
|
|
1102
1128
|
|
|
1103
1129
|
const labelText =
|
|
1104
1130
|
label == null
|
|
@@ -1116,6 +1142,9 @@ export function ChartTooltip({
|
|
|
1116
1142
|
className="fixed min-w-40 max-w-[280px] rounded-md border border-border bg-card px-3 py-2 text-xs text-foreground shadow-lg pointer-events-none"
|
|
1117
1143
|
style={{ zIndex: CHART_TOOLTIP_Z_INDEX }}
|
|
1118
1144
|
>
|
|
1145
|
+
{totalValue && (
|
|
1146
|
+
<div className="mb-1.5 font-semibold text-foreground">{totalValue}</div>
|
|
1147
|
+
)}
|
|
1119
1148
|
{labelText && (
|
|
1120
1149
|
<div className="mb-1.5 truncate font-medium text-foreground">
|
|
1121
1150
|
{labelText}
|
|
@@ -2223,6 +2252,7 @@ function BarRenderer({
|
|
|
2223
2252
|
labelFormatter={xLabelFormatter}
|
|
2224
2253
|
seriesNameFormatter={seriesNameFormatter}
|
|
2225
2254
|
valueFormatter={valueFormatter}
|
|
2255
|
+
stacked={stacked}
|
|
2226
2256
|
/>
|
|
2227
2257
|
}
|
|
2228
2258
|
itemSorter={(item) => -(Number(item.value) || 0)}
|
|
@@ -2333,6 +2363,7 @@ function TimeSeriesRenderer({
|
|
|
2333
2363
|
labelFormatter={xLabelFormatter}
|
|
2334
2364
|
seriesNameFormatter={seriesNameFormatter}
|
|
2335
2365
|
valueFormatter={valueFormatter}
|
|
2366
|
+
stacked={stacked}
|
|
2336
2367
|
/>
|
|
2337
2368
|
}
|
|
2338
2369
|
itemSorter={(item) => -(Number(item.value) || 0)}
|
|
@@ -2440,6 +2471,7 @@ function TimeSeriesRenderer({
|
|
|
2440
2471
|
labelFormatter={xLabelFormatter}
|
|
2441
2472
|
seriesNameFormatter={seriesNameFormatter}
|
|
2442
2473
|
valueFormatter={valueFormatter}
|
|
2474
|
+
stacked={stacked}
|
|
2443
2475
|
/>
|
|
2444
2476
|
}
|
|
2445
2477
|
itemSorter={(item) => -(Number(item.value) || 0)}
|
|
@@ -84,7 +84,7 @@ function InteractiveLayout({ children }: LayoutProps) {
|
|
|
84
84
|
"Answers:",
|
|
85
85
|
formattedAnswers,
|
|
86
86
|
"",
|
|
87
|
-
"Use these answers to choose the dashboard scope, data source, metrics, breakdowns, and layout. For dashboards, consult the data dictionary before writing SQL
|
|
87
|
+
"Use these answers to choose the dashboard scope, data source, metrics, breakdowns, and layout. For dashboards, consult the data dictionary before writing SQL.",
|
|
88
88
|
].join("\n"),
|
|
89
89
|
buildSkipContext: () =>
|
|
90
90
|
"The user skipped the guided analytics questions. Proceed with reasonable defaults, consult the data dictionary before writing SQL, and ask again only if a required source/table/metric is still genuinely ambiguous.",
|
|
@@ -148,7 +148,9 @@ import { useUserPref } from "@/hooks/use-user-pref";
|
|
|
148
148
|
import { shouldRenderDashboardList } from "@/lib/dashboard-list-loading";
|
|
149
149
|
import { usePopularity, popularityOf } from "@/lib/item-popularity";
|
|
150
150
|
import {
|
|
151
|
+
DASHBOARD_SESSION_LOADING_SCOPE,
|
|
151
152
|
dashboardCacheScope,
|
|
153
|
+
preserveScopedDashboardPlaceholder,
|
|
152
154
|
sqlDashboardPrefetchKey,
|
|
153
155
|
type PrefetchSnapshot,
|
|
154
156
|
} from "@/lib/prefetch-keys";
|
|
@@ -162,6 +164,8 @@ import { SidebarLoadError } from "./SidebarLoadError";
|
|
|
162
164
|
const SIDEBAR_PREVIEW_COUNT = 5;
|
|
163
165
|
const ASK_OPEN_KEY = "analytics-sidebar-ask-open";
|
|
164
166
|
const DASHBOARD_SORT_MODE_KEY = "dashboard-sort-mode";
|
|
167
|
+
const DASHBOARD_VISIBILITY_FILTER_KEY =
|
|
168
|
+
"analytics-sidebar-dashboard-visibility";
|
|
165
169
|
const DASHBOARDS_OPEN_KEY = "analytics-sidebar-dashboards-open";
|
|
166
170
|
const SIDEBAR_COLLAPSE_KEY = "analytics.sidebar.collapsed";
|
|
167
171
|
const SIDEBAR_SKELETON_CLASS =
|
|
@@ -231,6 +235,35 @@ function setStoredSortMode(key: string, value: SidebarSortMode): void {
|
|
|
231
235
|
}
|
|
232
236
|
}
|
|
233
237
|
|
|
238
|
+
export function getStoredVisibilityFilter(
|
|
239
|
+
key: string,
|
|
240
|
+
): SidebarVisibilityFilter {
|
|
241
|
+
if (typeof window === "undefined") return "all";
|
|
242
|
+
try {
|
|
243
|
+
const raw = window.localStorage.getItem(key);
|
|
244
|
+
if (raw === "all" || raw === "private" || raw === "shared") {
|
|
245
|
+
return raw;
|
|
246
|
+
}
|
|
247
|
+
} catch {
|
|
248
|
+
// coercion-ok: localStorage is optional; in-memory filter state remains authoritative.
|
|
249
|
+
// localStorage unavailable; visibility filter is best-effort.
|
|
250
|
+
}
|
|
251
|
+
return "all";
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function setStoredVisibilityFilter(
|
|
255
|
+
key: string,
|
|
256
|
+
value: SidebarVisibilityFilter,
|
|
257
|
+
): void {
|
|
258
|
+
if (typeof window === "undefined") return;
|
|
259
|
+
try {
|
|
260
|
+
window.localStorage.setItem(key, value);
|
|
261
|
+
} catch {
|
|
262
|
+
// coercion-ok: localStorage is optional; in-memory filter state remains authoritative.
|
|
263
|
+
// localStorage unavailable; visibility filter is best-effort.
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
234
267
|
function sortByName<T extends { id: string; name: string }>(items: T[]): T[] {
|
|
235
268
|
return [...items].sort((a, b) => {
|
|
236
269
|
const name = a.name.localeCompare(b.name);
|
|
@@ -516,6 +549,7 @@ function SortableRow({
|
|
|
516
549
|
useState(false);
|
|
517
550
|
const [isRenaming, setIsRenaming] = useState(false);
|
|
518
551
|
const [renameValue, setRenameValue] = useState(name);
|
|
552
|
+
const pendingRenameRef = useRef(false);
|
|
519
553
|
const renameInputRef = useAutoFocusSelect<HTMLInputElement>(isRenaming);
|
|
520
554
|
|
|
521
555
|
useEffect(() => {
|
|
@@ -749,11 +783,22 @@ function SortableRow({
|
|
|
749
783
|
{t("sidebar.itemActions", { name })}
|
|
750
784
|
</TooltipContent>
|
|
751
785
|
</Tooltip>
|
|
752
|
-
<DropdownMenuContent
|
|
786
|
+
<DropdownMenuContent
|
|
787
|
+
side="right"
|
|
788
|
+
align="start"
|
|
789
|
+
className="w-44"
|
|
790
|
+
onCloseAutoFocus={(event) => {
|
|
791
|
+
if (!pendingRenameRef.current) return;
|
|
792
|
+
event.preventDefault();
|
|
793
|
+
pendingRenameRef.current = false;
|
|
794
|
+
setIsRenaming(true);
|
|
795
|
+
}}
|
|
796
|
+
>
|
|
753
797
|
<DropdownMenuItem
|
|
754
798
|
onSelect={() => {
|
|
755
799
|
setRenameValue(name);
|
|
756
|
-
|
|
800
|
+
pendingRenameRef.current = true;
|
|
801
|
+
setMenuOpen(false);
|
|
757
802
|
}}
|
|
758
803
|
>
|
|
759
804
|
<IconPencil className="me-2 h-3.5 w-3.5" />
|
|
@@ -1513,8 +1558,10 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1513
1558
|
const t = useT();
|
|
1514
1559
|
const queryClient = useQueryClient();
|
|
1515
1560
|
const { setTheme } = useTheme();
|
|
1516
|
-
const { auth } = useAuth();
|
|
1517
|
-
const dashboardScope =
|
|
1561
|
+
const { auth, isLoading: authLoading } = useAuth();
|
|
1562
|
+
const dashboardScope = authLoading
|
|
1563
|
+
? DASHBOARD_SESSION_LOADING_SCOPE
|
|
1564
|
+
: dashboardCacheScope(auth);
|
|
1518
1565
|
|
|
1519
1566
|
const isAskRoute = location.pathname === "/ask";
|
|
1520
1567
|
const activeDashboardId = useMemo(() => {
|
|
@@ -1536,8 +1583,9 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1536
1583
|
activeDashboardId !== null,
|
|
1537
1584
|
);
|
|
1538
1585
|
const [dashShowAll, setDashShowAll] = useState(false);
|
|
1539
|
-
const [dashFilter, setDashFilter] =
|
|
1540
|
-
|
|
1586
|
+
const [dashFilter, setDashFilter] = useState<SidebarVisibilityFilter>(() =>
|
|
1587
|
+
getStoredVisibilityFilter(DASHBOARD_VISIBILITY_FILTER_KEY),
|
|
1588
|
+
);
|
|
1541
1589
|
const [dashboardSortMode, setDashboardSortModeState] =
|
|
1542
1590
|
useState<SidebarSortMode>(() => getStoredSortMode(DASHBOARD_SORT_MODE_KEY));
|
|
1543
1591
|
const { data: popularity, isReady: popularityReady } = usePopularity();
|
|
@@ -1630,6 +1678,14 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1630
1678
|
setDashboardSortModeState(mode);
|
|
1631
1679
|
}, []);
|
|
1632
1680
|
|
|
1681
|
+
const setDashboardVisibilityFilter = useCallback(
|
|
1682
|
+
(value: SidebarVisibilityFilter) => {
|
|
1683
|
+
setStoredVisibilityFilter(DASHBOARD_VISIBILITY_FILTER_KEY, value);
|
|
1684
|
+
setDashFilter(value);
|
|
1685
|
+
},
|
|
1686
|
+
[],
|
|
1687
|
+
);
|
|
1688
|
+
|
|
1633
1689
|
useEffect(() => {
|
|
1634
1690
|
if (getStoredBooleanPreference(ASK_OPEN_KEY) === null) {
|
|
1635
1691
|
setAskOpen(isAskRoute);
|
|
@@ -1700,7 +1756,10 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
1700
1756
|
} = useQuery({
|
|
1701
1757
|
queryKey: ["sql-dashboards-sidebar", dashboardScope, dashboardsSync],
|
|
1702
1758
|
queryFn: () => fetchSqlDashboards(t),
|
|
1759
|
+
enabled: !authLoading,
|
|
1703
1760
|
staleTime: 30_000,
|
|
1761
|
+
placeholderData: (prev, previousQuery) =>
|
|
1762
|
+
preserveScopedDashboardPlaceholder(prev, previousQuery, dashboardScope),
|
|
1704
1763
|
});
|
|
1705
1764
|
|
|
1706
1765
|
const {
|
|
@@ -2464,7 +2523,7 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
|
|
|
2464
2523
|
sortMode={dashboardSortMode}
|
|
2465
2524
|
onSortModeChange={setDashboardSortMode}
|
|
2466
2525
|
visibilityFilter={dashFilter}
|
|
2467
|
-
onVisibilityFilterChange={
|
|
2526
|
+
onVisibilityFilterChange={setDashboardVisibilityFilter}
|
|
2468
2527
|
/>
|
|
2469
2528
|
<button
|
|
2470
2529
|
type="button"
|
|
@@ -9,6 +9,8 @@ export type DashboardCacheSession = {
|
|
|
9
9
|
orgId?: string | null;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
export const DASHBOARD_SESSION_LOADING_SCOPE = "session-loading";
|
|
13
|
+
|
|
12
14
|
/**
|
|
13
15
|
* Dashboard payloads are access-scoped. Keep the principal and active org in
|
|
14
16
|
* every client cache key so a session change cannot adopt another caller's
|
|
@@ -22,6 +24,14 @@ export function dashboardCacheScope(
|
|
|
22
24
|
return `${encodeURIComponent(principal)}:${encodeURIComponent(org)}`;
|
|
23
25
|
}
|
|
24
26
|
|
|
27
|
+
export function preserveScopedDashboardPlaceholder<T>(
|
|
28
|
+
previous: T | undefined,
|
|
29
|
+
previousQuery: { queryKey: readonly unknown[] } | undefined,
|
|
30
|
+
scope: string,
|
|
31
|
+
): T | undefined {
|
|
32
|
+
return previousQuery?.queryKey[1] === scope ? previous : undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
25
35
|
export const sqlDashboardPrefetchKey = (
|
|
26
36
|
id: string,
|
|
27
37
|
scope = "anonymous:personal",
|
|
@@ -118,8 +118,8 @@ const TAB_ID = generateTabId();
|
|
|
118
118
|
|
|
119
119
|
type FetchedExplorerDashboard = {
|
|
120
120
|
data: ExplorerDashboardData;
|
|
121
|
-
ownerEmail: string | null;
|
|
122
121
|
createdAt: string | null;
|
|
122
|
+
createdBy: string | null;
|
|
123
123
|
updatedAt: string | null;
|
|
124
124
|
updatedBy: string | null;
|
|
125
125
|
archivedAt: string | null;
|
|
@@ -152,8 +152,8 @@ async function fetchDashboard(
|
|
|
152
152
|
name: raw.name ?? "Untitled Dashboard",
|
|
153
153
|
charts: raw.charts ?? [],
|
|
154
154
|
},
|
|
155
|
-
ownerEmail: typeof raw.ownerEmail === "string" ? raw.ownerEmail : null,
|
|
156
155
|
createdAt: typeof raw.createdAt === "string" ? raw.createdAt : null,
|
|
156
|
+
createdBy: typeof raw.createdBy === "string" ? raw.createdBy : null,
|
|
157
157
|
updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : null,
|
|
158
158
|
updatedBy: typeof raw.updatedBy === "string" ? raw.updatedBy : null,
|
|
159
159
|
archivedAt: typeof raw.archivedAt === "string" ? raw.archivedAt : null,
|
|
@@ -189,7 +189,9 @@ export default function ExplorerDashboardPage() {
|
|
|
189
189
|
const [dashboard, setDashboard] = useState<ExplorerDashboardData | null>(
|
|
190
190
|
null,
|
|
191
191
|
);
|
|
192
|
-
const [
|
|
192
|
+
const [dashboardCreatedBy, setDashboardCreatedBy] = useState<string | null>(
|
|
193
|
+
null,
|
|
194
|
+
);
|
|
193
195
|
const [dashboardCreatedAt, setDashboardCreatedAt] = useState<string | null>(
|
|
194
196
|
null,
|
|
195
197
|
);
|
|
@@ -345,7 +347,7 @@ export default function ExplorerDashboardPage() {
|
|
|
345
347
|
if (!dashboardId) return;
|
|
346
348
|
setLoaded(false);
|
|
347
349
|
setDashboard(null);
|
|
348
|
-
|
|
350
|
+
setDashboardCreatedBy(null);
|
|
349
351
|
setDashboardCreatedAt(null);
|
|
350
352
|
setDashboardUpdatedAt(null);
|
|
351
353
|
setDashboardUpdatedBy(null);
|
|
@@ -360,7 +362,7 @@ export default function ExplorerDashboardPage() {
|
|
|
360
362
|
const d = dashboardQuery.data;
|
|
361
363
|
if (d) {
|
|
362
364
|
setDashboard(d.data);
|
|
363
|
-
|
|
365
|
+
setDashboardCreatedBy(d.createdBy);
|
|
364
366
|
setDashboardCreatedAt(d.createdAt);
|
|
365
367
|
setDashboardUpdatedAt(d.updatedAt);
|
|
366
368
|
setDashboardUpdatedBy(d.updatedBy);
|
|
@@ -377,7 +379,7 @@ export default function ExplorerDashboardPage() {
|
|
|
377
379
|
name: t("explorerDashboard.untitledDashboard"),
|
|
378
380
|
charts: [],
|
|
379
381
|
});
|
|
380
|
-
|
|
382
|
+
setDashboardCreatedBy(null);
|
|
381
383
|
setDashboardCreatedAt(null);
|
|
382
384
|
setDashboardUpdatedAt(null);
|
|
383
385
|
setDashboardUpdatedBy(null);
|
|
@@ -701,7 +703,7 @@ export default function ExplorerDashboardPage() {
|
|
|
701
703
|
<DropdownMenuLabel className="font-normal">
|
|
702
704
|
<DashboardMetadata
|
|
703
705
|
createdAt={dashboardCreatedAt}
|
|
704
|
-
createdBy={
|
|
706
|
+
createdBy={dashboardCreatedBy}
|
|
705
707
|
updatedAt={dashboardUpdatedAt}
|
|
706
708
|
updatedBy={dashboardUpdatedBy}
|
|
707
709
|
/>
|
|
@@ -407,8 +407,8 @@ type FetchedDashboard = {
|
|
|
407
407
|
hiddenAt: string | null;
|
|
408
408
|
hiddenBy: string | null;
|
|
409
409
|
visibility: "private" | "org" | "public";
|
|
410
|
-
ownerEmail: string | null;
|
|
411
410
|
createdAt: string | null;
|
|
411
|
+
createdBy: string | null;
|
|
412
412
|
updatedAt: string | null;
|
|
413
413
|
updatedBy: string | null;
|
|
414
414
|
} & ResourceAccess;
|
|
@@ -494,8 +494,8 @@ async function fetchDashboard(
|
|
|
494
494
|
data.visibility === "org" || data.visibility === "public"
|
|
495
495
|
? data.visibility
|
|
496
496
|
: "private",
|
|
497
|
-
ownerEmail: typeof data.ownerEmail === "string" ? data.ownerEmail : null,
|
|
498
497
|
createdAt: typeof data.createdAt === "string" ? data.createdAt : null,
|
|
498
|
+
createdBy: typeof data.createdBy === "string" ? data.createdBy : null,
|
|
499
499
|
updatedAt: typeof data.updatedAt === "string" ? data.updatedAt : null,
|
|
500
500
|
updatedBy: typeof data.updatedBy === "string" ? data.updatedBy : null,
|
|
501
501
|
role: typeof data.role === "string" ? data.role : undefined,
|
|
@@ -584,7 +584,9 @@ function SqlDashboardPageContent({
|
|
|
584
584
|
const [dashboardVisibility, setDashboardVisibility] = useState<
|
|
585
585
|
"private" | "org" | "public" | null
|
|
586
586
|
>(null);
|
|
587
|
-
const [
|
|
587
|
+
const [dashboardCreatedBy, setDashboardCreatedBy] = useState<string | null>(
|
|
588
|
+
null,
|
|
589
|
+
);
|
|
588
590
|
const [dashboardCreatedAt, setDashboardCreatedAt] = useState<string | null>(
|
|
589
591
|
null,
|
|
590
592
|
);
|
|
@@ -875,7 +877,7 @@ function SqlDashboardPageContent({
|
|
|
875
877
|
setArchivedAt(null);
|
|
876
878
|
setHiddenAt(null);
|
|
877
879
|
setDashboardVisibility(null);
|
|
878
|
-
|
|
880
|
+
setDashboardCreatedBy(null);
|
|
879
881
|
setDashboardCreatedAt(null);
|
|
880
882
|
setDashboardUpdatedAt(null);
|
|
881
883
|
setDashboardUpdatedBy(null);
|
|
@@ -922,7 +924,7 @@ function SqlDashboardPageContent({
|
|
|
922
924
|
setArchivedAt(fetched?.archivedAt ?? null);
|
|
923
925
|
setHiddenAt(fetched?.hiddenAt ?? null);
|
|
924
926
|
setDashboardVisibility(fetchedVisibility);
|
|
925
|
-
|
|
927
|
+
setDashboardCreatedBy(fetched?.createdBy ?? null);
|
|
926
928
|
setDashboardCreatedAt(fetched?.createdAt ?? null);
|
|
927
929
|
setDashboardUpdatedAt(fetched?.updatedAt ?? null);
|
|
928
930
|
setDashboardUpdatedBy(fetched?.updatedBy ?? null);
|
|
@@ -1682,14 +1684,11 @@ function SqlDashboardPageContent({
|
|
|
1682
1684
|
const handleUnhide = useCallback(async () => {
|
|
1683
1685
|
if (!dashboardId) return;
|
|
1684
1686
|
try {
|
|
1685
|
-
|
|
1687
|
+
await hideDashboardAction({
|
|
1686
1688
|
id: dashboardId,
|
|
1687
1689
|
hidden: false,
|
|
1688
|
-
})
|
|
1690
|
+
});
|
|
1689
1691
|
setHiddenAt(null);
|
|
1690
|
-
if (typeof result?.ownerEmail === "string") {
|
|
1691
|
-
setDashboardOwner(result.ownerEmail);
|
|
1692
|
-
}
|
|
1693
1692
|
queryClient.invalidateQueries({
|
|
1694
1693
|
queryKey: ["sql-dashboards-sidebar", dashboardScope],
|
|
1695
1694
|
});
|
|
@@ -1952,7 +1951,7 @@ function SqlDashboardPageContent({
|
|
|
1952
1951
|
<DropdownMenuLabel className="font-normal">
|
|
1953
1952
|
<DashboardMetadata
|
|
1954
1953
|
createdAt={dashboardCreatedAt}
|
|
1955
|
-
createdBy={
|
|
1954
|
+
createdBy={dashboardCreatedBy}
|
|
1956
1955
|
updatedAt={dashboardUpdatedAt}
|
|
1957
1956
|
updatedBy={dashboardUpdatedBy}
|
|
1958
1957
|
/>
|
|
@@ -31,6 +31,8 @@ export const dashboards = table("dashboards", {
|
|
|
31
31
|
/** Full dashboard config (SqlDashboardConfig or Explorer state) as JSON. */
|
|
32
32
|
config: text("config").notNull(),
|
|
33
33
|
createdAt: text("created_at").notNull().default(now()),
|
|
34
|
+
/** Original authenticated creator. Null when historical provenance is unknown. */
|
|
35
|
+
createdBy: text("created_by"),
|
|
34
36
|
updatedAt: text("updated_at").notNull().default(now()),
|
|
35
37
|
/** Archive timestamp. Null = active. Archived rows are hidden from
|
|
36
38
|
* default list responses but remain accessible by id and can be restored. */
|
|
@@ -104,11 +104,14 @@ export function buildDashboardAgentContext(
|
|
|
104
104
|
hiddenAt: dashboard.hiddenAt,
|
|
105
105
|
hiddenBy: dashboard.hiddenBy,
|
|
106
106
|
createdAt: dashboard.createdAt,
|
|
107
|
+
createdBy: dashboard.createdBy,
|
|
107
108
|
updatedAt: dashboard.updatedAt,
|
|
108
109
|
updatedBy: dashboard.updatedBy,
|
|
109
110
|
url: `/dashboards/${dashboard.id}`,
|
|
110
111
|
};
|
|
111
|
-
return options.includeConfig === false
|
|
112
|
+
return options.includeConfig === false
|
|
113
|
+
? base
|
|
114
|
+
: { ...base, ...config, createdBy: base.createdBy };
|
|
112
115
|
}
|
|
113
116
|
|
|
114
117
|
export function buildDashboardSeedAgentContext(
|
|
@@ -135,9 +138,12 @@ export function buildDashboardSeedAgentContext(
|
|
|
135
138
|
archivedAt: null,
|
|
136
139
|
hiddenAt: null,
|
|
137
140
|
hiddenBy: null,
|
|
141
|
+
createdBy: null,
|
|
138
142
|
url: `/dashboards/${id}`,
|
|
139
143
|
};
|
|
140
|
-
return options.includeConfig === false
|
|
144
|
+
return options.includeConfig === false
|
|
145
|
+
? base
|
|
146
|
+
: { ...base, ...seed, createdBy: base.createdBy };
|
|
141
147
|
}
|
|
142
148
|
|
|
143
149
|
export function buildAnalysisAgentContext(
|
|
@@ -53,6 +53,7 @@ export interface DashboardRecord {
|
|
|
53
53
|
orgId: string | null;
|
|
54
54
|
visibility: "private" | "org" | "public";
|
|
55
55
|
createdAt: string;
|
|
56
|
+
createdBy: string | null;
|
|
56
57
|
updatedAt: string;
|
|
57
58
|
updatedBy: string | null;
|
|
58
59
|
/** ISO timestamp set when the dashboard is archived. Null = active. */
|
|
@@ -467,6 +468,7 @@ function rowToDashboard(row: any, role?: AccessRole): DashboardRecord {
|
|
|
467
468
|
orgId: row.orgId ?? null,
|
|
468
469
|
visibility: row.visibility,
|
|
469
470
|
createdAt: row.createdAt,
|
|
471
|
+
createdBy: row.createdBy ?? null,
|
|
470
472
|
updatedAt: row.updatedAt,
|
|
471
473
|
updatedBy: row.updatedBy ?? null,
|
|
472
474
|
archivedAt: row.archivedAt ?? null,
|
|
@@ -546,6 +548,7 @@ async function migrateDashboardFromSettings(
|
|
|
546
548
|
(typeof (settingsValue as any).updatedAt === "string" &&
|
|
547
549
|
(settingsValue as any).updatedAt) ||
|
|
548
550
|
createdAt;
|
|
551
|
+
const createdBy = visibility === "private" ? ownerEmail : null;
|
|
549
552
|
await db
|
|
550
553
|
.insert(schema.dashboards)
|
|
551
554
|
.values({
|
|
@@ -557,6 +560,7 @@ async function migrateDashboardFromSettings(
|
|
|
557
560
|
orgId,
|
|
558
561
|
visibility,
|
|
559
562
|
createdAt,
|
|
563
|
+
createdBy,
|
|
560
564
|
updatedAt,
|
|
561
565
|
updatedBy: ownerEmail,
|
|
562
566
|
})
|
|
@@ -1389,6 +1393,7 @@ export async function upsertDashboard(
|
|
|
1389
1393
|
ownerEmail: ctx.email,
|
|
1390
1394
|
orgId: ctx.orgId,
|
|
1391
1395
|
visibility: "private",
|
|
1396
|
+
createdBy: ctx.email,
|
|
1392
1397
|
updatedBy: ctx.email,
|
|
1393
1398
|
});
|
|
1394
1399
|
}
|
|
@@ -504,6 +504,7 @@ export function repairFirstPartyObservedRetentionPanels(
|
|
|
504
504
|
legacySql: [
|
|
505
505
|
LEGACY_WAU_BY_TEMPLATE_SQL,
|
|
506
506
|
PRE_MARKETING_SITE_WAU_BY_TEMPLATE_SQL,
|
|
507
|
+
DAU_BY_TEMPLATE_SQL,
|
|
507
508
|
],
|
|
508
509
|
sql: WAU_BY_TEMPLATE_SQL,
|
|
509
510
|
},
|
|
@@ -573,10 +574,11 @@ export function repairFirstPartyObservedRetentionPanels(
|
|
|
573
574
|
}
|
|
574
575
|
export const LEGACY_DAU_BY_TEMPLATE_SQL = `SELECT ${EVENT_DATE_SQL} AS date, ${TEMPLATE_EXPR} AS template, COUNT(DISTINCT ${SIGNED_IN_ACTIVITY_KEY_SQL}) AS visitors FROM analytics_events WHERE ${SIGNED_IN_ACTIVITY_FILTER} AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} GROUP BY ${EVENT_DATE_SQL}, ${TEMPLATE_EXPR} ORDER BY date, template`;
|
|
575
576
|
export const PRE_MARKETING_SITE_DAU_BY_TEMPLATE_SQL = `SELECT ${EVENT_DATE_SQL} AS date, ${TEMPLATE_EXPR} AS template, COUNT(DISTINCT user_key) AS visitors FROM analytics_events WHERE ${SIGNED_IN_ACTIVITY_FILTER} AND ${DASHBOARD_TIME_RANGE_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} GROUP BY ${EVENT_DATE_SQL}, ${TEMPLATE_EXPR} ORDER BY date, template`;
|
|
576
|
-
const DAU_BY_TEMPLATE_SQL =
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
577
|
+
export const DAU_BY_TEMPLATE_SQL =
|
|
578
|
+
PRE_MARKETING_SITE_DAU_BY_TEMPLATE_SQL.replace(
|
|
579
|
+
` AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} GROUP BY`,
|
|
580
|
+
` AND ${FIRST_PARTY_KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER} GROUP BY`,
|
|
581
|
+
);
|
|
580
582
|
export const LEGACY_WAU_BY_TEMPLATE_SQL = `WITH base AS (SELECT ${SIGNED_IN_ACTIVITY_KEY_SQL} AS visitor_key, ${TEMPLATE_EXPR} AS template, ${EVENT_DATE_SQL} AS event_date, user_id FROM analytics_events WHERE ${SIGNED_IN_ACTIVITY_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${DASHBOARD_WAU_BASE_RANGE_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.visitor_key) AS visitors 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`;
|
|
581
583
|
export const PRE_MARKETING_SITE_WAU_BY_TEMPLATE_SQL = `WITH base AS (SELECT user_key AS visitor_key, ${TEMPLATE_EXPR} AS template, ${EVENT_DATE_SQL} AS event_date, user_id FROM analytics_events WHERE ${SIGNED_IN_ACTIVITY_FILTER} AND ${DASHBOARD_EMAIL_FILTER} AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${DASHBOARD_WAU_BASE_RANGE_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.visitor_key) AS visitors 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`;
|
|
582
584
|
const WAU_BY_TEMPLATE_SQL = PRE_MARKETING_SITE_WAU_BY_TEMPLATE_SQL.replace(
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "@agent-native/core/db/schema";
|
|
9
9
|
import { recordChange } from "@agent-native/core/server";
|
|
10
10
|
import { listOrgSettings } from "@agent-native/core/settings";
|
|
11
|
-
import { eq, inArray } from "drizzle-orm";
|
|
11
|
+
import { and, eq, inArray, isNull } from "drizzle-orm";
|
|
12
12
|
|
|
13
13
|
import { getDb, schema } from "../db/index.js";
|
|
14
14
|
|
|
@@ -750,6 +750,7 @@ export async function migrateAnalyticsArtifacts(
|
|
|
750
750
|
}
|
|
751
751
|
await db.transaction(async (tx: any) => {
|
|
752
752
|
for (const row of state.dashboards) {
|
|
753
|
+
const createdBy = row.visibility === "private" ? row.ownerEmail : null;
|
|
753
754
|
await tx
|
|
754
755
|
.insert(schema.dashboards)
|
|
755
756
|
.values({
|
|
@@ -761,6 +762,7 @@ export async function migrateAnalyticsArtifacts(
|
|
|
761
762
|
orgId: row.orgId,
|
|
762
763
|
visibility: row.visibility,
|
|
763
764
|
createdAt: row.createdAt,
|
|
765
|
+
createdBy,
|
|
764
766
|
updatedAt: row.updatedAt,
|
|
765
767
|
updatedBy: ctx.userEmail,
|
|
766
768
|
archivedAt: row.archivedAt,
|
|
@@ -768,6 +770,18 @@ export async function migrateAnalyticsArtifacts(
|
|
|
768
770
|
hiddenBy: null,
|
|
769
771
|
})
|
|
770
772
|
.onConflictDoNothing();
|
|
773
|
+
if (createdBy) {
|
|
774
|
+
await tx
|
|
775
|
+
.update(schema.dashboards)
|
|
776
|
+
.set({ createdBy })
|
|
777
|
+
.where(
|
|
778
|
+
and(
|
|
779
|
+
eq(schema.dashboards.id, row.id),
|
|
780
|
+
eq(schema.dashboards.orgId, row.orgId),
|
|
781
|
+
isNull(schema.dashboards.createdBy),
|
|
782
|
+
),
|
|
783
|
+
);
|
|
784
|
+
}
|
|
771
785
|
}
|
|
772
786
|
for (const row of state.analyses) {
|
|
773
787
|
await tx
|
|
@@ -930,6 +944,8 @@ export async function migrateAnalyticsArtifacts(
|
|
|
930
944
|
orgId: analysis.orgId,
|
|
931
945
|
visibility: analysis.visibility,
|
|
932
946
|
createdAt: analysis.createdAt,
|
|
947
|
+
createdBy:
|
|
948
|
+
analysis.visibility === "private" ? analysis.ownerEmail : null,
|
|
933
949
|
updatedAt: now,
|
|
934
950
|
updatedBy: ctx.userEmail,
|
|
935
951
|
hiddenAt: analysis.hiddenAt,
|
|
@@ -994,6 +1010,8 @@ export async function migrateAnalyticsArtifacts(
|
|
|
994
1010
|
orgId: extension.orgId,
|
|
995
1011
|
visibility: extension.visibility,
|
|
996
1012
|
createdAt: extension.createdAt,
|
|
1013
|
+
createdBy:
|
|
1014
|
+
extension.visibility === "private" ? extension.ownerEmail : null,
|
|
997
1015
|
updatedAt: now,
|
|
998
1016
|
updatedBy: ctx.userEmail,
|
|
999
1017
|
hiddenAt: extension.hiddenAt,
|