@agent-native/core 0.175.4 → 0.175.5-nightly-20260827014436

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/corpus/templates/analytics/actions/get-explorer-dashboard.ts +1 -0
  2. package/corpus/templates/analytics/app/components/auth/AuthProvider.tsx +8 -6
  3. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +32 -0
  4. package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -1
  5. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +66 -7
  6. package/corpus/templates/analytics/app/lib/prefetch-keys.ts +10 -0
  7. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +9 -7
  8. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +10 -11
  9. package/corpus/templates/analytics/changelog/2026-08-24-feature-flag-changes-recover-from-temporary-workspace-direct.md +6 -0
  10. package/corpus/templates/analytics/changelog/2026-08-26-analytics-distinguishes-daily-from-weekly-activity-shows-sta.md +6 -0
  11. package/corpus/templates/analytics/changelog/2026-08-26-dashboard-metadata-now-shows-the-original-creator-separately.md +6 -0
  12. package/corpus/templates/analytics/changelog/2026-08-26-dashboard-names-stay-editable-when-the-analytics-sidebar-ref.md +6 -0
  13. package/corpus/templates/analytics/changelog/2026-08-26-fixed-the-agent-re-asking-dashboard-scope-questions-you-had-.md +6 -0
  14. package/corpus/templates/analytics/server/db/schema.ts +2 -0
  15. package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +8 -2
  16. package/corpus/templates/analytics/server/lib/dashboards-store.ts +5 -0
  17. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +6 -4
  18. package/corpus/templates/analytics/server/lib/migrate-analytics-artifacts.ts +19 -1
  19. package/corpus/templates/analytics/server/lib/workspace-feature-flags.ts +40 -9
  20. package/corpus/templates/analytics/server/plugins/db.ts +10 -0
  21. package/corpus/templates/analytics/server/routes/api/dashboard-agent-context.json.get.ts +1 -0
  22. package/corpus/templates/analytics/shared/feature-flags.ts +11 -1
  23. package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +2 -9
  24. package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +8 -7
  25. package/corpus/templates/clips/.agents/skills/recording/SKILL.md +9 -8
  26. package/corpus/templates/clips/actions/import-loom-recording.ts +1 -1
  27. package/corpus/templates/clips/actions/lib/loom-import-job.ts +52 -35
  28. package/corpus/templates/clips/actions/request-transcript.ts +6 -183
  29. package/corpus/templates/clips/app/components/clips-avatar.tsx +46 -0
  30. package/corpus/templates/clips/app/components/library/recording-card.tsx +8 -7
  31. package/corpus/templates/clips/app/components/library/space-card.tsx +8 -5
  32. package/corpus/templates/clips/app/components/meetings/attendee-stack.tsx +7 -8
  33. package/corpus/templates/clips/app/components/meetings/transcript-bubbles.tsx +19 -12
  34. package/corpus/templates/clips/app/components/player/transcript-panel.tsx +128 -94
  35. package/corpus/templates/clips/app/components/recorder/microphone-visualizer.tsx +25 -104
  36. package/corpus/templates/clips/app/components/workspace/members-list.tsx +8 -6
  37. package/corpus/templates/clips/app/components/workspace/notifications-list.tsx +8 -6
  38. package/corpus/templates/clips/app/components/workspace/top-creators-table.tsx +8 -6
  39. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +8 -7
  40. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +0 -26
  41. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -4
  42. package/corpus/templates/clips/changelog/2026-08-26-detected-calls-no-longer-duplicate-meetings-or-strand-the-prompt.md +6 -0
  43. package/corpus/templates/clips/desktop/src/app.tsx +8 -10
  44. package/corpus/templates/clips/desktop/src/components/live-waveform.tsx +99 -0
  45. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +248 -55
  46. package/corpus/templates/clips/desktop/src/lib/agent-steps.ts +477 -0
  47. package/corpus/templates/clips/desktop/src/lib/ask-sheet-layout.ts +71 -0
  48. package/corpus/templates/clips/desktop/src/lib/meeting-ask.ts +297 -0
  49. package/corpus/templates/clips/desktop/src/lib/url.ts +24 -0
  50. package/corpus/templates/clips/desktop/src/overlays/ask-steps.tsx +155 -0
  51. package/corpus/templates/clips/desktop/src/overlays/flow-bar.tsx +7 -81
  52. package/corpus/templates/clips/desktop/src/overlays/live-transcript.tsx +29 -2
  53. package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +80 -22
  54. package/corpus/templates/clips/desktop/src/overlays/record-pill.tsx +13 -53
  55. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +1017 -82
  56. package/corpus/templates/clips/desktop/src/styles.css +796 -57
  57. package/corpus/templates/clips/desktop/src/tailwind.css +23 -2
  58. package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +1765 -219
  59. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +6 -0
  60. package/corpus/templates/clips/desktop/src-tauri/src/meetings_watcher.rs +45 -30
  61. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +5 -3
  62. package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +91 -0
  63. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +123 -27
  64. package/corpus/templates/clips/server/routes/_agent-native/google/callback.get.ts +16 -0
  65. package/corpus/templates/clips/shared/audio-meter.ts +145 -0
  66. package/corpus/templates/clips/shared/clips-ai-prefs.ts +0 -1
  67. package/corpus/templates/clips/shared/live-waveform.tsx +119 -0
  68. package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +44 -22
  69. package/corpus/templates/content/app/components/ui/avatar.tsx +1 -0
  70. package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +4 -1
  71. package/corpus/templates/design/app/hooks/use-question-flow.ts +9 -2
  72. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +111 -37
  73. package/corpus/templates/design/changelog/2026-08-26-design-no-longer-asks-users-to-confirm-guided-questions-they-have-already-answered.md +6 -0
  74. package/corpus/templates/dispatch/changelog/2026-08-26-signing-out-goes-straight-to-the-sign-in-page.md +5 -0
  75. package/corpus/templates/dispatch/server/lib/org-apps-directory.ts +96 -47
  76. package/corpus/templates/dispatch/server/plugins/org-apps-directory.ts +73 -29
  77. package/corpus/templates/factory/.env.example +6 -2
  78. package/corpus/templates/factory/AGENTS.md +3 -3
  79. package/corpus/templates/factory/README.md +4 -2
  80. package/corpus/templates/factory/server/connectors/credentials.ts +70 -4
  81. package/corpus/templates/mail/actions/get-email.ts +68 -21
  82. package/corpus/templates/mail/actions/get-thread.ts +92 -51
  83. package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +2 -9
  84. package/corpus/templates/mail/app/hooks/use-emails.ts +7 -4
  85. package/corpus/templates/mail/server/lib/mail-connector-catalog.ts +7 -4
  86. package/corpus/templates/plan/app/pages/PlansPage.tsx +23 -15
  87. package/corpus/templates/slides/actions/add-deck.ts +20 -0
  88. package/corpus/templates/slides/actions/create-deck.ts +17 -7
  89. package/corpus/templates/slides/actions/delete-deck.ts +45 -5
  90. package/corpus/templates/slides/actions/get-deck.ts +77 -11
  91. package/corpus/templates/slides/actions/patch-deck.ts +14 -2
  92. package/corpus/templates/slides/actions/save-deck.ts +20 -0
  93. package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +18 -7
  94. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +38 -14
  95. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +2 -2
  96. package/corpus/templates/slides/app/components/ui/avatar.tsx +1 -0
  97. package/corpus/templates/slides/server/handlers/decks.ts +10 -0
  98. package/corpus/templates/slides/shared/slide-ids.ts +133 -0
  99. package/corpus/templates/tasks/DEVELOPING.md +8 -0
  100. package/corpus/templates/tasks/drizzle.config.ts +3 -1
  101. package/corpus/templates/tasks/drizzle.local.config.ts +6 -0
  102. package/corpus/templates/tasks/package.json +2 -1
  103. package/corpus/templates/tasks/server/db/migrations/meta/0000_snapshot.json +234 -0
  104. package/corpus/templates/tasks/server/db/migrations/meta/_journal.json +13 -0
  105. package/corpus/templates/tasks/server/db/migrations.ts +110 -0
  106. package/corpus/templates/tasks/server/plugins/db.ts +3 -87
  107. package/dist/client/AssistantChat.js +3 -10
  108. package/dist/client/guided-questions.d.ts +11 -1
  109. package/dist/client/guided-questions.js +24 -7
  110. package/dist/client/hooks/index.d.ts +2 -1
  111. package/dist/client/hooks/index.js +2 -1
  112. package/dist/client/org/OrgSwitcher.js +3 -17
  113. package/dist/client/review/ReviewThreadPanel.js +4 -2
  114. package/dist/client/sign-out.d.ts +15 -0
  115. package/dist/client/sign-out.js +82 -0
  116. package/dist/client/use-action.d.ts +2 -0
  117. package/dist/client/use-action.js +4 -2
  118. package/dist/client/use-session.d.ts +23 -1
  119. package/dist/client/use-session.js +46 -0
  120. package/dist/collab/client.js +20 -5
  121. package/dist/collab/presence.d.ts +3 -1
  122. package/dist/collab/presence.js +48 -45
  123. package/dist/collab/routes.d.ts +1 -1
  124. package/dist/db/drizzle-config.d.ts +7 -0
  125. package/dist/db/drizzle-config.js +35 -9
  126. package/dist/db/drizzle-migrations.d.ts +28 -0
  127. package/dist/db/drizzle-migrations.js +81 -0
  128. package/dist/db/index.d.ts +1 -1
  129. package/dist/db/migrations.d.ts +13 -1
  130. package/dist/db/migrations.js +60 -31
  131. package/dist/db/schema.js +4 -1
  132. package/dist/deploy/build.d.ts +6 -0
  133. package/dist/deploy/build.js +41 -0
  134. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  135. package/dist/mcp/index.d.ts +1 -1
  136. package/dist/mcp/index.js +1 -1
  137. package/dist/mcp/org-directory.d.ts +19 -7
  138. package/dist/mcp/org-directory.js +92 -68
  139. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  140. package/dist/notifications/routes.d.ts +3 -3
  141. package/dist/org/context.d.ts +6 -0
  142. package/dist/org/context.js +22 -0
  143. package/dist/org/index.d.ts +1 -1
  144. package/dist/org/index.js +1 -1
  145. package/dist/resources/store.d.ts +12 -0
  146. package/dist/resources/store.js +55 -0
  147. package/dist/server/agent-discovery.d.ts +18 -2
  148. package/dist/server/agent-discovery.js +191 -22
  149. package/dist/server/auth.js +3 -2
  150. package/dist/server/builder-browser.d.ts +0 -4
  151. package/dist/server/builder-browser.js +23 -8
  152. package/dist/server/google-oauth.d.ts +18 -0
  153. package/dist/server/google-oauth.js +3 -3
  154. package/dist/server/onboarding-html.js +3 -3
  155. package/dist/server/poll.d.ts +4 -2
  156. package/dist/server/poll.js +8 -3
  157. package/dist/server/realtime-token.d.ts +1 -1
  158. package/dist/server/short-lived-token.d.ts +1 -1
  159. package/dist/server/short-lived-token.js +1 -1
  160. package/dist/shared/environment-lanes.d.ts +1 -0
  161. package/dist/shared/environment-lanes.js +1 -0
  162. package/dist/shared/google-profile-image.d.ts +2 -0
  163. package/dist/shared/google-profile-image.js +24 -0
  164. package/dist/shared/index.d.ts +1 -0
  165. package/dist/shared/index.js +1 -0
  166. package/dist/styles/agent-conversation.css +13 -0
  167. package/docs/content/creating-templates.mdx +10 -1
  168. package/docs/content/server-database.mdx +49 -3
  169. package/docs/content/server-plugins.mdx +39 -3
  170. package/docs/content/webmcp.mdx +2 -0
  171. package/package.json +2 -1
  172. package/corpus/templates/analytics/data/explorer-configs/_autosave.json +0 -18
  173. package/corpus/templates/analytics/data/explorer-configs/steve-chart.json +0 -18
  174. package/corpus/templates/analytics/data/explorer-dashboards/dashboard-1773260837897.json +0 -10
  175. package/corpus/templates/analytics/data/sync-config.json +0 -8
  176. package/corpus/templates/brain/data/sync-config.json +0 -1
  177. package/corpus/templates/calendar/data/availability.json +0 -32
  178. package/corpus/templates/calendar/data/settings.json +0 -6
  179. package/corpus/templates/calendar/data/sync-config.json +0 -10
  180. package/corpus/templates/chat/data/sync-config.json +0 -1
  181. package/corpus/templates/clips/data/sync-config.json +0 -1
  182. package/corpus/templates/clips/desktop/src/lib/audio-meter.ts +0 -80
  183. package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +0 -113
  184. package/corpus/templates/design/data/sync-config.json +0 -1
  185. package/corpus/templates/factory/data/sync-config.json +0 -1
  186. package/corpus/templates/forms/data/settings.json +0 -8
  187. package/corpus/templates/forms/data/sync-config.json +0 -3
  188. package/corpus/templates/macros/data/sync-config.json +0 -4
  189. package/corpus/templates/mail/data/emails.defaults.json +0 -1
  190. package/corpus/templates/mail/data/labels.defaults.json +0 -59
  191. package/corpus/templates/mail/data/settings.defaults.json +0 -9
  192. package/corpus/templates/mail/data/sync-config.json +0 -8
  193. package/corpus/templates/slides/data/sync-config.json +0 -8
  194. package/corpus/templates/tasks/data/sync-config.json +0 -1
  195. package/dist/templates/chat/data/.gitkeep +0 -0
  196. package/dist/templates/chat/data/sync-config.json +0 -1
  197. package/dist/templates/default/data/.gitkeep +0 -0
  198. package/dist/templates/default/data/sync-config.json +0 -1
  199. package/src/templates/chat/data/.gitkeep +0 -0
  200. package/src/templates/chat/data/sync-config.json +0 -1
  201. package/src/templates/default/data/.gitkeep +0 -0
  202. package/src/templates/default/data/sync-config.json +0 -1
