@agent-native/core 0.79.21 → 0.79.22
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 +2 -2
- package/corpus/core/CHANGELOG.md +10 -0
- package/corpus/core/docs/content/deployment.md +82 -82
- package/corpus/core/docs/content/faq.md +1 -1
- package/corpus/core/docs/content/tracking.md +3 -3
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/engine/openai-compatible-endpoint.ts +25 -0
- package/corpus/core/src/agent/engine/provider-env-vars.ts +2 -0
- package/corpus/core/src/agent/engine/registry.ts +59 -11
- package/corpus/core/src/client/FeedbackButton.tsx +11 -1
- package/corpus/core/src/client/agent-engine-key.ts +57 -10
- package/corpus/core/src/client/analytics.ts +78 -27
- package/corpus/core/src/client/blocks/library/HighlightedCode.tsx +1 -1
- package/corpus/core/src/client/index.ts +2 -0
- package/corpus/core/src/client/session-replay.ts +159 -17
- package/corpus/core/src/client/settings/SettingsPanel.tsx +119 -4
- package/corpus/core/src/scripts/agent-engines/manage-agent-engine.ts +5 -0
- package/corpus/core/src/scripts/agent-engines/set-agent-engine.ts +8 -3
- package/corpus/core/src/scripts/agent-engines/test-agent-engine.ts +54 -6
- package/corpus/core/src/server/agent-engine-api-key-route.ts +83 -12
- package/corpus/core/src/server/core-routes-plugin.ts +26 -2
- package/corpus/core/src/styles/blocks.css +23 -7
- package/corpus/templates/analytics/actions/list-session-recordings.ts +1 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +22 -4
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +64 -50
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +38 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-sync.ts +89 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +138 -59
- package/corpus/templates/analytics/changelog/2026-06-27-dashboard-charts-drag-smoothly-when-rearranging-panels.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-27-dashboard-email-reports-still-send-when-the-live-screenshot-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-27-fixed-dashboard-edits-so-charts-no-longer-briefly-snap-back-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +1 -0
- package/corpus/templates/analytics/changelog/2026-06-27-session-replay-lists-now-show-only-signed-in-recordings-with.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-27-sidebar-loading-placeholders-are-visible-in-light-mode.md +6 -0
- package/corpus/templates/analytics/netlify.toml +4 -0
- package/corpus/templates/analytics/scripts/seed-session-replay.ts +1 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +1 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +120 -29
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +1 -1
- package/corpus/templates/analytics/server/lib/session-replay.ts +158 -46
- package/corpus/templates/assets/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +1 -0
- package/corpus/templates/clips/app/components/capture-install-options.tsx +0 -9
- package/corpus/templates/clips/changelog/2026-06-27-clips-no-longer-shows-desktop-app-prompts-on-mobile-screens.md +1 -0
- package/corpus/templates/clips/changelog/2026-06-27-recorder-download-options-now-show-the-chrome-extension-and-.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-27-recorder-setup-mobile-capture-options.md +1 -0
- package/corpus/templates/clips/chrome-extension/package.json +1 -1
- package/corpus/templates/clips/chrome-extension/src/sentry.ts +17 -1
- package/corpus/templates/clips/desktop/package.json +1 -0
- package/corpus/templates/clips/desktop/scripts/check-tauri-prereqs.mjs +45 -0
- package/corpus/templates/clips/desktop/src/lib/sentry.ts +71 -0
- package/corpus/templates/clips/desktop/src/main.tsx +2 -0
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +2 -1
- package/corpus/templates/clips/desktop/src-tauri/build.rs +29 -0
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +3 -0
- package/corpus/templates/clips/desktop/src-tauri/src/logfile.rs +1 -0
- package/corpus/templates/clips/desktop/src-tauri/src/sentry_report.rs +142 -0
- package/corpus/templates/clips/desktop/vite.config.ts +66 -0
- package/corpus/templates/design/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +1 -0
- package/corpus/templates/forms/actions/export-responses.ts +3 -2
- package/corpus/templates/forms/actions/list-responses.ts +2 -1
- package/corpus/templates/forms/actions/response-insights.ts +13 -4
- package/corpus/templates/forms/changelog/2026-06-27-anonymous-feedback-no-longer-shows-internal-agent-native-ano.md +6 -0
- package/corpus/templates/forms/server/handlers/submissions.ts +5 -8
- package/corpus/templates/forms/server/lib/integrations.ts +9 -6
- package/corpus/templates/forms/shared/submitter-email.ts +20 -0
- package/corpus/templates/forms/shared/types.ts +1 -1
- package/corpus/templates/plan/app/components/plan/wireframe/html-artboard.css +49 -10
- package/corpus/templates/slides/changelog/2026-06-27-mobile-navigation-chrome-and-motion.md +1 -0
- package/dist/agent/engine/openai-compatible-endpoint.d.ts +3 -0
- package/dist/agent/engine/openai-compatible-endpoint.d.ts.map +1 -0
- package/dist/agent/engine/openai-compatible-endpoint.js +23 -0
- package/dist/agent/engine/openai-compatible-endpoint.js.map +1 -0
- package/dist/agent/engine/provider-env-vars.d.ts +1 -0
- package/dist/agent/engine/provider-env-vars.d.ts.map +1 -1
- package/dist/agent/engine/provider-env-vars.js +1 -0
- package/dist/agent/engine/provider-env-vars.js.map +1 -1
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +39 -12
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/client/FeedbackButton.d.ts.map +1 -1
- package/dist/client/FeedbackButton.js +6 -1
- package/dist/client/FeedbackButton.js.map +1 -1
- package/dist/client/agent-engine-key.d.ts +14 -0
- package/dist/client/agent-engine-key.d.ts.map +1 -1
- package/dist/client/agent-engine-key.js +35 -10
- package/dist/client/agent-engine-key.js.map +1 -1
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +71 -24
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/blocks/library/HighlightedCode.d.ts +1 -1
- package/dist/client/blocks/library/HighlightedCode.js +1 -1
- package/dist/client/blocks/library/HighlightedCode.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/session-replay.d.ts +1 -1
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +115 -17
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +42 -6
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +7 -7
- package/dist/progress/routes.d.ts +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.d.ts.map +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.js +4 -0
- package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.d.ts.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.js +5 -4
- package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
- package/dist/scripts/agent-engines/test-agent-engine.d.ts.map +1 -1
- package/dist/scripts/agent-engines/test-agent-engine.js +37 -5
- package/dist/scripts/agent-engines/test-agent-engine.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +4 -4
- package/dist/server/agent-engine-api-key-route.d.ts.map +1 -1
- package/dist/server/agent-engine-api-key-route.js +71 -11
- package/dist/server/agent-engine-api-key-route.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +20 -3
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/styles/blocks.css +23 -7
- package/docs/content/deployment.md +82 -82
- package/docs/content/faq.md +1 -1
- package/docs/content/tracking.md +3 -3
- package/package.json +1 -1
|
@@ -25,7 +25,6 @@ import {
|
|
|
25
25
|
type DragOverEvent,
|
|
26
26
|
type DragStartEvent,
|
|
27
27
|
type CollisionDetection,
|
|
28
|
-
type Collision,
|
|
29
28
|
} from "@dnd-kit/core";
|
|
30
29
|
import {
|
|
31
30
|
IconArchive,
|
|
@@ -105,16 +104,22 @@ import {
|
|
|
105
104
|
import BlankDashboard from "../BlankDashboard";
|
|
106
105
|
import { DashboardSkeleton } from "../DashboardSkeleton";
|
|
107
106
|
import {
|
|
107
|
+
availableDropSlotIdsForPanel,
|
|
108
108
|
buildDashboardPanelGroups,
|
|
109
109
|
distanceFromPointerToRect,
|
|
110
110
|
dropSlotId,
|
|
111
|
-
isDropSlotAvailable,
|
|
112
111
|
movePanelToDropSlot,
|
|
113
112
|
readDropSlot,
|
|
114
113
|
removePanelFromLayout,
|
|
115
114
|
sameDropSlot,
|
|
116
115
|
type DashboardDropSlot,
|
|
117
116
|
} from "./dashboard-layout";
|
|
117
|
+
import {
|
|
118
|
+
createDashboardAdoptionHold,
|
|
119
|
+
dashboardPrefetchInitialData,
|
|
120
|
+
shouldAdoptDashboardQueryResult,
|
|
121
|
+
type DashboardAdoptionHold,
|
|
122
|
+
} from "./dashboard-sync";
|
|
118
123
|
import {
|
|
119
124
|
DashboardFilterBar,
|
|
120
125
|
FILTER_PARAM_PREFIX,
|
|
@@ -165,6 +170,31 @@ function groupDashboardTabs(tabs: string[]): {
|
|
|
165
170
|
return { groups, hasNestedTabs };
|
|
166
171
|
}
|
|
167
172
|
|
|
173
|
+
function parseReportPanelLimit(raw: string | null): number | null {
|
|
174
|
+
if (!raw) return null;
|
|
175
|
+
const parsed = Number.parseInt(raw, 10);
|
|
176
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return null;
|
|
177
|
+
return Math.min(50, parsed);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function limitReportPanels(panels: SqlPanel[], limit: number | null) {
|
|
181
|
+
if (!limit) return panels;
|
|
182
|
+
const limited: SqlPanel[] = [];
|
|
183
|
+
let chartCount = 0;
|
|
184
|
+
|
|
185
|
+
for (const panel of panels) {
|
|
186
|
+
if (panel.chartType === "section") {
|
|
187
|
+
if (chartCount < limit) limited.push(panel);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (chartCount >= limit) continue;
|
|
191
|
+
chartCount++;
|
|
192
|
+
limited.push(panel);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return limited;
|
|
196
|
+
}
|
|
197
|
+
|
|
168
198
|
function DashboardDropLine({
|
|
169
199
|
slot,
|
|
170
200
|
activeSlot,
|
|
@@ -220,6 +250,7 @@ const PanelCell = memo(function PanelCell({
|
|
|
220
250
|
remoteEditor,
|
|
221
251
|
editable,
|
|
222
252
|
eagerLoad,
|
|
253
|
+
isDragSource,
|
|
223
254
|
onRemovePanel,
|
|
224
255
|
onEditPanel,
|
|
225
256
|
onSavePanel,
|
|
@@ -229,6 +260,7 @@ const PanelCell = memo(function PanelCell({
|
|
|
229
260
|
remoteEditor: { color: string; name: string } | undefined;
|
|
230
261
|
editable: boolean;
|
|
231
262
|
eagerLoad: boolean;
|
|
263
|
+
isDragSource: boolean;
|
|
232
264
|
onRemovePanel: (panelId: string) => void;
|
|
233
265
|
onEditPanel: (panel: SqlPanel) => void;
|
|
234
266
|
onSavePanel: (panel: SqlPanel) => Promise<void>;
|
|
@@ -283,6 +315,7 @@ const PanelCell = memo(function PanelCell({
|
|
|
283
315
|
onSaveSql={(sql) => onSavePanel({ ...panel, sql })}
|
|
284
316
|
editable={editable}
|
|
285
317
|
eagerLoad={eagerLoad}
|
|
318
|
+
isDragSource={isDragSource}
|
|
286
319
|
/>
|
|
287
320
|
</div>
|
|
288
321
|
);
|
|
@@ -394,11 +427,13 @@ export default function SqlDashboardPage() {
|
|
|
394
427
|
const navigate = useNavigate();
|
|
395
428
|
const dashboardId = searchParams.get("id") || routeId;
|
|
396
429
|
const reportScreenshot = searchParams.get("reportScreenshot") === "1";
|
|
430
|
+
const reportPanelLimit = reportScreenshot
|
|
431
|
+
? parseReportPanelLimit(searchParams.get("reportPanelLimit"))
|
|
432
|
+
: null;
|
|
397
433
|
|
|
398
434
|
const [dashboard, setDashboard] = useState<SqlDashboardConfig | null>(null);
|
|
399
435
|
const [archivedAt, setArchivedAt] = useState<string | null>(null);
|
|
400
436
|
const [hiddenAt, setHiddenAt] = useState<string | null>(null);
|
|
401
|
-
const [hiddenBy, setHiddenBy] = useState<string | null>(null);
|
|
402
437
|
const [dashboardVisibility, setDashboardVisibility] = useState<
|
|
403
438
|
"private" | "org" | "public" | null
|
|
404
439
|
>(null);
|
|
@@ -422,6 +457,7 @@ export default function SqlDashboardPage() {
|
|
|
422
457
|
null,
|
|
423
458
|
);
|
|
424
459
|
const viewedDashboardIdRef = useRef<string | null>(null);
|
|
460
|
+
const pendingConfigRef = useRef<DashboardAdoptionHold | null>(null);
|
|
425
461
|
const canEdit = !reportScreenshot && resourceCanEdit(resourceAccess);
|
|
426
462
|
const canManage = !reportScreenshot && resourceCanManage(resourceAccess);
|
|
427
463
|
const dashboardColumns = clampDashboardColumns(
|
|
@@ -462,10 +498,7 @@ export default function SqlDashboardPage() {
|
|
|
462
498
|
const snapshot = queryClient.getQueryData<
|
|
463
499
|
PrefetchSnapshot<FetchedDashboard | null>
|
|
464
500
|
>(sqlDashboardPrefetchKey(dashboardId));
|
|
465
|
-
|
|
466
|
-
return undefined;
|
|
467
|
-
}
|
|
468
|
-
return snapshot?.data;
|
|
501
|
+
return dashboardPrefetchInitialData(snapshot, sync);
|
|
469
502
|
},
|
|
470
503
|
initialDataUpdatedAt: () => {
|
|
471
504
|
if (!dashboardId) return undefined;
|
|
@@ -475,7 +508,7 @@ export default function SqlDashboardPage() {
|
|
|
475
508
|
queryKey,
|
|
476
509
|
);
|
|
477
510
|
if (!snapshot) return undefined;
|
|
478
|
-
if (snapshot.syncVersion !== sync) return
|
|
511
|
+
if (snapshot.syncVersion !== sync) return undefined;
|
|
479
512
|
return queryClient.getQueryState(queryKey)?.dataUpdatedAt;
|
|
480
513
|
},
|
|
481
514
|
});
|
|
@@ -510,6 +543,36 @@ export default function SqlDashboardPage() {
|
|
|
510
543
|
user: currentUser,
|
|
511
544
|
});
|
|
512
545
|
|
|
546
|
+
const updateCachedDashboardConfig = useCallback(
|
|
547
|
+
(updated: SqlDashboardConfig) => {
|
|
548
|
+
if (!dashboardId) return;
|
|
549
|
+
queryClient.setQueriesData<FetchedDashboard | null>(
|
|
550
|
+
{ queryKey: ["data", "sql-dashboard", dashboardId] },
|
|
551
|
+
(prev) => (prev ? { ...prev, config: updated } : prev),
|
|
552
|
+
);
|
|
553
|
+
queryClient.setQueryData<PrefetchSnapshot<FetchedDashboard | null>>(
|
|
554
|
+
sqlDashboardPrefetchKey(dashboardId),
|
|
555
|
+
(prev) =>
|
|
556
|
+
prev?.data
|
|
557
|
+
? { ...prev, data: { ...prev.data, config: updated } }
|
|
558
|
+
: prev,
|
|
559
|
+
);
|
|
560
|
+
},
|
|
561
|
+
[dashboardId, queryClient],
|
|
562
|
+
);
|
|
563
|
+
|
|
564
|
+
const holdDashboardConfig = useCallback(() => {
|
|
565
|
+
if (!dashboardId) return;
|
|
566
|
+
pendingConfigRef.current = createDashboardAdoptionHold({
|
|
567
|
+
dashboardId,
|
|
568
|
+
currentUpdatedAt: dashboardUpdatedAt,
|
|
569
|
+
});
|
|
570
|
+
void queryClient.cancelQueries(
|
|
571
|
+
{ queryKey: ["data", "sql-dashboard", dashboardId] },
|
|
572
|
+
{ revert: false },
|
|
573
|
+
);
|
|
574
|
+
}, [dashboardId, dashboardUpdatedAt, queryClient]);
|
|
575
|
+
|
|
513
576
|
// Track which panels remote users are editing (from awareness)
|
|
514
577
|
const [remoteEditingPanels, setRemoteEditingPanels] = useState<
|
|
515
578
|
Map<string, { color: string; name: string }>
|
|
@@ -548,8 +611,10 @@ export default function SqlDashboardPage() {
|
|
|
548
611
|
if (!raw) return;
|
|
549
612
|
try {
|
|
550
613
|
const parsed = JSON.parse(raw) as SqlDashboardConfig;
|
|
551
|
-
if (parsed && parsed.panels) {
|
|
614
|
+
if (parsed && Array.isArray(parsed.panels)) {
|
|
615
|
+
holdDashboardConfig();
|
|
552
616
|
setDashboard(parsed);
|
|
617
|
+
updateCachedDashboardConfig(parsed);
|
|
553
618
|
}
|
|
554
619
|
} catch {
|
|
555
620
|
// JSON parse failed — ignore partial updates
|
|
@@ -559,7 +624,7 @@ export default function SqlDashboardPage() {
|
|
|
559
624
|
return () => {
|
|
560
625
|
ytext.unobserve(handler);
|
|
561
626
|
};
|
|
562
|
-
}, [ydoc, collabSynced]);
|
|
627
|
+
}, [ydoc, collabSynced, holdDashboardConfig, updateCachedDashboardConfig]);
|
|
563
628
|
|
|
564
629
|
// Per-user saved filter state
|
|
565
630
|
const filterPrefKey = dashboardId ? `dashboard-filters:${dashboardId}` : "";
|
|
@@ -581,7 +646,6 @@ export default function SqlDashboardPage() {
|
|
|
581
646
|
setDashboard(null);
|
|
582
647
|
setArchivedAt(null);
|
|
583
648
|
setHiddenAt(null);
|
|
584
|
-
setHiddenBy(null);
|
|
585
649
|
setDashboardVisibility(null);
|
|
586
650
|
setDashboardOwner(null);
|
|
587
651
|
setDashboardUpdatedAt(null);
|
|
@@ -592,17 +656,29 @@ export default function SqlDashboardPage() {
|
|
|
592
656
|
useEffect(() => {
|
|
593
657
|
if (!dashboardId || !dashboardQuery.isSuccess) return;
|
|
594
658
|
const fetched = dashboardQuery.data;
|
|
595
|
-
|
|
659
|
+
const adoption = shouldAdoptDashboardQueryResult({
|
|
660
|
+
dashboardId,
|
|
661
|
+
loaded,
|
|
662
|
+
isPlaceholderData: dashboardQuery.isPlaceholderData,
|
|
663
|
+
fetchedId: fetched?.id,
|
|
664
|
+
fetchedUpdatedAt: fetched?.updatedAt,
|
|
665
|
+
currentUpdatedAt: dashboardUpdatedAt,
|
|
666
|
+
hold: pendingConfigRef.current,
|
|
667
|
+
});
|
|
668
|
+
if (adoption.clearHold) {
|
|
669
|
+
pendingConfigRef.current = null;
|
|
670
|
+
}
|
|
671
|
+
if (!adoption.adopt) return;
|
|
672
|
+
const fetchedConfig = fetched?.config ?? null;
|
|
596
673
|
const fetchedVisibility =
|
|
597
674
|
fetched?.visibility === "private" ||
|
|
598
675
|
fetched?.visibility === "org" ||
|
|
599
676
|
fetched?.visibility === "public"
|
|
600
677
|
? fetched.visibility
|
|
601
678
|
: null;
|
|
602
|
-
setDashboard(
|
|
679
|
+
setDashboard(fetchedConfig);
|
|
603
680
|
setArchivedAt(fetched?.archivedAt ?? null);
|
|
604
681
|
setHiddenAt(fetched?.hiddenAt ?? null);
|
|
605
|
-
setHiddenBy(fetched?.hiddenBy ?? null);
|
|
606
682
|
setDashboardVisibility(fetchedVisibility);
|
|
607
683
|
setDashboardOwner(fetched?.ownerEmail ?? null);
|
|
608
684
|
setDashboardUpdatedAt(fetched?.updatedAt ?? null);
|
|
@@ -628,6 +704,9 @@ export default function SqlDashboardPage() {
|
|
|
628
704
|
dashboardId,
|
|
629
705
|
dashboardQuery.data,
|
|
630
706
|
dashboardQuery.isSuccess,
|
|
707
|
+
dashboardQuery.isPlaceholderData,
|
|
708
|
+
dashboardUpdatedAt,
|
|
709
|
+
loaded,
|
|
631
710
|
reportScreenshot,
|
|
632
711
|
]);
|
|
633
712
|
|
|
@@ -738,24 +817,6 @@ export default function SqlDashboardPage() {
|
|
|
738
817
|
[collabDocId],
|
|
739
818
|
);
|
|
740
819
|
|
|
741
|
-
const updateCachedDashboardConfig = useCallback(
|
|
742
|
-
(updated: SqlDashboardConfig) => {
|
|
743
|
-
if (!dashboardId) return;
|
|
744
|
-
queryClient.setQueriesData<FetchedDashboard | null>(
|
|
745
|
-
{ queryKey: ["data", "sql-dashboard", dashboardId] },
|
|
746
|
-
(prev) => (prev ? { ...prev, config: updated } : prev),
|
|
747
|
-
);
|
|
748
|
-
queryClient.setQueryData<PrefetchSnapshot<FetchedDashboard | null>>(
|
|
749
|
-
sqlDashboardPrefetchKey(dashboardId),
|
|
750
|
-
(prev) =>
|
|
751
|
-
prev?.data
|
|
752
|
-
? { ...prev, data: { ...prev.data, config: updated } }
|
|
753
|
-
: prev,
|
|
754
|
-
);
|
|
755
|
-
},
|
|
756
|
-
[dashboardId, queryClient],
|
|
757
|
-
);
|
|
758
|
-
|
|
759
820
|
/**
|
|
760
821
|
* Persist without throwing — background save used for drag reorder, width
|
|
761
822
|
* toggle, title/description edits, and panel delete. If the save fails
|
|
@@ -769,6 +830,7 @@ export default function SqlDashboardPage() {
|
|
|
769
830
|
toast.error(t("sqlDashboard.viewOnly"));
|
|
770
831
|
return;
|
|
771
832
|
}
|
|
833
|
+
holdDashboardConfig();
|
|
772
834
|
setDashboard(updated);
|
|
773
835
|
updateCachedDashboardConfig(updated);
|
|
774
836
|
pushToCollab(updated);
|
|
@@ -800,6 +862,7 @@ export default function SqlDashboardPage() {
|
|
|
800
862
|
[
|
|
801
863
|
dashboardId,
|
|
802
864
|
canEdit,
|
|
865
|
+
holdDashboardConfig,
|
|
803
866
|
queryClient,
|
|
804
867
|
pushToCollab,
|
|
805
868
|
t,
|
|
@@ -817,6 +880,7 @@ export default function SqlDashboardPage() {
|
|
|
817
880
|
if (!canEdit) {
|
|
818
881
|
throw new Error(t("sqlDashboard.viewOnly"));
|
|
819
882
|
}
|
|
883
|
+
holdDashboardConfig();
|
|
820
884
|
await saveDashboard(dashboardId, updated);
|
|
821
885
|
setDashboard(updated);
|
|
822
886
|
updateCachedDashboardConfig(updated);
|
|
@@ -833,6 +897,7 @@ export default function SqlDashboardPage() {
|
|
|
833
897
|
[
|
|
834
898
|
dashboardId,
|
|
835
899
|
canEdit,
|
|
900
|
+
holdDashboardConfig,
|
|
836
901
|
queryClient,
|
|
837
902
|
pushToCollab,
|
|
838
903
|
t,
|
|
@@ -1025,9 +1090,11 @@ export default function SqlDashboardPage() {
|
|
|
1025
1090
|
// dashboard shows every panel as before.
|
|
1026
1091
|
const visiblePanels = useMemo(() => {
|
|
1027
1092
|
if (!dashboard) return [];
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1093
|
+
const tabPanels = activeTab
|
|
1094
|
+
? dashboard.panels.filter((p) => !p.tab || p.tab === activeTab)
|
|
1095
|
+
: dashboard.panels;
|
|
1096
|
+
return limitReportPanels(tabPanels, reportPanelLimit);
|
|
1097
|
+
}, [dashboard, activeTab, reportPanelLimit]);
|
|
1031
1098
|
|
|
1032
1099
|
// Group panels into "section blocks": each section starts a new block whose
|
|
1033
1100
|
// grid uses the section's `columns` (falling back to the dashboard default).
|
|
@@ -1043,17 +1110,23 @@ export default function SqlDashboardPage() {
|
|
|
1043
1110
|
: null,
|
|
1044
1111
|
[activeDragPanelId, visiblePanels],
|
|
1045
1112
|
);
|
|
1113
|
+
const activeDropSlotIds = useMemo(
|
|
1114
|
+
() =>
|
|
1115
|
+
activeDragPanelId
|
|
1116
|
+
? availableDropSlotIdsForPanel(panelGroups, activeDragPanelId)
|
|
1117
|
+
: null,
|
|
1118
|
+
[activeDragPanelId, panelGroups],
|
|
1119
|
+
);
|
|
1046
1120
|
|
|
1047
1121
|
const dashboardCollisionDetection = useCallback<CollisionDetection>(
|
|
1048
1122
|
(args) => {
|
|
1049
1123
|
const activePanelId = String(args.active.id);
|
|
1050
|
-
const
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
},
|
|
1124
|
+
const availableSlotIds =
|
|
1125
|
+
activeDragPanelId === activePanelId && activeDropSlotIds
|
|
1126
|
+
? activeDropSlotIds
|
|
1127
|
+
: availableDropSlotIdsForPanel(panelGroups, activePanelId);
|
|
1128
|
+
const droppableContainers = args.droppableContainers.filter((container) =>
|
|
1129
|
+
availableSlotIds.has(String(container.id)),
|
|
1057
1130
|
);
|
|
1058
1131
|
|
|
1059
1132
|
if (droppableContainers.length === 0) return [];
|
|
@@ -1066,29 +1139,34 @@ export default function SqlDashboardPage() {
|
|
|
1066
1139
|
|
|
1067
1140
|
if (!args.pointerCoordinates) return [];
|
|
1068
1141
|
|
|
1069
|
-
|
|
1142
|
+
let closestId: string | null = null;
|
|
1143
|
+
let closestContainer: (typeof droppableContainers)[number] | null = null;
|
|
1144
|
+
let closestValue = Number.MAX_VALUE;
|
|
1070
1145
|
for (const droppableContainer of droppableContainers) {
|
|
1071
1146
|
const rect = args.droppableRects.get(droppableContainer.id);
|
|
1072
1147
|
if (!rect) continue;
|
|
1073
1148
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
});
|
|
1149
|
+
const value = distanceFromPointerToRect(args.pointerCoordinates, rect);
|
|
1150
|
+
if (value < closestValue) {
|
|
1151
|
+
closestId = String(droppableContainer.id);
|
|
1152
|
+
closestContainer = droppableContainer;
|
|
1153
|
+
closestValue = value;
|
|
1154
|
+
}
|
|
1081
1155
|
}
|
|
1082
1156
|
|
|
1083
|
-
return
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1157
|
+
return closestId && closestContainer
|
|
1158
|
+
? [
|
|
1159
|
+
{
|
|
1160
|
+
id: closestId,
|
|
1161
|
+
data: {
|
|
1162
|
+
droppableContainer: closestContainer,
|
|
1163
|
+
value: closestValue,
|
|
1164
|
+
},
|
|
1165
|
+
},
|
|
1166
|
+
]
|
|
1167
|
+
: [];
|
|
1090
1168
|
},
|
|
1091
|
-
[panelGroups],
|
|
1169
|
+
[activeDragPanelId, activeDropSlotIds, panelGroups],
|
|
1092
1170
|
);
|
|
1093
1171
|
|
|
1094
1172
|
const handleDelete = useCallback(async () => {
|
|
@@ -1155,7 +1233,6 @@ export default function SqlDashboardPage() {
|
|
|
1155
1233
|
hidden: false,
|
|
1156
1234
|
})) as { ownerEmail?: string | null } | undefined;
|
|
1157
1235
|
setHiddenAt(null);
|
|
1158
|
-
setHiddenBy(null);
|
|
1159
1236
|
if (typeof result?.ownerEmail === "string") {
|
|
1160
1237
|
setDashboardOwner(result.ownerEmail);
|
|
1161
1238
|
}
|
|
@@ -1648,6 +1725,7 @@ export default function SqlDashboardPage() {
|
|
|
1648
1725
|
onEdit={() => openEditPanel(section)}
|
|
1649
1726
|
editable={canEdit}
|
|
1650
1727
|
eagerLoad={reportScreenshot}
|
|
1728
|
+
isDragSource={activeDragPanelId === section.id}
|
|
1651
1729
|
/>
|
|
1652
1730
|
</div>
|
|
1653
1731
|
);
|
|
@@ -1699,6 +1777,7 @@ export default function SqlDashboardPage() {
|
|
|
1699
1777
|
}
|
|
1700
1778
|
editable={canEdit}
|
|
1701
1779
|
eagerLoad={reportScreenshot}
|
|
1780
|
+
isDragSource={activeDragPanelId === panel.id}
|
|
1702
1781
|
onRemovePanel={removePanel}
|
|
1703
1782
|
onEditPanel={openEditPanel}
|
|
1704
1783
|
onSavePanel={handleSavePanel}
|
|
@@ -144,6 +144,7 @@ async function main() {
|
|
|
144
144
|
publicKey,
|
|
145
145
|
replayId: `seed-${seed.app}-${started}`,
|
|
146
146
|
sessionId: `seed-session-${seed.app}-${started}`,
|
|
147
|
+
userId: `seed-user-${index + 1}@example.com`,
|
|
147
148
|
anonymousId: `seed-anon-${index + 1}`,
|
|
148
149
|
url: `http://localhost:8080${seed.path}`,
|
|
149
150
|
app: seed.app,
|
|
@@ -11,6 +11,7 @@ const DEFAULT_MAX_REPORTS_PER_SWEEP = 5;
|
|
|
11
11
|
|
|
12
12
|
function maxReportsPerSweep(): number {
|
|
13
13
|
const raw = process.env.DASHBOARD_REPORT_SWEEP_LIMIT?.trim();
|
|
14
|
+
if (!raw && process.env.NETLIFY === "true") return 1;
|
|
14
15
|
if (!raw) return DEFAULT_MAX_REPORTS_PER_SWEEP;
|
|
15
16
|
const parsed = Number.parseInt(raw, 10);
|
|
16
17
|
return Number.isFinite(parsed) && parsed > 0
|