@@ -34,6 +34,7 @@ export default defineAction({
34
34
  orgId: dash.orgId,
35
35
  visibility: dash.visibility,
36
36
  createdAt: dash.createdAt,
37
+ createdBy: dash.createdBy,
37
38
  updatedAt: dash.updatedAt,
38
39
  updatedBy: dash.updatedBy,
39
40
  role: dash.role,
@@ -1,5 +1,8 @@
1
- import { agentNativePath } from "@agent-native/core/client/api-path";
2
- import { useSession, type AuthSession } from "@agent-native/core/client/hooks";
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
- fetch(agentNativePath("/_agent-native/auth/logout"), {
21
- method: "POST",
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 and only ask another question if a required source/table/metric is still genuinely ambiguous.",
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 side="right" align="start" className="w-44">
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
- setIsRenaming(true);
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 = dashboardCacheScope(auth);
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
- useState<SidebarVisibilityFilter>("private");
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={setDashFilter}
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 [dashboardOwner, setDashboardOwner] = useState<string | null>(null);
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
- setDashboardOwner(null);
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
- setDashboardOwner(d.ownerEmail);
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
- setDashboardOwner(null);
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={dashboardOwner}
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 [dashboardOwner, setDashboardOwner] = useState<string | null>(null);
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
- setDashboardOwner(null);
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
- setDashboardOwner(fetched?.ownerEmail ?? null);
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
- const result = (await hideDashboardAction({
1687
+ await hideDashboardAction({
1686
1688
  id: dashboardId,
1687
1689
  hidden: false,
1688
- })) as { ownerEmail?: string | null } | undefined;
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={dashboardOwner}
1954
+ createdBy={dashboardCreatedBy}
1956
1955
  updatedAt={dashboardUpdatedAt}
1957
1956
  updatedBy={dashboardUpdatedBy}
1958
1957
  />
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-24
4
+ ---
5
+
6
+ Feature flag management recovers from temporary workspace directory failures, while directory reads avoid slow per-app database lookups
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-26
4
+ ---
5
+
6
+ Analytics distinguishes daily from weekly activity, shows stacked totals in chart tooltips, and remembers dashboard visibility.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-26
4
+ ---
5
+
6
+ Dashboard metadata now shows the original creator separately from the current owner
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-26
4
+ ---
5
+
6
+ Dashboard names stay editable when the Analytics sidebar refreshes
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-26
4
+ ---
5
+
6
+ Fixed the agent re-asking dashboard scope questions you had already answered
@@ -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 ? base : { ...base, ...config };
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 ? base : { ...base, ...seed };
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 = PRE_MARKETING_SITE_DAU_BY_TEMPLATE_SQL.replace(
577
- ` AND ${KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} GROUP BY`,
578
- ` AND ${FIRST_PARTY_KNOWN_PRODUCT_ACTIVITY_TEMPLATE_FILTER} AND ${MARKETING_SITE_TEMPLATE_FILTER} GROUP BY`,
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,