@mastra/playground-ui 23.0.2 → 24.0.0-alpha.0
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/CHANGELOG.md +19 -0
- package/dist/index.cjs.js +4254 -13
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.css +354 -84
- package/dist/index.es.js +4137 -16
- package/dist/index.es.js.map +1 -1
- package/dist/src/domains/logs/components/index.d.ts +6 -0
- package/dist/src/domains/logs/components/log-details-view.d.ts +12 -0
- package/dist/src/domains/logs/components/logs-error-content.d.ts +14 -0
- package/dist/src/domains/logs/components/logs-layout.d.ts +19 -0
- package/dist/src/domains/logs/components/logs-list-view.d.ts +20 -0
- package/dist/src/domains/logs/components/logs-toolbar.d.ts +13 -0
- package/dist/src/domains/logs/components/no-logs-info.d.ts +1 -0
- package/dist/src/domains/logs/hooks/index.d.ts +4 -0
- package/dist/src/domains/logs/hooks/use-logs-filter-persistence.d.ts +22 -0
- package/dist/src/domains/logs/hooks/use-logs-list-navigation.d.ts +22 -0
- package/dist/src/domains/logs/hooks/use-logs-url-state.d.ts +38 -0
- package/dist/src/domains/logs/hooks/use-logs.d.ts +1271 -0
- package/dist/src/domains/logs/index.d.ts +4 -0
- package/dist/src/domains/logs/log-filters.d.ts +109 -0
- package/dist/src/domains/logs/types.d.ts +35 -0
- package/dist/src/domains/metrics/components/bar-list.d.ts +21 -0
- package/dist/src/domains/metrics/components/date-range-selector.d.ts +1 -0
- package/dist/src/domains/metrics/components/index.d.ts +9 -0
- package/dist/src/domains/metrics/components/kpi-card-view.d.ts +9 -0
- package/dist/src/domains/metrics/components/latency-card-view.d.ts +11 -0
- package/dist/src/domains/metrics/components/metrics-utils.d.ts +15 -0
- package/dist/src/domains/metrics/components/model-usage-cost-card-view.d.ts +7 -0
- package/dist/src/domains/metrics/components/scores-card-view.d.ts +12 -0
- package/dist/src/domains/metrics/components/token-usage-by-agent-card-view.d.ts +7 -0
- package/dist/src/domains/metrics/components/traces-volume-card-view.d.ts +11 -0
- package/dist/src/domains/metrics/hooks/index.d.ts +12 -0
- package/dist/src/domains/metrics/hooks/use-agent-runs-kpi-metrics.d.ts +10 -0
- package/dist/src/domains/metrics/hooks/use-avg-score-kpi-metrics.d.ts +10 -0
- package/dist/src/domains/metrics/hooks/use-latency-metrics.d.ts +11 -0
- package/dist/src/domains/metrics/hooks/use-metrics-filters.d.ts +9 -0
- package/dist/src/domains/metrics/hooks/use-metrics.d.ts +43 -0
- package/dist/src/domains/metrics/hooks/use-model-cost-kpi-metrics.d.ts +7 -0
- package/dist/src/domains/metrics/hooks/use-model-usage-cost-metrics.d.ts +10 -0
- package/dist/src/domains/metrics/hooks/use-scores-metrics.d.ts +22 -0
- package/dist/src/domains/metrics/hooks/use-token-usage-by-agent-metrics.d.ts +9 -0
- package/dist/src/domains/metrics/hooks/use-total-tokens-kpi-metrics.d.ts +6 -0
- package/dist/src/domains/metrics/hooks/use-trace-volume-metrics.d.ts +10 -0
- package/dist/src/domains/metrics/index.d.ts +2 -0
- package/dist/src/domains/traces/components/format-hierarchical-spans.d.ts +12 -0
- package/dist/src/domains/traces/components/index.d.ts +18 -0
- package/dist/src/domains/traces/components/shared.d.ts +3 -0
- package/dist/src/domains/traces/components/span-data-panel-view.d.ts +26 -0
- package/dist/src/domains/traces/components/span-details-view.d.ts +14 -0
- package/dist/src/domains/traces/components/span-token-usage.d.ts +22 -0
- package/dist/src/domains/traces/components/timeline-expand-col.d.ts +12 -0
- package/dist/src/domains/traces/components/timeline-name-col.d.ts +15 -0
- package/dist/src/domains/traces/components/timeline-structure-sign.d.ts +5 -0
- package/dist/src/domains/traces/components/timeline-timing-col.d.ts +12 -0
- package/dist/src/domains/traces/components/trace-data-panel-view.d.ts +28 -0
- package/dist/src/domains/traces/components/trace-details-view.d.ts +18 -0
- package/dist/src/domains/traces/components/trace-keys-and-values.d.ts +16 -0
- package/dist/src/domains/traces/components/trace-timeline-span.d.ts +18 -0
- package/dist/src/domains/traces/components/trace-timeline.d.ts +15 -0
- package/dist/src/domains/traces/components/traces-error-content.d.ts +16 -0
- package/dist/src/domains/traces/components/traces-layout.d.ts +18 -0
- package/dist/src/domains/traces/components/traces-list-view.d.ts +39 -0
- package/dist/src/domains/traces/components/traces-toolbar.d.ts +19 -0
- package/dist/src/domains/traces/hooks/get-all-span-ids.d.ts +3 -0
- package/dist/src/domains/traces/hooks/index.d.ts +13 -0
- package/dist/src/domains/traces/hooks/use-entity-names.d.ts +7 -0
- package/dist/src/domains/traces/hooks/use-environments.d.ts +1 -0
- package/dist/src/domains/traces/hooks/use-service-names.d.ts +1 -0
- package/dist/src/domains/traces/hooks/use-span-detail.d.ts +46 -0
- package/dist/src/domains/traces/hooks/use-tags.d.ts +1 -0
- package/dist/src/domains/traces/hooks/use-trace-filter-persistence.d.ts +31 -0
- package/dist/src/domains/traces/hooks/use-trace-light-spans.d.ts +19 -0
- package/dist/src/domains/traces/hooks/use-trace-list-navigation.d.ts +12 -0
- package/dist/src/domains/traces/hooks/use-trace-span-navigation.d.ts +10 -0
- package/dist/src/domains/traces/hooks/use-trace-spans.d.ts +47 -0
- package/dist/src/domains/traces/hooks/use-trace-url-state.d.ts +53 -0
- package/dist/src/domains/traces/hooks/use-traces.d.ts +1549 -0
- package/dist/src/domains/traces/index.d.ts +8 -0
- package/dist/src/domains/traces/trace-filters.d.ts +121 -0
- package/dist/src/domains/traces/types.d.ts +35 -0
- package/dist/src/domains/traces/utils/group-traces-by-thread.d.ts +20 -0
- package/dist/src/domains/traces/utils/index.d.ts +2 -0
- package/dist/src/domains/traces/utils/span-utils.d.ts +15 -0
- package/dist/src/index.d.ts +3 -0
- package/package.json +12 -9
package/dist/index.es.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { X, Wand2, InfoIcon as InfoIcon$1, AlertCircle, TriangleAlert, CircleCheck, CircleX, CircleAlert, Info, CheckIcon as CheckIcon$1, CopyIcon, ShieldX, LogIn, Check, ChevronsUpDown, Search, ChevronDown, Circle, TriangleAlertIcon, SearchIcon, XIcon, TrendingUpIcon, TrendingDownIcon, EllipsisVerticalIcon, SaveIcon, Trash2Icon, ListFilterPlusIcon, ArrowLeftIcon, FilterIcon, PlusIcon, ChevronLeftIcon, ChevronRightIcon, CalendarIcon, CircleAlertIcon, ArrowRightIcon, Type, Hash, ToggleLeft, AlignLeft, Braces, List, PanelRightIcon, KeyboardIcon, AlertTriangleIcon, AlignLeftIcon, AlignJustifyIcon, ArrowUpIcon, ArrowDownIcon, ChevronsRightIcon, ClockIcon, BanIcon, ChevronRight, Folder, File, AlertTriangle, CircleXIcon, ExpandIcon, ExternalLinkIcon, Link2Icon, Ban, ListX, ChevronsLeft, ChevronsRight, ChevronLeft, Text, TextSearch, EqualNot, Equal, Plus, Component, ArrowRight, ArrowLeft } from 'lucide-react';
|
|
2
|
+
import { X, Wand2, InfoIcon as InfoIcon$1, AlertCircle, TriangleAlert, CircleCheck, CircleX, CircleAlert, Info, CheckIcon as CheckIcon$1, CopyIcon, ShieldX, LogIn, Check, ChevronsUpDown, Search, ChevronDown, Circle, TriangleAlertIcon, SearchIcon, XIcon, TrendingUpIcon, TrendingDownIcon, EllipsisVerticalIcon, SaveIcon, Trash2Icon, ListFilterPlusIcon, ArrowLeftIcon, FilterIcon, PlusIcon, ChevronLeftIcon, ChevronRightIcon, CalendarIcon, CircleAlertIcon, ArrowRightIcon, Type, Hash, ToggleLeft, AlignLeft, Braces, List, PanelRightIcon, KeyboardIcon, AlertTriangleIcon, AlignLeftIcon, AlignJustifyIcon, ArrowUpIcon, ArrowDownIcon, ChevronsRightIcon, ClockIcon, BanIcon, ChevronRight, Folder, File, AlertTriangle, CircleXIcon, ExpandIcon, ExternalLinkIcon, Link2Icon, Ban, ListX, ChevronsLeft, ChevronsRight, ChevronLeft, Text, TextSearch, EqualNot, Equal, Plus, Component, ArrowRight, ArrowLeft, BrainIcon, ArrowRightToLineIcon, CoinsIcon, ChevronsUpIcon, ChevronUpIcon, ChevronDownIcon, ChevronsDownIcon, ChevronsUpDownIcon, ChevronsDownUpIcon, CircleGaugeIcon, FileInputIcon, FileOutputIcon, BracesIcon, CircleSlashIcon } from 'lucide-react';
|
|
3
3
|
import * as React from 'react';
|
|
4
|
-
import React__default, { useState, useRef, useCallback, useSyncExternalStore, forwardRef, useMemo, useId, useEffect, Suspense, Fragment as Fragment$1 } from 'react';
|
|
4
|
+
import React__default, { useState, useRef, useCallback, useSyncExternalStore, forwardRef, useMemo, useId, useEffect, Suspense, Fragment as Fragment$1, createContext, useContext } from 'react';
|
|
5
5
|
import { Shadows, Glows, BorderColors, Colors, Sizes, FontSizes, LineHeights, BorderRadius, Spacings } from './tokens.es.js';
|
|
6
6
|
import './index.css';export { Animations } from './tokens.es.js';
|
|
7
7
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
@@ -51,6 +51,8 @@ import { isToday } from 'date-fns/isToday';
|
|
|
51
51
|
import { SearchCursor } from '@codemirror/search';
|
|
52
52
|
import { ResponsiveContainer, LineChart, CartesianGrid, XAxis, YAxis, Tooltip as Tooltip$1, Line } from 'recharts';
|
|
53
53
|
import { usePanelRef, Panel, Separator as Separator$1 } from 'react-resizable-panels';
|
|
54
|
+
import { useQuery, useInfiniteQuery, keepPreviousData } from '@tanstack/react-query';
|
|
55
|
+
import { EntityType } from '@mastra/core/observability';
|
|
54
56
|
|
|
55
57
|
const formElementSizes = {
|
|
56
58
|
sm: "h-form-sm",
|
|
@@ -12028,16 +12030,16 @@ function DataListSkeleton({ columns = "auto 1fr auto auto", numberOfRows = 3 })
|
|
|
12028
12030
|
)) });
|
|
12029
12031
|
}
|
|
12030
12032
|
|
|
12031
|
-
function toDate$
|
|
12033
|
+
function toDate$3(value) {
|
|
12032
12034
|
const date = value instanceof Date ? value : new Date(value);
|
|
12033
12035
|
return isNaN(date.getTime()) ? null : date;
|
|
12034
12036
|
}
|
|
12035
12037
|
function ScoresDataListDateCell({ timestamp }) {
|
|
12036
|
-
const date = toDate$
|
|
12038
|
+
const date = toDate$3(timestamp);
|
|
12037
12039
|
return /* @__PURE__ */ jsx(DataListCell, { height: "compact", className: "text-ui-smd text-neutral2", children: date ? isToday$1(date) ? "Today" : format(date, "MMM dd") : "-" });
|
|
12038
12040
|
}
|
|
12039
12041
|
function ScoresDataListTimeCell({ timestamp }) {
|
|
12040
|
-
const date = toDate$
|
|
12042
|
+
const date = toDate$3(timestamp);
|
|
12041
12043
|
return /* @__PURE__ */ jsx(DataListCell, { height: "compact", className: "text-ui-smd text-neutral3", children: date ? format(date, "h:mm:ss aaa") : "-" });
|
|
12042
12044
|
}
|
|
12043
12045
|
function ScoresDataListInputCell({ input }) {
|
|
@@ -12067,7 +12069,7 @@ const ScoresDataList = Object.assign(ScoresDataListRoot, {
|
|
|
12067
12069
|
ScoreCell: ScoresDataListScoreCell
|
|
12068
12070
|
});
|
|
12069
12071
|
|
|
12070
|
-
function toDate$
|
|
12072
|
+
function toDate$2(value) {
|
|
12071
12073
|
const date = value instanceof Date ? value : new Date(value);
|
|
12072
12074
|
return isNaN(date.getTime()) ? null : date;
|
|
12073
12075
|
}
|
|
@@ -12079,11 +12081,11 @@ function TracesDataListIdCell({ traceId }) {
|
|
|
12079
12081
|
return /* @__PURE__ */ jsx(DataListCell, { height: "compact", className: "text-ui-smd font-mono text-neutral3", children: getShortId(traceId) });
|
|
12080
12082
|
}
|
|
12081
12083
|
function TracesDataListDateCell({ timestamp }) {
|
|
12082
|
-
const date = toDate$
|
|
12084
|
+
const date = toDate$2(timestamp);
|
|
12083
12085
|
return /* @__PURE__ */ jsx(DataListCell, { height: "compact", className: "text-ui-smd text-neutral2", children: date ? isToday$1(date) ? "Today" : format(date, "MMM dd") : "-" });
|
|
12084
12086
|
}
|
|
12085
12087
|
function TracesDataListTimeCell({ timestamp }) {
|
|
12086
|
-
const date = toDate$
|
|
12088
|
+
const date = toDate$2(timestamp);
|
|
12087
12089
|
return /* @__PURE__ */ jsx(DataListCell, { height: "compact", className: "text-ui-smd font-mono text-neutral3 flex", children: date ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12088
12090
|
format(date, "HH:mm:ss"),
|
|
12089
12091
|
/* @__PURE__ */ jsxs("span", { className: "text-neutral2", children: [
|
|
@@ -12364,7 +12366,7 @@ function EntityListSkeleton({ columns, numberOfRows = 3 }) {
|
|
|
12364
12366
|
)) });
|
|
12365
12367
|
}
|
|
12366
12368
|
|
|
12367
|
-
function toDate(value) {
|
|
12369
|
+
function toDate$1(value) {
|
|
12368
12370
|
const date = value instanceof Date ? value : new Date(value);
|
|
12369
12371
|
return isNaN(date.getTime()) ? null : date;
|
|
12370
12372
|
}
|
|
@@ -12380,11 +12382,11 @@ function LogsDataListLevelCell({ level }) {
|
|
|
12380
12382
|
return /* @__PURE__ */ jsx(DataListCell, { height: "compact", children: /* @__PURE__ */ jsx("span", { className: "uppercase text-ui-sm font-semibold", style: { color: config.color }, children: config.label }) });
|
|
12381
12383
|
}
|
|
12382
12384
|
function LogsDataListDateCell({ timestamp }) {
|
|
12383
|
-
const date = toDate(timestamp);
|
|
12385
|
+
const date = toDate$1(timestamp);
|
|
12384
12386
|
return /* @__PURE__ */ jsx(DataListCell, { height: "compact", className: "text-ui-smd text-neutral2", children: date ? isToday$1(date) ? "Today" : format(date, "MMM dd") : "-" });
|
|
12385
12387
|
}
|
|
12386
12388
|
function LogsDataListTimeCell({ timestamp }) {
|
|
12387
|
-
const date = toDate(timestamp);
|
|
12389
|
+
const date = toDate$1(timestamp);
|
|
12388
12390
|
return /* @__PURE__ */ jsx(DataListCell, { height: "compact", className: "text-ui-smd font-mono text-neutral3 flex", children: date ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12389
12391
|
format(date, "HH:mm:ss"),
|
|
12390
12392
|
/* @__PURE__ */ jsxs("span", { className: "text-neutral2", children: [
|
|
@@ -13509,7 +13511,7 @@ const DataPanel = Object.assign(DataPanelRoot, {
|
|
|
13509
13511
|
CodeSection: DataCodeSection
|
|
13510
13512
|
});
|
|
13511
13513
|
|
|
13512
|
-
const DATE_PRESETS = [
|
|
13514
|
+
const DATE_PRESETS$1 = [
|
|
13513
13515
|
{ value: "all", label: "All" },
|
|
13514
13516
|
{ value: "last-24h", label: "Last 24 hours", ms: 24 * 60 * 60 * 1e3 },
|
|
13515
13517
|
{ value: "last-3d", label: "Last 3 days", ms: 3 * 24 * 60 * 60 * 1e3 },
|
|
@@ -13533,7 +13535,7 @@ function DateTimeRangePicker({
|
|
|
13533
13535
|
presets,
|
|
13534
13536
|
size = "md"
|
|
13535
13537
|
}) {
|
|
13536
|
-
const visiblePresets = presets ? DATE_PRESETS.filter((p) => presets.includes(p.value)) : DATE_PRESETS;
|
|
13538
|
+
const visiblePresets = presets ? DATE_PRESETS$1.filter((p) => presets.includes(p.value)) : DATE_PRESETS$1;
|
|
13537
13539
|
const fallbackPreset = visiblePresets.find((p) => p.value !== "custom")?.value ?? "all";
|
|
13538
13540
|
const [customRangeOpen, setCustomRangeOpen] = useState(false);
|
|
13539
13541
|
const [draftDateFrom, setDraftDateFrom] = useState(dateFrom);
|
|
@@ -13541,7 +13543,7 @@ function DateTimeRangePicker({
|
|
|
13541
13543
|
const [draftTimeFrom, setDraftTimeFrom] = useState("12:00 AM");
|
|
13542
13544
|
const [draftTimeTo, setDraftTimeTo] = useState("11:59 PM");
|
|
13543
13545
|
const [customRangeError, setCustomRangeError] = useState();
|
|
13544
|
-
const datePresetLabel = DATE_PRESETS.find((p) => p.value === preset)?.label ?? "All";
|
|
13546
|
+
const datePresetLabel = DATE_PRESETS$1.find((p) => p.value === preset)?.label ?? "All";
|
|
13545
13547
|
const handlePresetSelect = (value) => {
|
|
13546
13548
|
onPresetChange?.(value);
|
|
13547
13549
|
if (value === "custom") {
|
|
@@ -13552,7 +13554,7 @@ function DateTimeRangePicker({
|
|
|
13552
13554
|
setCustomRangeOpen(true);
|
|
13553
13555
|
return;
|
|
13554
13556
|
}
|
|
13555
|
-
const entry = DATE_PRESETS.find((p) => p.value === value);
|
|
13557
|
+
const entry = DATE_PRESETS$1.find((p) => p.value === value);
|
|
13556
13558
|
if (entry?.ms) {
|
|
13557
13559
|
onDateChange?.(new Date(Date.now() - entry.ms), "from");
|
|
13558
13560
|
onDateChange?.(void 0, "to");
|
|
@@ -14970,5 +14972,4124 @@ function generateDefaultValues(schema) {
|
|
|
14970
14972
|
return generateObjectDefaults(schema.properties, 0);
|
|
14971
14973
|
}
|
|
14972
14974
|
|
|
14973
|
-
|
|
14975
|
+
const DATE_PRESETS = [
|
|
14976
|
+
{ label: "Last 24 hours", value: "24h" },
|
|
14977
|
+
{ label: "Last 3 days", value: "3d" },
|
|
14978
|
+
{ label: "Last 7 days", value: "7d" },
|
|
14979
|
+
{ label: "Last 14 days", value: "14d" },
|
|
14980
|
+
{ label: "Last 30 days", value: "30d" }
|
|
14981
|
+
];
|
|
14982
|
+
const VALID_PRESETS = new Set(DATE_PRESETS.map((p) => p.value));
|
|
14983
|
+
function isValidPreset(value) {
|
|
14984
|
+
return typeof value === "string" && (VALID_PRESETS.has(value) || value === "custom");
|
|
14985
|
+
}
|
|
14986
|
+
const MetricsContext = createContext({
|
|
14987
|
+
datePreset: "24h",
|
|
14988
|
+
setDatePreset: () => {
|
|
14989
|
+
},
|
|
14990
|
+
customRange: void 0,
|
|
14991
|
+
setCustomRange: () => {
|
|
14992
|
+
},
|
|
14993
|
+
dateRangeLabel: "Last 24 hours"
|
|
14994
|
+
});
|
|
14995
|
+
function useMetrics() {
|
|
14996
|
+
return useContext(MetricsContext);
|
|
14997
|
+
}
|
|
14998
|
+
function getDateRangeLabel(preset, customRange) {
|
|
14999
|
+
if (preset !== "custom") {
|
|
15000
|
+
return DATE_PRESETS.find((p) => p.value === preset).label;
|
|
15001
|
+
}
|
|
15002
|
+
if (customRange?.from) {
|
|
15003
|
+
if (customRange.to) {
|
|
15004
|
+
return `${format(customRange.from, "MMM d, yyyy")} – ${format(customRange.to, "MMM d, yyyy")}`;
|
|
15005
|
+
}
|
|
15006
|
+
return format(customRange.from, "MMM d, yyyy");
|
|
15007
|
+
}
|
|
15008
|
+
return "Custom range";
|
|
15009
|
+
}
|
|
15010
|
+
function MetricsProvider({
|
|
15011
|
+
children,
|
|
15012
|
+
initialPreset,
|
|
15013
|
+
onPresetChange
|
|
15014
|
+
}) {
|
|
15015
|
+
const [datePreset, setDatePresetState] = useState(initialPreset ?? "24h");
|
|
15016
|
+
const [customRange, setCustomRange] = useState(void 0);
|
|
15017
|
+
const dateRangeLabel = getDateRangeLabel(datePreset, customRange);
|
|
15018
|
+
useEffect(() => {
|
|
15019
|
+
if (initialPreset && initialPreset !== datePreset) {
|
|
15020
|
+
setDatePresetState(initialPreset);
|
|
15021
|
+
}
|
|
15022
|
+
}, [initialPreset]);
|
|
15023
|
+
const setDatePreset = useCallback(
|
|
15024
|
+
(v) => {
|
|
15025
|
+
setDatePresetState(v);
|
|
15026
|
+
onPresetChange?.(v);
|
|
15027
|
+
},
|
|
15028
|
+
[onPresetChange]
|
|
15029
|
+
);
|
|
15030
|
+
return /* @__PURE__ */ jsx(
|
|
15031
|
+
MetricsContext.Provider,
|
|
15032
|
+
{
|
|
15033
|
+
value: {
|
|
15034
|
+
datePreset,
|
|
15035
|
+
setDatePreset,
|
|
15036
|
+
customRange,
|
|
15037
|
+
setCustomRange,
|
|
15038
|
+
dateRangeLabel
|
|
15039
|
+
},
|
|
15040
|
+
children
|
|
15041
|
+
}
|
|
15042
|
+
);
|
|
15043
|
+
}
|
|
15044
|
+
|
|
15045
|
+
function DateRangeSelector() {
|
|
15046
|
+
const { datePreset, setDatePreset } = useMetrics();
|
|
15047
|
+
return /* @__PURE__ */ jsx(
|
|
15048
|
+
SelectFieldBlock,
|
|
15049
|
+
{
|
|
15050
|
+
name: "date-range",
|
|
15051
|
+
labelIsHidden: true,
|
|
15052
|
+
value: datePreset,
|
|
15053
|
+
options: DATE_PRESETS.map((p) => ({ label: p.label, value: p.value })),
|
|
15054
|
+
onValueChange: (value) => {
|
|
15055
|
+
if (isValidPreset(value)) setDatePreset(value);
|
|
15056
|
+
}
|
|
15057
|
+
}
|
|
15058
|
+
);
|
|
15059
|
+
}
|
|
15060
|
+
|
|
15061
|
+
function formatCompact(n) {
|
|
15062
|
+
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
15063
|
+
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
|
|
15064
|
+
return n.toLocaleString();
|
|
15065
|
+
}
|
|
15066
|
+
function formatCost(value, unit) {
|
|
15067
|
+
if (unit?.toLowerCase() === "usd" || !unit) {
|
|
15068
|
+
return `$${value < 0.01 && value > 0 ? value.toFixed(4) : value.toFixed(2)}`;
|
|
15069
|
+
}
|
|
15070
|
+
return `${value.toFixed(4)} ${unit}`;
|
|
15071
|
+
}
|
|
15072
|
+
const CHART_COLORS = {
|
|
15073
|
+
green: "#22c55e",
|
|
15074
|
+
orange: "#fb923c",
|
|
15075
|
+
pink: "#f472b6",
|
|
15076
|
+
purple: "#8b5cf6",
|
|
15077
|
+
blue: "#4f83f1",
|
|
15078
|
+
blueDark: "#2b5cd9",
|
|
15079
|
+
blueLight: "#6b8fe5",
|
|
15080
|
+
red: "#f87171",
|
|
15081
|
+
greenDark: "#15613a",
|
|
15082
|
+
redDark: "#991b1b",
|
|
15083
|
+
yellow: "#facc15"
|
|
15084
|
+
};
|
|
15085
|
+
|
|
15086
|
+
function BarListContent({
|
|
15087
|
+
data,
|
|
15088
|
+
maxVal,
|
|
15089
|
+
fmt,
|
|
15090
|
+
color,
|
|
15091
|
+
valueLabel,
|
|
15092
|
+
legend
|
|
15093
|
+
}) {
|
|
15094
|
+
const sorted = [...data].sort((a, b) => b.value - a.value);
|
|
15095
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
15096
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-2", children: [
|
|
15097
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center gap-4", children: legend?.map((l) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
15098
|
+
/* @__PURE__ */ jsx("div", { className: "size-2 rounded-full", style: { backgroundColor: l.color } }),
|
|
15099
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-icon2", children: l.label })
|
|
15100
|
+
] }, l.label)) }),
|
|
15101
|
+
valueLabel && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-icon2", children: valueLabel })
|
|
15102
|
+
] }),
|
|
15103
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-2.5", children: sorted.map((d) => {
|
|
15104
|
+
const pct = Math.min(Math.max(maxVal > 0 ? d.value / maxVal * 100 : 0, 0), 100);
|
|
15105
|
+
return /* @__PURE__ */ jsxs("div", { className: "group flex items-center gap-3", children: [
|
|
15106
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex-1 h-7", children: [
|
|
15107
|
+
/* @__PURE__ */ jsx(
|
|
15108
|
+
"div",
|
|
15109
|
+
{
|
|
15110
|
+
className: "absolute inset-y-0 left-0 rounded",
|
|
15111
|
+
style: { width: `${pct}%`, backgroundColor: color }
|
|
15112
|
+
}
|
|
15113
|
+
),
|
|
15114
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inset-y-0 left-2 flex items-center text-xs text-white whitespace-nowrap", children: d.name })
|
|
15115
|
+
] }),
|
|
15116
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs font-mono text-icon6 tabular-nums", children: fmt(d.value) })
|
|
15117
|
+
] }, d.name);
|
|
15118
|
+
}) })
|
|
15119
|
+
] });
|
|
15120
|
+
}
|
|
15121
|
+
function StackedRunsBars({ data }) {
|
|
15122
|
+
const sorted = [...data].sort((a, b) => b.completed + b.errors - (a.completed + a.errors));
|
|
15123
|
+
const maxTotal = Math.max(...sorted.map((d) => d.completed + d.errors));
|
|
15124
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
15125
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-2", children: [
|
|
15126
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 flex items-center gap-4", children: [
|
|
15127
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
15128
|
+
/* @__PURE__ */ jsx("div", { className: "size-2 rounded-full", style: { backgroundColor: CHART_COLORS.blue } }),
|
|
15129
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-icon2", children: "Completed" })
|
|
15130
|
+
] }),
|
|
15131
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
15132
|
+
/* @__PURE__ */ jsx("div", { className: "size-2 rounded-full", style: { backgroundColor: CHART_COLORS.red } }),
|
|
15133
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-icon2", children: "Errors" })
|
|
15134
|
+
] })
|
|
15135
|
+
] }),
|
|
15136
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-icon2", children: "Total (Success)" })
|
|
15137
|
+
] }),
|
|
15138
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-2.5", children: sorted.map((d) => {
|
|
15139
|
+
const total = d.completed + d.errors;
|
|
15140
|
+
const successPct = total > 0 ? (d.completed / total * 100).toFixed(1) : "0.0";
|
|
15141
|
+
const completedWidth = Math.min(Math.max(maxTotal > 0 ? d.completed / maxTotal * 100 : 0, 0), 100);
|
|
15142
|
+
const errorsWidth = Math.min(Math.max(maxTotal > 0 ? d.errors / maxTotal * 100 : 0, 0), 100);
|
|
15143
|
+
return /* @__PURE__ */ jsxs("div", { className: "group flex items-center gap-3", children: [
|
|
15144
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex-1 h-7", children: [
|
|
15145
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
15146
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
15147
|
+
"div",
|
|
15148
|
+
{
|
|
15149
|
+
role: "img",
|
|
15150
|
+
"aria-label": `${d.completed.toLocaleString()} completed`,
|
|
15151
|
+
tabIndex: 0,
|
|
15152
|
+
className: "absolute inset-y-0 left-0 rounded-l cursor-default",
|
|
15153
|
+
style: { width: `${completedWidth}%`, backgroundColor: CHART_COLORS.blue }
|
|
15154
|
+
}
|
|
15155
|
+
) }),
|
|
15156
|
+
/* @__PURE__ */ jsxs(TooltipContent, { side: "top", className: "font-mono", children: [
|
|
15157
|
+
d.completed.toLocaleString(),
|
|
15158
|
+
" completed"
|
|
15159
|
+
] })
|
|
15160
|
+
] }),
|
|
15161
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
15162
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
15163
|
+
"div",
|
|
15164
|
+
{
|
|
15165
|
+
role: "img",
|
|
15166
|
+
"aria-label": `${d.errors.toLocaleString()} errors`,
|
|
15167
|
+
tabIndex: 0,
|
|
15168
|
+
className: "absolute inset-y-0 rounded-r cursor-default",
|
|
15169
|
+
style: {
|
|
15170
|
+
left: `${completedWidth}%`,
|
|
15171
|
+
width: `${errorsWidth}%`,
|
|
15172
|
+
backgroundColor: CHART_COLORS.red
|
|
15173
|
+
}
|
|
15174
|
+
}
|
|
15175
|
+
) }),
|
|
15176
|
+
/* @__PURE__ */ jsxs(TooltipContent, { side: "top", className: "font-mono", children: [
|
|
15177
|
+
d.errors.toLocaleString(),
|
|
15178
|
+
" errors"
|
|
15179
|
+
] })
|
|
15180
|
+
] }),
|
|
15181
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inset-y-0 left-2 flex items-center text-xs text-white whitespace-nowrap pointer-events-none", children: d.name })
|
|
15182
|
+
] }),
|
|
15183
|
+
/* @__PURE__ */ jsxs("span", { className: "shrink-0 text-xs font-mono text-icon6 tabular-nums", children: [
|
|
15184
|
+
total.toLocaleString(),
|
|
15185
|
+
" (",
|
|
15186
|
+
successPct,
|
|
15187
|
+
"%)"
|
|
15188
|
+
] })
|
|
15189
|
+
] }, d.name);
|
|
15190
|
+
}) })
|
|
15191
|
+
] });
|
|
15192
|
+
}
|
|
15193
|
+
|
|
15194
|
+
function KpiCardView({ label, value, prevValue, changePct, isLoading, isError }) {
|
|
15195
|
+
const hasData = value != null;
|
|
15196
|
+
return /* @__PURE__ */ jsxs(MetricsKpiCard, { children: [
|
|
15197
|
+
/* @__PURE__ */ jsx(MetricsKpiCard.Label, { children: label }),
|
|
15198
|
+
/* @__PURE__ */ jsx(MetricsKpiCard.Value, { className: hasData ? void 0 : "invisible", children: hasData ? value : "—" }),
|
|
15199
|
+
isError ? /* @__PURE__ */ jsx(MetricsKpiCard.Error, {}) : isLoading ? /* @__PURE__ */ jsx(MetricsKpiCard.Loading, {}) : hasData ? changePct != null ? /* @__PURE__ */ jsx(MetricsKpiCard.Change, { changePct, prevValue }) : /* @__PURE__ */ jsx(MetricsKpiCard.NoChange, {}) : /* @__PURE__ */ jsx(MetricsKpiCard.NoData, {})
|
|
15200
|
+
] });
|
|
15201
|
+
}
|
|
15202
|
+
|
|
15203
|
+
const latencySeries = [
|
|
15204
|
+
{
|
|
15205
|
+
dataKey: "p50",
|
|
15206
|
+
label: "p50",
|
|
15207
|
+
color: CHART_COLORS.blue,
|
|
15208
|
+
aggregate: (data) => ({
|
|
15209
|
+
value: data.length > 0 ? `${Math.round(data.reduce((s, d) => s + d.p50, 0) / data.length)}` : "0",
|
|
15210
|
+
suffix: "avg ms"
|
|
15211
|
+
})
|
|
15212
|
+
},
|
|
15213
|
+
{
|
|
15214
|
+
dataKey: "p95",
|
|
15215
|
+
label: "p95",
|
|
15216
|
+
color: CHART_COLORS.yellow,
|
|
15217
|
+
aggregate: (data) => ({
|
|
15218
|
+
value: data.length > 0 ? `${Math.round(data.reduce((s, d) => s + d.p95, 0) / data.length)}` : "0",
|
|
15219
|
+
suffix: "avg ms"
|
|
15220
|
+
})
|
|
15221
|
+
}
|
|
15222
|
+
];
|
|
15223
|
+
function LatencyChart({ data }) {
|
|
15224
|
+
if (data.length === 0) {
|
|
15225
|
+
return /* @__PURE__ */ jsx(MetricsCard.NoData, { message: "No latency data yet" });
|
|
15226
|
+
}
|
|
15227
|
+
return /* @__PURE__ */ jsx(MetricsLineChart, { data, series: latencySeries });
|
|
15228
|
+
}
|
|
15229
|
+
function LatencyCardView({ data, isLoading, isError }) {
|
|
15230
|
+
const hasData = !!data && (data.agentData.length > 0 || data.workflowData.length > 0 || data.toolData.length > 0);
|
|
15231
|
+
const p50Values = data ? Object.values(data).filter(Array.isArray).flat().map((d) => d.p50).filter((v) => typeof v === "number") : [];
|
|
15232
|
+
const avgP50 = p50Values.length > 0 ? `${Math.round(p50Values.reduce((s, v) => s + v, 0) / p50Values.length)}ms` : "—";
|
|
15233
|
+
return /* @__PURE__ */ jsxs(MetricsCard, { children: [
|
|
15234
|
+
/* @__PURE__ */ jsxs(MetricsCard.TopBar, { children: [
|
|
15235
|
+
/* @__PURE__ */ jsx(MetricsCard.TitleAndDescription, { title: "Latency", description: "Hourly p50 and p95 latency." }),
|
|
15236
|
+
hasData && /* @__PURE__ */ jsx(MetricsCard.Summary, { value: avgP50, label: "Avg p50" })
|
|
15237
|
+
] }),
|
|
15238
|
+
isLoading ? /* @__PURE__ */ jsx(MetricsCard.Loading, {}) : isError ? /* @__PURE__ */ jsx(MetricsCard.Error, { message: "Failed to load latency data" }) : /* @__PURE__ */ jsx(MetricsCard.Content, { children: !hasData ? /* @__PURE__ */ jsx(MetricsCard.NoData, { message: "No latency data yet" }) : /* @__PURE__ */ jsxs(
|
|
15239
|
+
Tabs,
|
|
15240
|
+
{
|
|
15241
|
+
defaultTab: data.agentData.length > 0 ? "agents" : data.workflowData.length > 0 ? "workflows" : data.toolData.length > 0 ? "tools" : "agents",
|
|
15242
|
+
className: "overflow-visible",
|
|
15243
|
+
children: [
|
|
15244
|
+
/* @__PURE__ */ jsxs(TabList, { children: [
|
|
15245
|
+
/* @__PURE__ */ jsx(Tab, { value: "agents", children: "Agents" }),
|
|
15246
|
+
/* @__PURE__ */ jsx(Tab, { value: "workflows", children: "Workflows" }),
|
|
15247
|
+
/* @__PURE__ */ jsx(Tab, { value: "tools", children: "Tools" })
|
|
15248
|
+
] }),
|
|
15249
|
+
/* @__PURE__ */ jsx(TabContent, { value: "agents", children: /* @__PURE__ */ jsx(LatencyChart, { data: data.agentData }) }),
|
|
15250
|
+
/* @__PURE__ */ jsx(TabContent, { value: "workflows", children: /* @__PURE__ */ jsx(LatencyChart, { data: data.workflowData }) }),
|
|
15251
|
+
/* @__PURE__ */ jsx(TabContent, { value: "tools", children: /* @__PURE__ */ jsx(LatencyChart, { data: data.toolData }) })
|
|
15252
|
+
]
|
|
15253
|
+
}
|
|
15254
|
+
) })
|
|
15255
|
+
] });
|
|
15256
|
+
}
|
|
15257
|
+
|
|
15258
|
+
function ModelUsageCostCardView({ rows, isLoading, isError }) {
|
|
15259
|
+
const hasData = !!rows && rows.length > 0;
|
|
15260
|
+
return /* @__PURE__ */ jsxs(MetricsCard, { children: [
|
|
15261
|
+
/* @__PURE__ */ jsxs(MetricsCard.TopBar, { children: [
|
|
15262
|
+
/* @__PURE__ */ jsx(MetricsCard.TitleAndDescription, { title: "Model Usage & Cost", description: "Token consumption by model." }),
|
|
15263
|
+
hasData && (() => {
|
|
15264
|
+
const totalCost = rows.reduce((sum, r) => sum + (r.cost ?? 0), 0);
|
|
15265
|
+
const units = new Set(rows.filter((r) => r.cost != null && r.costUnit).map((r) => r.costUnit));
|
|
15266
|
+
let value;
|
|
15267
|
+
if (units.size === 0) {
|
|
15268
|
+
value = totalCost > 0 ? formatCost(totalCost) : "—";
|
|
15269
|
+
} else if (units.size === 1) {
|
|
15270
|
+
value = totalCost > 0 ? formatCost(totalCost, [...units][0]) : "—";
|
|
15271
|
+
} else {
|
|
15272
|
+
value = "Mixed";
|
|
15273
|
+
}
|
|
15274
|
+
return /* @__PURE__ */ jsx(MetricsCard.Summary, { value, label: "Total cost" });
|
|
15275
|
+
})()
|
|
15276
|
+
] }),
|
|
15277
|
+
isLoading ? /* @__PURE__ */ jsx(MetricsCard.Loading, {}) : isError ? /* @__PURE__ */ jsx(MetricsCard.Error, { message: "Failed to load model usage data" }) : /* @__PURE__ */ jsx(MetricsCard.Content, { children: !hasData ? /* @__PURE__ */ jsx(MetricsCard.NoData, { message: "No model usage data yet" }) : /* @__PURE__ */ jsx(
|
|
15278
|
+
MetricsDataTable,
|
|
15279
|
+
{
|
|
15280
|
+
columns: [
|
|
15281
|
+
{ label: "Model", value: (row) => row.model },
|
|
15282
|
+
{ label: "Input", value: (row) => row.input },
|
|
15283
|
+
{ label: "Output", value: (row) => row.output },
|
|
15284
|
+
{ label: "Cache Read", value: (row) => row.cacheRead },
|
|
15285
|
+
{ label: "Cache Write", value: (row) => row.cacheWrite },
|
|
15286
|
+
{
|
|
15287
|
+
label: "Cost",
|
|
15288
|
+
value: (row) => row.cost != null ? formatCost(row.cost, row.costUnit) : "—",
|
|
15289
|
+
highlight: true
|
|
15290
|
+
}
|
|
15291
|
+
],
|
|
15292
|
+
data: rows.map((row) => ({ ...row, key: row.model }))
|
|
15293
|
+
}
|
|
15294
|
+
) })
|
|
15295
|
+
] });
|
|
15296
|
+
}
|
|
15297
|
+
|
|
15298
|
+
const SERIES_COLORS = [
|
|
15299
|
+
CHART_COLORS.green,
|
|
15300
|
+
CHART_COLORS.blue,
|
|
15301
|
+
CHART_COLORS.purple,
|
|
15302
|
+
CHART_COLORS.orange,
|
|
15303
|
+
CHART_COLORS.pink,
|
|
15304
|
+
CHART_COLORS.yellow
|
|
15305
|
+
];
|
|
15306
|
+
function ScoresCardView({ data, isLoading, isError }) {
|
|
15307
|
+
const hasData = !!data && (data.summaryData.length > 0 || data.overTimeData.length > 0);
|
|
15308
|
+
const series = useMemo(() => {
|
|
15309
|
+
if (!data?.scorerNames) return [];
|
|
15310
|
+
return data.scorerNames.map((name, i) => ({
|
|
15311
|
+
dataKey: name,
|
|
15312
|
+
label: name,
|
|
15313
|
+
color: SERIES_COLORS[i % SERIES_COLORS.length],
|
|
15314
|
+
aggregate: (points) => ({
|
|
15315
|
+
value: points.length > 0 ? (points.reduce((s, d) => s + (d[name] ?? 0), 0) / points.length).toFixed(2) : "0",
|
|
15316
|
+
suffix: "avg"
|
|
15317
|
+
})
|
|
15318
|
+
}));
|
|
15319
|
+
}, [data?.scorerNames]);
|
|
15320
|
+
return /* @__PURE__ */ jsxs(MetricsCard, { children: [
|
|
15321
|
+
/* @__PURE__ */ jsxs(MetricsCard.TopBar, { children: [
|
|
15322
|
+
/* @__PURE__ */ jsx(MetricsCard.TitleAndDescription, { title: "Scores", description: "Evaluation scorer performance." }),
|
|
15323
|
+
hasData && /* @__PURE__ */ jsx(
|
|
15324
|
+
MetricsCard.Summary,
|
|
15325
|
+
{
|
|
15326
|
+
value: data?.avgScore != null ? `avg ${data.avgScore}` : "—",
|
|
15327
|
+
label: "Across all scorers"
|
|
15328
|
+
}
|
|
15329
|
+
)
|
|
15330
|
+
] }),
|
|
15331
|
+
isLoading ? /* @__PURE__ */ jsx(MetricsCard.Loading, {}) : isError ? /* @__PURE__ */ jsx(MetricsCard.Error, { message: "Failed to load scores data" }) : /* @__PURE__ */ jsx(MetricsCard.Content, { children: !hasData ? /* @__PURE__ */ jsx(MetricsCard.NoData, { message: "No scores data yet" }) : /* @__PURE__ */ jsxs(Tabs, { defaultTab: "over-time", className: "overflow-visible", children: [
|
|
15332
|
+
/* @__PURE__ */ jsxs(TabList, { children: [
|
|
15333
|
+
/* @__PURE__ */ jsx(Tab, { value: "over-time", children: "Over Time" }),
|
|
15334
|
+
/* @__PURE__ */ jsx(Tab, { value: "summary", children: "Summary" })
|
|
15335
|
+
] }),
|
|
15336
|
+
/* @__PURE__ */ jsx(TabContent, { value: "over-time", className: "pb-0", children: data.overTimeData.length > 0 ? /* @__PURE__ */ jsx(MetricsLineChart, { data: data.overTimeData, series, yDomain: [0, 1] }) : /* @__PURE__ */ jsx(MetricsCard.NoData, { message: "No time series data yet" }) }),
|
|
15337
|
+
/* @__PURE__ */ jsx(TabContent, { value: "summary", children: /* @__PURE__ */ jsx(
|
|
15338
|
+
MetricsDataTable,
|
|
15339
|
+
{
|
|
15340
|
+
columns: [
|
|
15341
|
+
{ label: "Scorer", value: (row) => row.scorer },
|
|
15342
|
+
{ label: "Avg", value: (row) => row.avg.toFixed(2), highlight: true },
|
|
15343
|
+
{ label: "Min", value: (row) => row.min.toFixed(2) },
|
|
15344
|
+
{ label: "Max", value: (row) => row.max.toFixed(2) },
|
|
15345
|
+
{ label: "Count", value: (row) => row.count.toLocaleString() }
|
|
15346
|
+
],
|
|
15347
|
+
data: data.summaryData.map((row) => ({ ...row, key: row.scorer }))
|
|
15348
|
+
}
|
|
15349
|
+
) })
|
|
15350
|
+
] }) })
|
|
15351
|
+
] });
|
|
15352
|
+
}
|
|
15353
|
+
|
|
15354
|
+
function isTokenUsageTab(value) {
|
|
15355
|
+
return value === "tokens" || value === "cost";
|
|
15356
|
+
}
|
|
15357
|
+
function TokenUsageByAgentCardView({ data, isLoading, isError }) {
|
|
15358
|
+
const [activeTab, setActiveTab] = useState("tokens");
|
|
15359
|
+
const rows = data ?? [];
|
|
15360
|
+
const hasData = rows.length > 0;
|
|
15361
|
+
const totalTokens = rows.reduce((s, d) => s + d.total, 0);
|
|
15362
|
+
const costRows = rows.filter((d) => d.cost != null && d.cost > 0);
|
|
15363
|
+
const uniqueCostUnits = new Set(costRows.map((d) => d.costUnit ?? "usd"));
|
|
15364
|
+
const hasSingleCostUnit = uniqueCostUnits.size <= 1;
|
|
15365
|
+
const costUnit = hasSingleCostUnit ? [...uniqueCostUnits][0] ?? "usd" : null;
|
|
15366
|
+
const totalCost = hasSingleCostUnit ? costRows.reduce((s, d) => s + (d.cost ?? 0), 0) : 0;
|
|
15367
|
+
const hasCostData = hasSingleCostUnit && totalCost > 0;
|
|
15368
|
+
return /* @__PURE__ */ jsxs(MetricsCard, { children: [
|
|
15369
|
+
/* @__PURE__ */ jsxs(MetricsCard.TopBar, { children: [
|
|
15370
|
+
/* @__PURE__ */ jsx(
|
|
15371
|
+
MetricsCard.TitleAndDescription,
|
|
15372
|
+
{
|
|
15373
|
+
title: "Token Usage by Agent",
|
|
15374
|
+
description: "Token consumption grouped by agent."
|
|
15375
|
+
}
|
|
15376
|
+
),
|
|
15377
|
+
hasData && (activeTab === "cost" && hasCostData ? /* @__PURE__ */ jsx(MetricsCard.Summary, { value: formatCost(totalCost, costUnit), label: "Total cost" }) : /* @__PURE__ */ jsx(MetricsCard.Summary, { value: formatCompact(totalTokens), label: "Total tokens" }))
|
|
15378
|
+
] }),
|
|
15379
|
+
isLoading ? /* @__PURE__ */ jsx(MetricsCard.Loading, {}) : isError ? /* @__PURE__ */ jsx(MetricsCard.Error, { message: "Failed to load token usage data" }) : /* @__PURE__ */ jsx(MetricsCard.Content, { children: !hasData ? /* @__PURE__ */ jsx(MetricsCard.NoData, { message: "No token usage data yet" }) : /* @__PURE__ */ jsxs(
|
|
15380
|
+
Tabs,
|
|
15381
|
+
{
|
|
15382
|
+
defaultTab: "tokens",
|
|
15383
|
+
value: activeTab,
|
|
15384
|
+
onValueChange: (v) => {
|
|
15385
|
+
if (isTokenUsageTab(v)) setActiveTab(v);
|
|
15386
|
+
},
|
|
15387
|
+
className: "grid grid-rows-[auto_1fr] overflow-y-auto h-full",
|
|
15388
|
+
children: [
|
|
15389
|
+
/* @__PURE__ */ jsxs(TabList, { children: [
|
|
15390
|
+
/* @__PURE__ */ jsx(Tab, { value: "tokens", children: "Tokens" }),
|
|
15391
|
+
/* @__PURE__ */ jsx(Tab, { value: "cost", children: "Cost" })
|
|
15392
|
+
] }),
|
|
15393
|
+
/* @__PURE__ */ jsx(TabContent, { value: "tokens", children: /* @__PURE__ */ jsx(
|
|
15394
|
+
HorizontalBars,
|
|
15395
|
+
{
|
|
15396
|
+
data: rows.map((d) => ({ name: d.name, values: [d.input, d.output] })),
|
|
15397
|
+
segments: [
|
|
15398
|
+
{ label: "Input", color: CHART_COLORS.blueDark },
|
|
15399
|
+
{ label: "Output", color: CHART_COLORS.blue }
|
|
15400
|
+
],
|
|
15401
|
+
maxVal: Math.max(...rows.map((d) => d.input + d.output)),
|
|
15402
|
+
fmt: formatCompact
|
|
15403
|
+
}
|
|
15404
|
+
) }),
|
|
15405
|
+
/* @__PURE__ */ jsx(TabContent, { value: "cost", children: hasCostData ? /* @__PURE__ */ jsx(
|
|
15406
|
+
HorizontalBars,
|
|
15407
|
+
{
|
|
15408
|
+
data: costRows.slice().sort((a, b) => (b.cost ?? 0) - (a.cost ?? 0)).map((d) => ({ name: d.name, values: [d.cost] })),
|
|
15409
|
+
segments: [{ label: "Cost", color: CHART_COLORS.purple }],
|
|
15410
|
+
maxVal: Math.max(...costRows.map((d) => d.cost ?? 0)),
|
|
15411
|
+
fmt: (v) => formatCost(v, costUnit)
|
|
15412
|
+
}
|
|
15413
|
+
) : /* @__PURE__ */ jsx(MetricsCard.NoData, { message: "No cost data yet" }) })
|
|
15414
|
+
]
|
|
15415
|
+
}
|
|
15416
|
+
) })
|
|
15417
|
+
] });
|
|
15418
|
+
}
|
|
15419
|
+
|
|
15420
|
+
function VolumeBars({ data }) {
|
|
15421
|
+
return /* @__PURE__ */ jsx(
|
|
15422
|
+
HorizontalBars,
|
|
15423
|
+
{
|
|
15424
|
+
data: data.map((d) => ({ name: d.name, values: [d.completed, d.errors] })),
|
|
15425
|
+
segments: [
|
|
15426
|
+
{ label: "Completed", color: CHART_COLORS.blueDark },
|
|
15427
|
+
{ label: "Errors", color: CHART_COLORS.pink }
|
|
15428
|
+
],
|
|
15429
|
+
maxVal: Math.max(...data.map((d) => d.completed + d.errors)),
|
|
15430
|
+
fmt: formatCompact
|
|
15431
|
+
}
|
|
15432
|
+
);
|
|
15433
|
+
}
|
|
15434
|
+
function TracesVolumeCardView({ data, isLoading, isError }) {
|
|
15435
|
+
const hasData = !!data && (data.agentData.length > 0 || data.workflowData.length > 0 || data.toolData.length > 0);
|
|
15436
|
+
const total = data ? [...data.agentData, ...data.workflowData, ...data.toolData].reduce((s, d) => s + d.completed + d.errors, 0) : 0;
|
|
15437
|
+
return /* @__PURE__ */ jsxs(MetricsCard, { children: [
|
|
15438
|
+
/* @__PURE__ */ jsxs(MetricsCard.TopBar, { children: [
|
|
15439
|
+
/* @__PURE__ */ jsx(MetricsCard.TitleAndDescription, { title: "Trace Volume", description: "Runs and call counts." }),
|
|
15440
|
+
hasData && /* @__PURE__ */ jsx(MetricsCard.Summary, { value: formatCompact(total), label: "Total runs" })
|
|
15441
|
+
] }),
|
|
15442
|
+
isLoading ? /* @__PURE__ */ jsx(MetricsCard.Loading, {}) : isError ? /* @__PURE__ */ jsx(MetricsCard.Error, { message: "Failed to load trace volume data" }) : /* @__PURE__ */ jsx(MetricsCard.Content, { children: !hasData ? /* @__PURE__ */ jsx(MetricsCard.NoData, { message: "No trace volume data yet" }) : /* @__PURE__ */ jsxs(Tabs, { defaultTab: "agents", className: "grid grid-rows-[auto_1fr] overflow-y-auto h-full", children: [
|
|
15443
|
+
/* @__PURE__ */ jsxs(TabList, { children: [
|
|
15444
|
+
/* @__PURE__ */ jsx(Tab, { value: "agents", children: "Agents" }),
|
|
15445
|
+
/* @__PURE__ */ jsx(Tab, { value: "workflows", children: "Workflows" }),
|
|
15446
|
+
/* @__PURE__ */ jsx(Tab, { value: "tools", children: "Tools" })
|
|
15447
|
+
] }),
|
|
15448
|
+
/* @__PURE__ */ jsx(TabContent, { value: "agents", children: data.agentData.length > 0 ? /* @__PURE__ */ jsx(VolumeBars, { data: data.agentData }) : /* @__PURE__ */ jsx(MetricsCard.NoData, { message: "No agent data yet" }) }),
|
|
15449
|
+
/* @__PURE__ */ jsx(TabContent, { value: "workflows", children: data.workflowData.length > 0 ? /* @__PURE__ */ jsx(VolumeBars, { data: data.workflowData }) : /* @__PURE__ */ jsx(MetricsCard.NoData, { message: "No workflow data yet" }) }),
|
|
15450
|
+
/* @__PURE__ */ jsx(TabContent, { value: "tools", children: data.toolData.length > 0 ? /* @__PURE__ */ jsx(VolumeBars, { data: data.toolData }) : /* @__PURE__ */ jsx(MetricsCard.NoData, { message: "No tool data yet" }) })
|
|
15451
|
+
] }) })
|
|
15452
|
+
] });
|
|
15453
|
+
}
|
|
15454
|
+
|
|
15455
|
+
const PRESET_MS$2 = {
|
|
15456
|
+
"24h": 24 * 60 * 60 * 1e3,
|
|
15457
|
+
"3d": 3 * 24 * 60 * 60 * 1e3,
|
|
15458
|
+
"7d": 7 * 24 * 60 * 60 * 1e3,
|
|
15459
|
+
"14d": 14 * 24 * 60 * 60 * 1e3,
|
|
15460
|
+
"30d": 30 * 24 * 60 * 60 * 1e3
|
|
15461
|
+
};
|
|
15462
|
+
function buildTimestamp(preset, customRange) {
|
|
15463
|
+
const now = /* @__PURE__ */ new Date();
|
|
15464
|
+
if (preset !== "custom") {
|
|
15465
|
+
const ms = PRESET_MS$2[preset] ?? PRESET_MS$2["24h"];
|
|
15466
|
+
return { start: new Date(now.getTime() - ms), end: now };
|
|
15467
|
+
}
|
|
15468
|
+
return {
|
|
15469
|
+
start: customRange?.from ?? new Date(now.getTime() - PRESET_MS$2["24h"]),
|
|
15470
|
+
end: customRange?.to ?? now
|
|
15471
|
+
};
|
|
15472
|
+
}
|
|
15473
|
+
function useMetricsFilters() {
|
|
15474
|
+
const { datePreset, customRange } = useMetrics();
|
|
15475
|
+
const timestamp = buildTimestamp(datePreset, customRange);
|
|
15476
|
+
return { datePreset, customRange, timestamp };
|
|
15477
|
+
}
|
|
15478
|
+
|
|
15479
|
+
function useAgentRunsKpiMetrics() {
|
|
15480
|
+
const client = useMastraClient();
|
|
15481
|
+
const { datePreset, customRange, timestamp } = useMetricsFilters();
|
|
15482
|
+
return useQuery({
|
|
15483
|
+
queryKey: ["metrics", "agent-runs-kpi", datePreset, customRange],
|
|
15484
|
+
queryFn: () => client.getMetricAggregate({
|
|
15485
|
+
name: ["mastra_agent_duration_ms"],
|
|
15486
|
+
aggregation: "count",
|
|
15487
|
+
filters: { timestamp },
|
|
15488
|
+
comparePeriod: "previous_period"
|
|
15489
|
+
})
|
|
15490
|
+
});
|
|
15491
|
+
}
|
|
15492
|
+
|
|
15493
|
+
function useAvgScoreKpiMetrics() {
|
|
15494
|
+
const client = useMastraClient();
|
|
15495
|
+
const { datePreset, customRange, timestamp } = useMetricsFilters();
|
|
15496
|
+
return useQuery({
|
|
15497
|
+
queryKey: ["metrics", "avg-score-kpi", datePreset, customRange],
|
|
15498
|
+
queryFn: async () => {
|
|
15499
|
+
const scorersMap = await client.listScorers();
|
|
15500
|
+
const scorerIds = Object.keys(scorersMap ?? {});
|
|
15501
|
+
if (scorerIds.length === 0) {
|
|
15502
|
+
return { value: null, previousValue: null, changePercent: null };
|
|
15503
|
+
}
|
|
15504
|
+
const filters = {
|
|
15505
|
+
timestamp: { start: timestamp.start, end: timestamp.end }
|
|
15506
|
+
};
|
|
15507
|
+
const results = await Promise.all(
|
|
15508
|
+
scorerIds.map(async (scorerId) => {
|
|
15509
|
+
const [avg2, count] = await Promise.all([
|
|
15510
|
+
client.getScoreAggregate({ scorerId, aggregation: "avg", filters }),
|
|
15511
|
+
client.getScoreAggregate({ scorerId, aggregation: "count", filters })
|
|
15512
|
+
]);
|
|
15513
|
+
return { avg: avg2.value ?? 0, count: count.value ?? 0 };
|
|
15514
|
+
})
|
|
15515
|
+
);
|
|
15516
|
+
const withData = results.filter((r) => r.count > 0);
|
|
15517
|
+
if (withData.length === 0) {
|
|
15518
|
+
return { value: null, previousValue: null, changePercent: null };
|
|
15519
|
+
}
|
|
15520
|
+
const totalCount = withData.reduce((sum, r) => sum + r.count, 0);
|
|
15521
|
+
const weightedSum = withData.reduce((sum, r) => sum + r.avg * r.count, 0);
|
|
15522
|
+
const avg = weightedSum / totalCount;
|
|
15523
|
+
return { value: Math.round(avg * 100) / 100, previousValue: null, changePercent: null };
|
|
15524
|
+
}
|
|
15525
|
+
});
|
|
15526
|
+
}
|
|
15527
|
+
|
|
15528
|
+
function useModelCostKpiMetrics() {
|
|
15529
|
+
const client = useMastraClient();
|
|
15530
|
+
const { datePreset, customRange, timestamp } = useMetricsFilters();
|
|
15531
|
+
return useQuery({
|
|
15532
|
+
queryKey: ["metrics", "model-cost-kpi", datePreset, customRange],
|
|
15533
|
+
queryFn: async () => {
|
|
15534
|
+
const res = await client.getMetricAggregate({
|
|
15535
|
+
name: ["mastra_model_total_input_tokens", "mastra_model_total_output_tokens"],
|
|
15536
|
+
aggregation: "sum",
|
|
15537
|
+
filters: { timestamp },
|
|
15538
|
+
comparePeriod: "previous_period"
|
|
15539
|
+
});
|
|
15540
|
+
return {
|
|
15541
|
+
cost: res.estimatedCost ?? null,
|
|
15542
|
+
costUnit: res.costUnit ?? null,
|
|
15543
|
+
previousCost: res.previousEstimatedCost ?? null,
|
|
15544
|
+
costChangePercent: res.costChangePercent ?? null
|
|
15545
|
+
};
|
|
15546
|
+
}
|
|
15547
|
+
});
|
|
15548
|
+
}
|
|
15549
|
+
|
|
15550
|
+
function useTotalTokensKpiMetrics() {
|
|
15551
|
+
const client = useMastraClient();
|
|
15552
|
+
const { datePreset, customRange, timestamp } = useMetricsFilters();
|
|
15553
|
+
return useQuery({
|
|
15554
|
+
queryKey: ["metrics", "total-tokens-kpi", datePreset, customRange],
|
|
15555
|
+
queryFn: async () => {
|
|
15556
|
+
const [input, output] = await Promise.all([
|
|
15557
|
+
client.getMetricAggregate({
|
|
15558
|
+
name: ["mastra_model_total_input_tokens"],
|
|
15559
|
+
aggregation: "sum",
|
|
15560
|
+
filters: { timestamp },
|
|
15561
|
+
comparePeriod: "previous_period"
|
|
15562
|
+
}),
|
|
15563
|
+
client.getMetricAggregate({
|
|
15564
|
+
name: ["mastra_model_total_output_tokens"],
|
|
15565
|
+
aggregation: "sum",
|
|
15566
|
+
filters: { timestamp },
|
|
15567
|
+
comparePeriod: "previous_period"
|
|
15568
|
+
})
|
|
15569
|
+
]);
|
|
15570
|
+
const hasCurrent = input.value != null || output.value != null;
|
|
15571
|
+
const hasPrevious = input.previousValue != null || output.previousValue != null;
|
|
15572
|
+
const value = (input.value ?? 0) + (output.value ?? 0);
|
|
15573
|
+
const previousValue = (input.previousValue ?? 0) + (output.previousValue ?? 0);
|
|
15574
|
+
const changePercent = hasPrevious && previousValue > 0 ? (value - previousValue) / previousValue * 100 : null;
|
|
15575
|
+
return {
|
|
15576
|
+
value: hasCurrent ? value : null,
|
|
15577
|
+
previousValue: hasPrevious ? previousValue : null,
|
|
15578
|
+
changePercent
|
|
15579
|
+
};
|
|
15580
|
+
}
|
|
15581
|
+
});
|
|
15582
|
+
}
|
|
15583
|
+
|
|
15584
|
+
function useModelUsageCostMetrics() {
|
|
15585
|
+
const client = useMastraClient();
|
|
15586
|
+
const { datePreset, customRange, timestamp } = useMetricsFilters();
|
|
15587
|
+
return useQuery({
|
|
15588
|
+
queryKey: ["metrics", "model-usage-cost", datePreset, customRange],
|
|
15589
|
+
queryFn: async () => {
|
|
15590
|
+
const metrics = [
|
|
15591
|
+
"mastra_model_total_input_tokens",
|
|
15592
|
+
"mastra_model_total_output_tokens",
|
|
15593
|
+
"mastra_model_input_cache_read_tokens",
|
|
15594
|
+
"mastra_model_input_cache_write_tokens"
|
|
15595
|
+
];
|
|
15596
|
+
const [inputRes, outputRes, cacheReadRes, cacheWriteRes] = await Promise.all(
|
|
15597
|
+
metrics.map(
|
|
15598
|
+
(name) => client.getMetricBreakdown({
|
|
15599
|
+
name: [name],
|
|
15600
|
+
groupBy: ["model"],
|
|
15601
|
+
aggregation: "sum",
|
|
15602
|
+
filters: { timestamp }
|
|
15603
|
+
})
|
|
15604
|
+
)
|
|
15605
|
+
);
|
|
15606
|
+
const modelMap = /* @__PURE__ */ new Map();
|
|
15607
|
+
const ensureModel = (model) => {
|
|
15608
|
+
if (!modelMap.has(model)) {
|
|
15609
|
+
modelMap.set(model, { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: null, costUnit: null });
|
|
15610
|
+
}
|
|
15611
|
+
return modelMap.get(model);
|
|
15612
|
+
};
|
|
15613
|
+
const addCost = (entry, group) => {
|
|
15614
|
+
if (group.estimatedCost != null) {
|
|
15615
|
+
entry.cost = (entry.cost ?? 0) + group.estimatedCost;
|
|
15616
|
+
if (group.costUnit) entry.costUnit = group.costUnit;
|
|
15617
|
+
}
|
|
15618
|
+
};
|
|
15619
|
+
for (const group of inputRes.groups) {
|
|
15620
|
+
const m = group.dimensions.model ?? "unknown";
|
|
15621
|
+
const entry = ensureModel(m);
|
|
15622
|
+
entry.input = group.value;
|
|
15623
|
+
addCost(entry, group);
|
|
15624
|
+
}
|
|
15625
|
+
for (const group of outputRes.groups) {
|
|
15626
|
+
const m = group.dimensions.model ?? "unknown";
|
|
15627
|
+
const entry = ensureModel(m);
|
|
15628
|
+
entry.output = group.value;
|
|
15629
|
+
addCost(entry, group);
|
|
15630
|
+
}
|
|
15631
|
+
for (const group of cacheReadRes.groups) {
|
|
15632
|
+
const m = group.dimensions.model ?? "unknown";
|
|
15633
|
+
const entry = ensureModel(m);
|
|
15634
|
+
entry.cacheRead = group.value;
|
|
15635
|
+
addCost(entry, group);
|
|
15636
|
+
}
|
|
15637
|
+
for (const group of cacheWriteRes.groups) {
|
|
15638
|
+
const m = group.dimensions.model ?? "unknown";
|
|
15639
|
+
const entry = ensureModel(m);
|
|
15640
|
+
entry.cacheWrite = group.value;
|
|
15641
|
+
addCost(entry, group);
|
|
15642
|
+
}
|
|
15643
|
+
return Array.from(modelMap.entries()).map(([model, vals]) => ({
|
|
15644
|
+
model,
|
|
15645
|
+
input: formatCompact(vals.input),
|
|
15646
|
+
output: formatCompact(vals.output),
|
|
15647
|
+
cacheRead: formatCompact(vals.cacheRead),
|
|
15648
|
+
cacheWrite: formatCompact(vals.cacheWrite),
|
|
15649
|
+
cost: vals.cost,
|
|
15650
|
+
costUnit: vals.costUnit
|
|
15651
|
+
})).sort((a, b) => a.model.localeCompare(b.model));
|
|
15652
|
+
}
|
|
15653
|
+
});
|
|
15654
|
+
}
|
|
15655
|
+
|
|
15656
|
+
async function fetchPercentiles(client, metricName, timestamp) {
|
|
15657
|
+
const res = await client.getMetricPercentiles({
|
|
15658
|
+
name: metricName,
|
|
15659
|
+
percentiles: [0.5, 0.95],
|
|
15660
|
+
interval: "1h",
|
|
15661
|
+
filters: { timestamp }
|
|
15662
|
+
});
|
|
15663
|
+
const p50Series = res.series.find((s) => s.percentile === 0.5);
|
|
15664
|
+
const p95Series = res.series.find((s) => s.percentile === 0.95);
|
|
15665
|
+
if (!p50Series || !p95Series) return [];
|
|
15666
|
+
const p95Map = new Map(p95Series.points.map((p) => [new Date(p.timestamp).getTime(), p.value]));
|
|
15667
|
+
return p50Series.points.map((p) => {
|
|
15668
|
+
const ts = new Date(p.timestamp);
|
|
15669
|
+
return {
|
|
15670
|
+
time: ts.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false }),
|
|
15671
|
+
p50: Math.round(p.value),
|
|
15672
|
+
p95: Math.round(p95Map.get(ts.getTime()) ?? 0)
|
|
15673
|
+
};
|
|
15674
|
+
});
|
|
15675
|
+
}
|
|
15676
|
+
function useLatencyMetrics() {
|
|
15677
|
+
const client = useMastraClient();
|
|
15678
|
+
const { datePreset, customRange, timestamp } = useMetricsFilters();
|
|
15679
|
+
return useQuery({
|
|
15680
|
+
queryKey: ["metrics", "latency", datePreset, customRange],
|
|
15681
|
+
queryFn: async () => {
|
|
15682
|
+
const [agentData, workflowData, toolData] = await Promise.all([
|
|
15683
|
+
fetchPercentiles(client, "mastra_agent_duration_ms", timestamp),
|
|
15684
|
+
fetchPercentiles(client, "mastra_workflow_duration_ms", timestamp),
|
|
15685
|
+
fetchPercentiles(client, "mastra_tool_duration_ms", timestamp)
|
|
15686
|
+
]);
|
|
15687
|
+
return { agentData, workflowData, toolData };
|
|
15688
|
+
}
|
|
15689
|
+
});
|
|
15690
|
+
}
|
|
15691
|
+
|
|
15692
|
+
async function fetchVolume(client, metricName, timestamp) {
|
|
15693
|
+
const res = await client.getMetricBreakdown({
|
|
15694
|
+
name: [metricName],
|
|
15695
|
+
groupBy: ["entityName", "status"],
|
|
15696
|
+
aggregation: "count",
|
|
15697
|
+
filters: { timestamp }
|
|
15698
|
+
});
|
|
15699
|
+
const map = /* @__PURE__ */ new Map();
|
|
15700
|
+
for (const group of res.groups) {
|
|
15701
|
+
const name = group.dimensions.entityName ?? "unknown";
|
|
15702
|
+
const status = group.dimensions.status ?? "ok";
|
|
15703
|
+
if (!map.has(name)) {
|
|
15704
|
+
map.set(name, { completed: 0, errors: 0 });
|
|
15705
|
+
}
|
|
15706
|
+
const entry = map.get(name);
|
|
15707
|
+
if (status === "error") {
|
|
15708
|
+
entry.errors += group.value;
|
|
15709
|
+
} else {
|
|
15710
|
+
entry.completed += group.value;
|
|
15711
|
+
}
|
|
15712
|
+
}
|
|
15713
|
+
return Array.from(map.entries()).map(([name, vals]) => ({ name, ...vals })).sort((a, b) => b.completed + b.errors - (a.completed + a.errors));
|
|
15714
|
+
}
|
|
15715
|
+
function useTraceVolumeMetrics() {
|
|
15716
|
+
const client = useMastraClient();
|
|
15717
|
+
const { datePreset, customRange, timestamp } = useMetricsFilters();
|
|
15718
|
+
return useQuery({
|
|
15719
|
+
queryKey: ["metrics", "trace-volume", datePreset, customRange],
|
|
15720
|
+
queryFn: async () => {
|
|
15721
|
+
const [agentData, workflowData, toolData] = await Promise.all([
|
|
15722
|
+
fetchVolume(client, "mastra_agent_duration_ms", timestamp),
|
|
15723
|
+
fetchVolume(client, "mastra_workflow_duration_ms", timestamp),
|
|
15724
|
+
fetchVolume(client, "mastra_tool_duration_ms", timestamp)
|
|
15725
|
+
]);
|
|
15726
|
+
return { agentData, workflowData, toolData };
|
|
15727
|
+
}
|
|
15728
|
+
});
|
|
15729
|
+
}
|
|
15730
|
+
|
|
15731
|
+
function useScoresMetrics() {
|
|
15732
|
+
const client = useMastraClient();
|
|
15733
|
+
const { datePreset, customRange, timestamp } = useMetricsFilters();
|
|
15734
|
+
return useQuery({
|
|
15735
|
+
queryKey: ["metrics", "scores-card", datePreset, customRange],
|
|
15736
|
+
queryFn: async () => {
|
|
15737
|
+
const filters = {
|
|
15738
|
+
timestamp: { start: timestamp.start, end: timestamp.end }
|
|
15739
|
+
};
|
|
15740
|
+
const scorersMap = await client.listScorers();
|
|
15741
|
+
const scorerIds = Object.keys(scorersMap ?? {});
|
|
15742
|
+
if (scorerIds.length === 0) {
|
|
15743
|
+
return { summaryData: [], overTimeData: [], scorerNames: [], avgScore: null };
|
|
15744
|
+
}
|
|
15745
|
+
const summaryResults = await Promise.all(
|
|
15746
|
+
scorerIds.map(async (scorerId) => {
|
|
15747
|
+
const [avg, min, max, count] = await Promise.all([
|
|
15748
|
+
client.getScoreAggregate({ scorerId, aggregation: "avg", filters }),
|
|
15749
|
+
client.getScoreAggregate({ scorerId, aggregation: "min", filters }),
|
|
15750
|
+
client.getScoreAggregate({ scorerId, aggregation: "max", filters }),
|
|
15751
|
+
client.getScoreAggregate({ scorerId, aggregation: "count", filters })
|
|
15752
|
+
]);
|
|
15753
|
+
return {
|
|
15754
|
+
scorer: scorerId,
|
|
15755
|
+
avg: avg.value ?? 0,
|
|
15756
|
+
min: min.value ?? 0,
|
|
15757
|
+
max: max.value ?? 0,
|
|
15758
|
+
count: count.value ?? 0
|
|
15759
|
+
};
|
|
15760
|
+
})
|
|
15761
|
+
);
|
|
15762
|
+
const summaryData = summaryResults.filter((s) => s.count > 0);
|
|
15763
|
+
const scorerNames = summaryData.map((s) => s.scorer);
|
|
15764
|
+
if (summaryData.length === 0) {
|
|
15765
|
+
return { summaryData: [], overTimeData: [], scorerNames: [], avgScore: null };
|
|
15766
|
+
}
|
|
15767
|
+
const totalWeighted = summaryData.reduce((s, d) => s + d.avg * d.count, 0);
|
|
15768
|
+
const totalCount = summaryData.reduce((s, d) => s + d.count, 0);
|
|
15769
|
+
const avgScore = totalCount ? Math.round(totalWeighted / totalCount * 100) / 100 : 0;
|
|
15770
|
+
const interval = "1h";
|
|
15771
|
+
const timeSeriesResults = await Promise.all(
|
|
15772
|
+
scorerNames.map(
|
|
15773
|
+
(scorerId) => client.getScoreTimeSeries({
|
|
15774
|
+
scorerId,
|
|
15775
|
+
interval,
|
|
15776
|
+
aggregation: "avg",
|
|
15777
|
+
filters
|
|
15778
|
+
})
|
|
15779
|
+
)
|
|
15780
|
+
);
|
|
15781
|
+
const hourBuckets = /* @__PURE__ */ new Map();
|
|
15782
|
+
for (let i = 0; i < scorerNames.length; i++) {
|
|
15783
|
+
const scorerId = scorerNames[i];
|
|
15784
|
+
const series = timeSeriesResults[i]?.series ?? [];
|
|
15785
|
+
for (const s of series) {
|
|
15786
|
+
for (const point of s.points) {
|
|
15787
|
+
const ts = new Date(point.timestamp);
|
|
15788
|
+
const hourKey = ts.toLocaleTimeString("en-US", {
|
|
15789
|
+
hour: "2-digit",
|
|
15790
|
+
minute: "2-digit",
|
|
15791
|
+
hour12: false
|
|
15792
|
+
});
|
|
15793
|
+
if (!hourBuckets.has(hourKey)) {
|
|
15794
|
+
hourBuckets.set(hourKey, /* @__PURE__ */ new Map());
|
|
15795
|
+
}
|
|
15796
|
+
const scorerMap = hourBuckets.get(hourKey);
|
|
15797
|
+
if (!scorerMap.has(scorerId)) {
|
|
15798
|
+
scorerMap.set(scorerId, { sum: 0, count: 0 });
|
|
15799
|
+
}
|
|
15800
|
+
const acc = scorerMap.get(scorerId);
|
|
15801
|
+
acc.sum += point.value;
|
|
15802
|
+
acc.count += 1;
|
|
15803
|
+
}
|
|
15804
|
+
}
|
|
15805
|
+
}
|
|
15806
|
+
const overTimeData = Array.from(hourBuckets.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([hourKey, scorerMap]) => {
|
|
15807
|
+
const point = { time: hourKey };
|
|
15808
|
+
for (const [scorerId, acc] of scorerMap) {
|
|
15809
|
+
point[scorerId] = +(acc.sum / acc.count).toFixed(2);
|
|
15810
|
+
}
|
|
15811
|
+
return point;
|
|
15812
|
+
});
|
|
15813
|
+
return {
|
|
15814
|
+
summaryData,
|
|
15815
|
+
overTimeData,
|
|
15816
|
+
scorerNames,
|
|
15817
|
+
avgScore
|
|
15818
|
+
};
|
|
15819
|
+
}
|
|
15820
|
+
});
|
|
15821
|
+
}
|
|
15822
|
+
|
|
15823
|
+
function useTokenUsageByAgentMetrics() {
|
|
15824
|
+
const client = useMastraClient();
|
|
15825
|
+
const { datePreset, customRange, timestamp } = useMetricsFilters();
|
|
15826
|
+
return useQuery({
|
|
15827
|
+
queryKey: ["metrics", "token-usage-by-agent", datePreset, customRange],
|
|
15828
|
+
queryFn: async () => {
|
|
15829
|
+
const [inputRes, outputRes, cacheReadRes, cacheWriteRes] = await Promise.all([
|
|
15830
|
+
client.getMetricBreakdown({
|
|
15831
|
+
name: ["mastra_model_total_input_tokens"],
|
|
15832
|
+
groupBy: ["entityName"],
|
|
15833
|
+
aggregation: "sum",
|
|
15834
|
+
filters: { timestamp }
|
|
15835
|
+
}),
|
|
15836
|
+
client.getMetricBreakdown({
|
|
15837
|
+
name: ["mastra_model_total_output_tokens"],
|
|
15838
|
+
groupBy: ["entityName"],
|
|
15839
|
+
aggregation: "sum",
|
|
15840
|
+
filters: { timestamp }
|
|
15841
|
+
}),
|
|
15842
|
+
client.getMetricBreakdown({
|
|
15843
|
+
name: ["mastra_model_input_cache_read_tokens"],
|
|
15844
|
+
groupBy: ["entityName"],
|
|
15845
|
+
aggregation: "sum",
|
|
15846
|
+
filters: { timestamp }
|
|
15847
|
+
}),
|
|
15848
|
+
client.getMetricBreakdown({
|
|
15849
|
+
name: ["mastra_model_input_cache_write_tokens"],
|
|
15850
|
+
groupBy: ["entityName"],
|
|
15851
|
+
aggregation: "sum",
|
|
15852
|
+
filters: { timestamp }
|
|
15853
|
+
})
|
|
15854
|
+
]);
|
|
15855
|
+
const agentMap = /* @__PURE__ */ new Map();
|
|
15856
|
+
const ensure = (name) => {
|
|
15857
|
+
if (!agentMap.has(name)) {
|
|
15858
|
+
agentMap.set(name, { input: 0, output: 0, cost: null, costUnit: null });
|
|
15859
|
+
}
|
|
15860
|
+
return agentMap.get(name);
|
|
15861
|
+
};
|
|
15862
|
+
const addCost = (entry, group) => {
|
|
15863
|
+
if (group.estimatedCost != null) {
|
|
15864
|
+
entry.cost = (entry.cost ?? 0) + group.estimatedCost;
|
|
15865
|
+
if (group.costUnit) entry.costUnit = group.costUnit;
|
|
15866
|
+
}
|
|
15867
|
+
};
|
|
15868
|
+
for (const group of inputRes.groups) {
|
|
15869
|
+
const name = group.dimensions.entityName ?? "unknown";
|
|
15870
|
+
const entry = ensure(name);
|
|
15871
|
+
entry.input = group.value;
|
|
15872
|
+
addCost(entry, group);
|
|
15873
|
+
}
|
|
15874
|
+
for (const group of outputRes.groups) {
|
|
15875
|
+
const name = group.dimensions.entityName ?? "unknown";
|
|
15876
|
+
const entry = ensure(name);
|
|
15877
|
+
entry.output = group.value;
|
|
15878
|
+
addCost(entry, group);
|
|
15879
|
+
}
|
|
15880
|
+
for (const group of cacheReadRes.groups) {
|
|
15881
|
+
const name = group.dimensions.entityName ?? "unknown";
|
|
15882
|
+
const entry = ensure(name);
|
|
15883
|
+
addCost(entry, group);
|
|
15884
|
+
}
|
|
15885
|
+
for (const group of cacheWriteRes.groups) {
|
|
15886
|
+
const name = group.dimensions.entityName ?? "unknown";
|
|
15887
|
+
const entry = ensure(name);
|
|
15888
|
+
addCost(entry, group);
|
|
15889
|
+
}
|
|
15890
|
+
return Array.from(agentMap.entries()).map(([name, vals]) => ({
|
|
15891
|
+
name,
|
|
15892
|
+
input: vals.input,
|
|
15893
|
+
output: vals.output,
|
|
15894
|
+
total: vals.input + vals.output,
|
|
15895
|
+
cost: vals.cost,
|
|
15896
|
+
costUnit: vals.costUnit
|
|
15897
|
+
})).sort((a, b) => b.total - a.total);
|
|
15898
|
+
}
|
|
15899
|
+
});
|
|
15900
|
+
}
|
|
15901
|
+
|
|
15902
|
+
const formatHierarchicalSpans = (spans) => {
|
|
15903
|
+
if (!spans || spans.length === 0) {
|
|
15904
|
+
return [];
|
|
15905
|
+
}
|
|
15906
|
+
const overallEndDate = spans.reduce(
|
|
15907
|
+
(latest, span) => {
|
|
15908
|
+
const endDate = span?.endedAt ? new Date(span.endedAt) : void 0;
|
|
15909
|
+
return endDate && (!latest || endDate > latest) ? endDate : latest;
|
|
15910
|
+
},
|
|
15911
|
+
null
|
|
15912
|
+
);
|
|
15913
|
+
const spanMap = /* @__PURE__ */ new Map();
|
|
15914
|
+
const rootSpans = [];
|
|
15915
|
+
spans.forEach((spanRecord) => {
|
|
15916
|
+
const startDate = new Date(spanRecord.startedAt);
|
|
15917
|
+
const endDate = spanRecord.endedAt ? new Date(spanRecord.endedAt) : void 0;
|
|
15918
|
+
const uiSpan = {
|
|
15919
|
+
id: spanRecord.spanId,
|
|
15920
|
+
name: spanRecord.name,
|
|
15921
|
+
type: spanRecord.spanType,
|
|
15922
|
+
latency: endDate ? endDate.getTime() - startDate.getTime() : 0,
|
|
15923
|
+
startTime: startDate.toISOString(),
|
|
15924
|
+
endTime: endDate ? endDate.toISOString() : void 0,
|
|
15925
|
+
spans: [],
|
|
15926
|
+
parentSpanId: spanRecord.parentSpanId
|
|
15927
|
+
};
|
|
15928
|
+
spanMap.set(spanRecord.spanId, uiSpan);
|
|
15929
|
+
});
|
|
15930
|
+
spans.forEach((spanRecord) => {
|
|
15931
|
+
const uiSpan = spanMap.get(spanRecord.spanId);
|
|
15932
|
+
if (spanRecord?.parentSpanId == null) {
|
|
15933
|
+
if (overallEndDate && uiSpan.endTime && overallEndDate > new Date(uiSpan.endTime)) {
|
|
15934
|
+
uiSpan.endTime = overallEndDate.toISOString();
|
|
15935
|
+
const overallEndTime = new Date(overallEndDate).getTime();
|
|
15936
|
+
const spanStartTime = new Date(uiSpan.startTime).getTime();
|
|
15937
|
+
uiSpan.latency = overallEndTime - spanStartTime;
|
|
15938
|
+
}
|
|
15939
|
+
rootSpans.push(uiSpan);
|
|
15940
|
+
} else {
|
|
15941
|
+
const parent = spanMap.get(spanRecord.parentSpanId);
|
|
15942
|
+
if (parent) {
|
|
15943
|
+
parent.spans.push(uiSpan);
|
|
15944
|
+
} else {
|
|
15945
|
+
rootSpans.push(uiSpan);
|
|
15946
|
+
}
|
|
15947
|
+
}
|
|
15948
|
+
});
|
|
15949
|
+
const sortSpansByStartTime = (spans2) => {
|
|
15950
|
+
return spans2.sort((a, b) => new Date(a.startTime).getTime() - new Date(b.startTime).getTime());
|
|
15951
|
+
};
|
|
15952
|
+
const sortedRootSpans = sortSpansByStartTime(rootSpans);
|
|
15953
|
+
const sortNestedSpans = (spans2) => {
|
|
15954
|
+
spans2.forEach((span) => {
|
|
15955
|
+
if (span.spans && span.spans.length > 0) {
|
|
15956
|
+
span.spans = sortSpansByStartTime(span.spans);
|
|
15957
|
+
sortNestedSpans(span.spans);
|
|
15958
|
+
}
|
|
15959
|
+
});
|
|
15960
|
+
};
|
|
15961
|
+
sortNestedSpans(sortedRootSpans);
|
|
15962
|
+
return sortedRootSpans;
|
|
15963
|
+
};
|
|
15964
|
+
|
|
15965
|
+
const spanTypePrefixes = ["agent", "workflow", "model", "mcp", "tool", "memory", "workspace", "other"];
|
|
15966
|
+
const spanTypeToUiElements = {
|
|
15967
|
+
agent: {
|
|
15968
|
+
icon: /* @__PURE__ */ jsx(AgentIcon, {}),
|
|
15969
|
+
color: "oklch(0.75 0.15 250)",
|
|
15970
|
+
label: "Agent",
|
|
15971
|
+
bgColor: "oklch(0.75 0.15 250 / 0.1)",
|
|
15972
|
+
typePrefix: "agent"
|
|
15973
|
+
},
|
|
15974
|
+
workflow: {
|
|
15975
|
+
icon: /* @__PURE__ */ jsx(WorkflowIcon, {}),
|
|
15976
|
+
color: "oklch(0.75 0.15 200)",
|
|
15977
|
+
label: "Workflow",
|
|
15978
|
+
bgColor: "oklch(0.75 0.15 200 / 0.1)",
|
|
15979
|
+
typePrefix: "workflow"
|
|
15980
|
+
},
|
|
15981
|
+
model: {
|
|
15982
|
+
icon: /* @__PURE__ */ jsx(BrainIcon, {}),
|
|
15983
|
+
color: "oklch(0.75 0.15 320)",
|
|
15984
|
+
label: "Model",
|
|
15985
|
+
bgColor: "oklch(0.75 0.15 320 / 0.1)",
|
|
15986
|
+
typePrefix: "model"
|
|
15987
|
+
},
|
|
15988
|
+
mcp: {
|
|
15989
|
+
icon: /* @__PURE__ */ jsx(McpServerIcon, {}),
|
|
15990
|
+
color: "oklch(0.75 0.15 160)",
|
|
15991
|
+
label: "MCP",
|
|
15992
|
+
bgColor: "oklch(0.75 0.15 160 / 0.1)",
|
|
15993
|
+
typePrefix: "mcp"
|
|
15994
|
+
},
|
|
15995
|
+
tool: {
|
|
15996
|
+
icon: /* @__PURE__ */ jsx(ToolsIcon, {}),
|
|
15997
|
+
color: "oklch(0.75 0.15 100)",
|
|
15998
|
+
label: "Tool",
|
|
15999
|
+
bgColor: "oklch(0.75 0.15 100 / 0.1)",
|
|
16000
|
+
typePrefix: "tool"
|
|
16001
|
+
},
|
|
16002
|
+
memory: {
|
|
16003
|
+
icon: /* @__PURE__ */ jsx(MemoryIcon, {}),
|
|
16004
|
+
color: "oklch(0.75 0.15 60)",
|
|
16005
|
+
label: "Memory",
|
|
16006
|
+
bgColor: "oklch(0.75 0.15 60 / 0.1)",
|
|
16007
|
+
typePrefix: "memory"
|
|
16008
|
+
},
|
|
16009
|
+
workspace: {
|
|
16010
|
+
icon: /* @__PURE__ */ jsx(FolderIcon, {}),
|
|
16011
|
+
color: "oklch(0.75 0.15 40)",
|
|
16012
|
+
label: "Workspace",
|
|
16013
|
+
bgColor: "oklch(0.75 0.15 40 / 0.1)",
|
|
16014
|
+
typePrefix: "workspace"
|
|
16015
|
+
}
|
|
16016
|
+
};
|
|
16017
|
+
const otherSpanType = {
|
|
16018
|
+
color: "oklch(0.65 0 0)",
|
|
16019
|
+
label: "Other",
|
|
16020
|
+
typePrefix: "other"
|
|
16021
|
+
};
|
|
16022
|
+
function getSpanTypeUi(type) {
|
|
16023
|
+
const typePrefix = type?.toLowerCase().split("_")[0];
|
|
16024
|
+
return spanTypeToUiElements[typePrefix] ?? otherSpanType;
|
|
16025
|
+
}
|
|
16026
|
+
|
|
16027
|
+
function isTokenDetailsObject(value) {
|
|
16028
|
+
return typeof value === "object" && value !== null;
|
|
16029
|
+
}
|
|
16030
|
+
const detailKeyLabels = {
|
|
16031
|
+
text: "Text",
|
|
16032
|
+
cacheRead: "Cache Read",
|
|
16033
|
+
cacheWrite: "Cache Write",
|
|
16034
|
+
audio: "Audio",
|
|
16035
|
+
image: "Image",
|
|
16036
|
+
reasoning: "Reasoning"
|
|
16037
|
+
};
|
|
16038
|
+
function SpanTokenUsage({ usage, className }) {
|
|
16039
|
+
if (!usage) return null;
|
|
16040
|
+
const isV5 = "inputTokens" in usage;
|
|
16041
|
+
const legacyTokenPresentations = {
|
|
16042
|
+
promptTokens: { label: "Prompt Tokens", icon: /* @__PURE__ */ jsx(ArrowRightIcon, {}) },
|
|
16043
|
+
completionTokens: { label: "Completion Tokens", icon: /* @__PURE__ */ jsx(ArrowRightToLineIcon, {}) }
|
|
16044
|
+
};
|
|
16045
|
+
const v5TokenPresentations = {
|
|
16046
|
+
inputTokens: { label: "Input Tokens", icon: /* @__PURE__ */ jsx(ArrowRightIcon, {}) },
|
|
16047
|
+
outputTokens: { label: "Output Tokens", icon: /* @__PURE__ */ jsx(ArrowRightToLineIcon, {}) },
|
|
16048
|
+
reasoningTokens: { label: "Reasoning Tokens", icon: /* @__PURE__ */ jsx(ArrowRightToLineIcon, {}) },
|
|
16049
|
+
cachedInputTokens: { label: "Cached Input Tokens", icon: /* @__PURE__ */ jsx(ArrowRightToLineIcon, {}) },
|
|
16050
|
+
inputDetails: { label: "Input Details", icon: /* @__PURE__ */ jsx(ArrowRightIcon, {}) },
|
|
16051
|
+
outputDetails: { label: "Output Details", icon: /* @__PURE__ */ jsx(ArrowRightToLineIcon, {}) }
|
|
16052
|
+
};
|
|
16053
|
+
const commonTokenPresentations = {
|
|
16054
|
+
totalTokens: { label: "Total LLM Tokens", icon: /* @__PURE__ */ jsx(CoinsIcon, {}) }
|
|
16055
|
+
};
|
|
16056
|
+
const tokenPresentations = {
|
|
16057
|
+
...commonTokenPresentations,
|
|
16058
|
+
...v5TokenPresentations,
|
|
16059
|
+
...legacyTokenPresentations
|
|
16060
|
+
};
|
|
16061
|
+
const usageKeyOrder = isV5 ? [
|
|
16062
|
+
"totalTokens",
|
|
16063
|
+
"inputTokens",
|
|
16064
|
+
"outputTokens",
|
|
16065
|
+
"reasoningTokens",
|
|
16066
|
+
"cachedInputTokens",
|
|
16067
|
+
"inputDetails",
|
|
16068
|
+
"outputDetails"
|
|
16069
|
+
] : ["totalTokens", "promptTokens", "completionTokens"];
|
|
16070
|
+
const usageAsArray = Object.entries(usage).filter((entry) => {
|
|
16071
|
+
const value = entry[1];
|
|
16072
|
+
return typeof value === "number" || isTokenDetailsObject(value);
|
|
16073
|
+
}).map(([key, value]) => ({ key, value })).sort((a, b) => usageKeyOrder.indexOf(a.key) - usageKeyOrder.indexOf(b.key));
|
|
16074
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex gap-6 flex-wrap", className), children: usageAsArray.map(({ key, value }) => {
|
|
16075
|
+
const isObject = isTokenDetailsObject(value);
|
|
16076
|
+
return /* @__PURE__ */ jsxs("div", { className: "bg-surface3 p-3 px-4 rounded-lg text-ui-md grow", children: [
|
|
16077
|
+
/* @__PURE__ */ jsxs(
|
|
16078
|
+
"div",
|
|
16079
|
+
{
|
|
16080
|
+
className: cn(
|
|
16081
|
+
"grid grid-cols-[1.5rem_1fr_auto] gap-2 items-center",
|
|
16082
|
+
"[&>svg]:w-[1.5em] [&>svg]:h-[1.5em] [&>svg]:opacity-70"
|
|
16083
|
+
),
|
|
16084
|
+
children: [
|
|
16085
|
+
tokenPresentations?.[key]?.icon,
|
|
16086
|
+
/* @__PURE__ */ jsx("span", { className: "text-ui-md", children: tokenPresentations?.[key]?.label }),
|
|
16087
|
+
!isObject && /* @__PURE__ */ jsx("b", { className: "text-ui-lg", children: value })
|
|
16088
|
+
]
|
|
16089
|
+
}
|
|
16090
|
+
),
|
|
16091
|
+
isObject && /* @__PURE__ */ jsx("div", { className: "text-ui-md mt-2 pl-8", children: Object.entries(value).map(([detailKey, detailValue]) => {
|
|
16092
|
+
if (typeof detailValue !== "number") return null;
|
|
16093
|
+
return /* @__PURE__ */ jsxs(
|
|
16094
|
+
"dl",
|
|
16095
|
+
{
|
|
16096
|
+
className: "grid grid-cols-[1fr_auto] gap-x-4 gap-y-1 justify-between text-neutral3",
|
|
16097
|
+
children: [
|
|
16098
|
+
/* @__PURE__ */ jsx("dt", { children: detailKeyLabels[detailKey] || detailKey }),
|
|
16099
|
+
/* @__PURE__ */ jsx("dd", { children: detailValue })
|
|
16100
|
+
]
|
|
16101
|
+
},
|
|
16102
|
+
detailKey
|
|
16103
|
+
);
|
|
16104
|
+
}) })
|
|
16105
|
+
] }, key);
|
|
16106
|
+
}) });
|
|
16107
|
+
}
|
|
16108
|
+
|
|
16109
|
+
function TimelineExpandCol({
|
|
16110
|
+
isSelected,
|
|
16111
|
+
isFaded,
|
|
16112
|
+
isExpanded,
|
|
16113
|
+
toggleChildren,
|
|
16114
|
+
expandAllDescendants,
|
|
16115
|
+
totalDescendants = 0,
|
|
16116
|
+
allDescendantsExpanded,
|
|
16117
|
+
numOfChildren
|
|
16118
|
+
}) {
|
|
16119
|
+
return /* @__PURE__ */ jsx(
|
|
16120
|
+
"div",
|
|
16121
|
+
{
|
|
16122
|
+
className: cn("flex items-center justify-end h-full px-1.5", {
|
|
16123
|
+
"opacity-30 [&:hover]:opacity-60": isFaded,
|
|
16124
|
+
"bg-surface4": isSelected
|
|
16125
|
+
}),
|
|
16126
|
+
children: numOfChildren && numOfChildren > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex gap-1", children: [
|
|
16127
|
+
/* @__PURE__ */ jsxs(ExpandButton, { onClick: () => toggleChildren?.(), children: [
|
|
16128
|
+
allDescendantsExpanded ? totalDescendants : numOfChildren,
|
|
16129
|
+
" ",
|
|
16130
|
+
isExpanded ? allDescendantsExpanded ? /* @__PURE__ */ jsx(ChevronsUpIcon, {}) : /* @__PURE__ */ jsx(ChevronUpIcon, {}) : /* @__PURE__ */ jsx(ChevronDownIcon, {})
|
|
16131
|
+
] }),
|
|
16132
|
+
totalDescendants > numOfChildren && !allDescendantsExpanded && /* @__PURE__ */ jsxs(ExpandButton, { onClick: () => expandAllDescendants?.(), children: [
|
|
16133
|
+
totalDescendants,
|
|
16134
|
+
" ",
|
|
16135
|
+
/* @__PURE__ */ jsx(ChevronsDownIcon, {})
|
|
16136
|
+
] })
|
|
16137
|
+
] }) : null
|
|
16138
|
+
}
|
|
16139
|
+
);
|
|
16140
|
+
}
|
|
16141
|
+
function ExpandButton({ onClick, children, className }) {
|
|
16142
|
+
return /* @__PURE__ */ jsx("button", { onClick, className: cn("h-full", className), children: /* @__PURE__ */ jsx(
|
|
16143
|
+
"div",
|
|
16144
|
+
{
|
|
16145
|
+
className: cn(
|
|
16146
|
+
"flex items-center gap-[0.1rem] text-ui-xs text-neutral5 border border-border1 pl-1.5 pr-0.5 rounded-md transition-all",
|
|
16147
|
+
"hover:text-yellow-500",
|
|
16148
|
+
"[&>svg]:shrink-0 [&>svg]:opacity-80 [&>svg]:w-[0.85rem] [&>svg]:h-[0.85rem] [&>svg]:transition-all"
|
|
16149
|
+
),
|
|
16150
|
+
children
|
|
16151
|
+
}
|
|
16152
|
+
) });
|
|
16153
|
+
}
|
|
16154
|
+
|
|
16155
|
+
function TimelineStructureSign({ isLastChild }) {
|
|
16156
|
+
return /* @__PURE__ */ jsx(
|
|
16157
|
+
"div",
|
|
16158
|
+
{
|
|
16159
|
+
className: cn(
|
|
16160
|
+
"w-[0.5rem] h-[1.8rem] relative opacity-100 shrink-0",
|
|
16161
|
+
'after:content-[""] after:absolute after:left-[-1px] after:top-0 after:bottom-0 after:w-[0px] after:border-l-[1px] after:border-neutral3 after:border-dashed ',
|
|
16162
|
+
'before:content-[""] before:absolute before:left-0 before:top-[50%] before:w-full before:h-[0px] before:border-b-[1px] before:border-neutral3 before:border-dashed',
|
|
16163
|
+
{
|
|
16164
|
+
"after:bottom-[50%]": isLastChild
|
|
16165
|
+
}
|
|
16166
|
+
)
|
|
16167
|
+
}
|
|
16168
|
+
);
|
|
16169
|
+
}
|
|
16170
|
+
|
|
16171
|
+
function TimelineNameCol({
|
|
16172
|
+
span,
|
|
16173
|
+
spanUI: _spanUI,
|
|
16174
|
+
isFaded,
|
|
16175
|
+
depth = 0,
|
|
16176
|
+
onSpanClick,
|
|
16177
|
+
selectedSpanId,
|
|
16178
|
+
isLastChild,
|
|
16179
|
+
hasChildren: _hasChildren,
|
|
16180
|
+
isRootSpan,
|
|
16181
|
+
isExpanded: _isExpanded
|
|
16182
|
+
}) {
|
|
16183
|
+
return /* @__PURE__ */ jsxs(
|
|
16184
|
+
"div",
|
|
16185
|
+
{
|
|
16186
|
+
"data-span-id": span.id,
|
|
16187
|
+
"aria-label": `View details for span ${span.name}`,
|
|
16188
|
+
className: cn("rounded-md flex opacity-80 min-h-8 items-center rounded-l-lg", {
|
|
16189
|
+
"opacity-30 [&:hover]:opacity-60": isFaded,
|
|
16190
|
+
"bg-surface4": selectedSpanId === span.id
|
|
16191
|
+
}),
|
|
16192
|
+
style: { paddingLeft: `${depth * 1}rem` },
|
|
16193
|
+
children: [
|
|
16194
|
+
!isRootSpan && /* @__PURE__ */ jsx(TimelineStructureSign, { isLastChild }),
|
|
16195
|
+
/* @__PURE__ */ jsx(
|
|
16196
|
+
"button",
|
|
16197
|
+
{
|
|
16198
|
+
onClick: () => onSpanClick?.(span.id),
|
|
16199
|
+
className: cn(
|
|
16200
|
+
"text-ui-sm flex items-center text-left gap-1.5 text-neutral6 w-full min-w-0 rounded-md h-full px-2 py-1 transition-colors",
|
|
16201
|
+
"[&>svg]:transition-all [&>svg]:shrink-0 [&>svg]:opacity-0 [&>svg]:w-[1em] [&>svg]:h-[1em] [&>svg]:ml-auto",
|
|
16202
|
+
"hover:bg-surface4 [&:hover>svg]:opacity-60",
|
|
16203
|
+
"focus:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-accent1"
|
|
16204
|
+
),
|
|
16205
|
+
children: /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: span.name })
|
|
16206
|
+
}
|
|
16207
|
+
)
|
|
16208
|
+
]
|
|
16209
|
+
}
|
|
16210
|
+
);
|
|
16211
|
+
}
|
|
16212
|
+
|
|
16213
|
+
function TimelineTimingCol({
|
|
16214
|
+
span,
|
|
16215
|
+
selectedSpanId,
|
|
16216
|
+
isFaded,
|
|
16217
|
+
overallLatency,
|
|
16218
|
+
overallStartTime,
|
|
16219
|
+
color,
|
|
16220
|
+
chartWidth = "default"
|
|
16221
|
+
}) {
|
|
16222
|
+
const percentageSpanLatency = overallLatency ? Math.ceil(span.latency / overallLatency * 100) : 0;
|
|
16223
|
+
const overallStartTimeDate = overallStartTime ? new Date(overallStartTime) : null;
|
|
16224
|
+
const spanStartTimeDate = span.startTime ? new Date(span.startTime) : null;
|
|
16225
|
+
const spanStartTimeShift = spanStartTimeDate && overallStartTimeDate ? spanStartTimeDate.getTime() - overallStartTimeDate.getTime() : 0;
|
|
16226
|
+
const percentageSpanStartTime = overallLatency && Math.floor(spanStartTimeShift / overallLatency * 100);
|
|
16227
|
+
return /* @__PURE__ */ jsxs(HoverCard.Root, { openDelay: 250, children: [
|
|
16228
|
+
/* @__PURE__ */ jsxs(
|
|
16229
|
+
HoverCard.Trigger,
|
|
16230
|
+
{
|
|
16231
|
+
className: cn(
|
|
16232
|
+
"h-8 p-1 grid grid-cols-[1fr_auto] gap-2 items-center cursor-help pr-2 rounded-r-md",
|
|
16233
|
+
chartWidth === "wide" ? "min-w-72" : "min-w-32",
|
|
16234
|
+
"[&:hover>div]:bg-surface5",
|
|
16235
|
+
{
|
|
16236
|
+
"opacity-30 [&:hover]:opacity-60": isFaded,
|
|
16237
|
+
"bg-surface4": selectedSpanId === span.id
|
|
16238
|
+
}
|
|
16239
|
+
),
|
|
16240
|
+
children: [
|
|
16241
|
+
/* @__PURE__ */ jsx("div", { className: cn("w-full p-1.5 rounded-md bg-surface4 transition-colors duration-1000"), children: /* @__PURE__ */ jsx("div", { className: "relative w-full h-1.5 rounded-sm overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
16242
|
+
"div",
|
|
16243
|
+
{
|
|
16244
|
+
className: cn("bg-neutral1 absolute rounded-sm h-1.5 top-0"),
|
|
16245
|
+
style: {
|
|
16246
|
+
width: percentageSpanLatency ? `${percentageSpanLatency}%` : "2px",
|
|
16247
|
+
left: `${percentageSpanStartTime || 0}%`,
|
|
16248
|
+
backgroundColor: color
|
|
16249
|
+
}
|
|
16250
|
+
}
|
|
16251
|
+
) }) }),
|
|
16252
|
+
/* @__PURE__ */ jsxs("div", { className: cn("flex justify-end text-neutral3 text-ui-xs"), children: [
|
|
16253
|
+
(span.latency / 1e3).toFixed(3),
|
|
16254
|
+
" s"
|
|
16255
|
+
] })
|
|
16256
|
+
]
|
|
16257
|
+
}
|
|
16258
|
+
),
|
|
16259
|
+
/* @__PURE__ */ jsx(HoverCard.Portal, { children: /* @__PURE__ */ jsxs(
|
|
16260
|
+
HoverCard.Content,
|
|
16261
|
+
{
|
|
16262
|
+
className: "z-50 w-auto max-w-100 rounded-md bg-surface4 p-2 px-4 pr-6 text-ui-sm text-neutral5 border border-border1",
|
|
16263
|
+
sideOffset: 5,
|
|
16264
|
+
side: "top",
|
|
16265
|
+
children: [
|
|
16266
|
+
/* @__PURE__ */ jsx("div", { className: cn("text-ui-sm flex items-center gap-2 mb-2 mt-1"), children: "Span Timing" }),
|
|
16267
|
+
/* @__PURE__ */ jsxs(DataKeysAndValues, { children: [
|
|
16268
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Latency" }),
|
|
16269
|
+
/* @__PURE__ */ jsxs(DataKeysAndValues.Value, { children: [
|
|
16270
|
+
span.latency,
|
|
16271
|
+
" ms"
|
|
16272
|
+
] }),
|
|
16273
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Started at" }),
|
|
16274
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: span.startTime ? format$1(new Date(span.startTime), "hh:mm:ss:SSS a") : "-" }),
|
|
16275
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Ended at" }),
|
|
16276
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: span.endTime ? format$1(new Date(span.endTime), "hh:mm:ss:SSS a") : "-" }),
|
|
16277
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Start Shift" }),
|
|
16278
|
+
/* @__PURE__ */ jsxs(DataKeysAndValues.Value, { children: [
|
|
16279
|
+
spanStartTimeShift,
|
|
16280
|
+
"ms"
|
|
16281
|
+
] })
|
|
16282
|
+
] }),
|
|
16283
|
+
/* @__PURE__ */ jsx(HoverCard.Arrow, { className: "fill-surface5" })
|
|
16284
|
+
]
|
|
16285
|
+
}
|
|
16286
|
+
) })
|
|
16287
|
+
] });
|
|
16288
|
+
}
|
|
16289
|
+
|
|
16290
|
+
function computeTraceStatus(span) {
|
|
16291
|
+
if (span.error != null) return "error" /* ERROR */;
|
|
16292
|
+
if (span.endedAt == null) return "running" /* RUNNING */;
|
|
16293
|
+
return "success" /* SUCCESS */;
|
|
16294
|
+
}
|
|
16295
|
+
function TraceKeysAndValues({ rootSpan, numOfCol = 2, className }) {
|
|
16296
|
+
const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;
|
|
16297
|
+
const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;
|
|
16298
|
+
const status = computeTraceStatus(rootSpan);
|
|
16299
|
+
const statusLabel = status === "error" /* ERROR */ ? "ERROR" : status === "running" /* RUNNING */ ? "RUNNING" : "SUCCESS";
|
|
16300
|
+
return /* @__PURE__ */ jsxs(DataKeysAndValues, { numOfCol, className, children: [
|
|
16301
|
+
rootSpan.entityId && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16302
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Entity Id" }),
|
|
16303
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: rootSpan.entityName || rootSpan.entityId })
|
|
16304
|
+
] }),
|
|
16305
|
+
rootSpan.entityType && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16306
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Entity Type" }),
|
|
16307
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: rootSpan.entityType })
|
|
16308
|
+
] }),
|
|
16309
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Status" }),
|
|
16310
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: statusLabel }),
|
|
16311
|
+
startedAt && endedAt && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16312
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Duration" }),
|
|
16313
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: `${(endedAt.getTime() - startedAt.getTime()).toLocaleString()}ms` })
|
|
16314
|
+
] }),
|
|
16315
|
+
startedAt && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16316
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Started at" }),
|
|
16317
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: format(startedAt, "MMM dd, h:mm:ss.SSS aaa") })
|
|
16318
|
+
] }),
|
|
16319
|
+
endedAt && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16320
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Ended at" }),
|
|
16321
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: format(endedAt, "MMM dd, h:mm:ss.SSS aaa") })
|
|
16322
|
+
] })
|
|
16323
|
+
] });
|
|
16324
|
+
}
|
|
16325
|
+
|
|
16326
|
+
function getSpanDescendantIds(span) {
|
|
16327
|
+
if (!span.spans || span.spans.length === 0) {
|
|
16328
|
+
return [];
|
|
16329
|
+
}
|
|
16330
|
+
const descendantIds = [];
|
|
16331
|
+
span.spans.forEach((childSpan) => {
|
|
16332
|
+
descendantIds.push(childSpan.id);
|
|
16333
|
+
descendantIds.push(...getSpanDescendantIds(childSpan));
|
|
16334
|
+
});
|
|
16335
|
+
return descendantIds;
|
|
16336
|
+
}
|
|
16337
|
+
function getAllSpanIds(spans) {
|
|
16338
|
+
const ids = [];
|
|
16339
|
+
for (const span of spans) {
|
|
16340
|
+
ids.push(span.id);
|
|
16341
|
+
ids.push(...getSpanDescendantIds(span));
|
|
16342
|
+
}
|
|
16343
|
+
return ids;
|
|
16344
|
+
}
|
|
16345
|
+
|
|
16346
|
+
function TraceTimelineSpan({
|
|
16347
|
+
span,
|
|
16348
|
+
depth = 0,
|
|
16349
|
+
onSpanClick,
|
|
16350
|
+
selectedSpanId,
|
|
16351
|
+
isLastChild,
|
|
16352
|
+
overallLatency,
|
|
16353
|
+
overallStartTime,
|
|
16354
|
+
fadedTypes,
|
|
16355
|
+
searchPhrase,
|
|
16356
|
+
featuredSpanIds,
|
|
16357
|
+
expandedSpanIds,
|
|
16358
|
+
setExpandedSpanIds,
|
|
16359
|
+
chartWidth
|
|
16360
|
+
}) {
|
|
16361
|
+
const hasChildren = span.spans && span.spans.length > 0;
|
|
16362
|
+
const numOfChildren = span.spans ? span.spans.length : 0;
|
|
16363
|
+
const allDescendantIds = getSpanDescendantIds(span);
|
|
16364
|
+
const totalDescendants = allDescendantIds.length;
|
|
16365
|
+
const isRootSpan = depth === 0;
|
|
16366
|
+
const spanUI = getSpanTypeUi(span?.type);
|
|
16367
|
+
const isExpanded = expandedSpanIds ? expandedSpanIds.includes(span.id) : false;
|
|
16368
|
+
const isFadedBySearch = featuredSpanIds && featuredSpanIds.length > 0 ? !featuredSpanIds.includes(span.id) : false;
|
|
16369
|
+
const isFadedByType = fadedTypes && fadedTypes.length > 0 ? fadedTypes.includes(spanUI?.typePrefix || "") : false;
|
|
16370
|
+
const isFaded = isFadedByType || isFadedBySearch;
|
|
16371
|
+
useEffect(() => {
|
|
16372
|
+
if (!featuredSpanIds || allDescendantIds.length === 0) return;
|
|
16373
|
+
if (isExpanded) return;
|
|
16374
|
+
const hasFeaturedDescendant = allDescendantIds.some((id) => featuredSpanIds.includes(id));
|
|
16375
|
+
if (hasFeaturedDescendant && setExpandedSpanIds) {
|
|
16376
|
+
setExpandedSpanIds((prev) => !prev || prev.includes(span.id) ? prev ?? [span.id] : [...prev, span.id]);
|
|
16377
|
+
}
|
|
16378
|
+
}, [featuredSpanIds, allDescendantIds]);
|
|
16379
|
+
const toggleChildren = () => {
|
|
16380
|
+
if (!setExpandedSpanIds) return;
|
|
16381
|
+
setExpandedSpanIds((prev) => {
|
|
16382
|
+
if (!prev) return prev;
|
|
16383
|
+
const idsToRemove = /* @__PURE__ */ new Set([span.id, ...allDescendantIds]);
|
|
16384
|
+
return isExpanded ? prev.filter((id) => !idsToRemove.has(id)) : [...prev, span.id];
|
|
16385
|
+
});
|
|
16386
|
+
};
|
|
16387
|
+
const expandAllDescendants = () => {
|
|
16388
|
+
if (!setExpandedSpanIds) return;
|
|
16389
|
+
setExpandedSpanIds((prev) => {
|
|
16390
|
+
if (!prev) return prev;
|
|
16391
|
+
return Array.from(/* @__PURE__ */ new Set([...prev, span.id, ...allDescendantIds]));
|
|
16392
|
+
});
|
|
16393
|
+
};
|
|
16394
|
+
const allDescendantsExpanded = allDescendantIds.every((id) => expandedSpanIds?.includes(id));
|
|
16395
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16396
|
+
/* @__PURE__ */ jsx(
|
|
16397
|
+
TimelineNameCol,
|
|
16398
|
+
{
|
|
16399
|
+
span,
|
|
16400
|
+
spanUI,
|
|
16401
|
+
isFaded,
|
|
16402
|
+
depth,
|
|
16403
|
+
onSpanClick,
|
|
16404
|
+
selectedSpanId,
|
|
16405
|
+
isLastChild,
|
|
16406
|
+
hasChildren,
|
|
16407
|
+
isRootSpan,
|
|
16408
|
+
isExpanded
|
|
16409
|
+
}
|
|
16410
|
+
),
|
|
16411
|
+
/* @__PURE__ */ jsx(
|
|
16412
|
+
TimelineExpandCol,
|
|
16413
|
+
{
|
|
16414
|
+
isSelected: selectedSpanId === span.id,
|
|
16415
|
+
isFaded,
|
|
16416
|
+
isExpanded,
|
|
16417
|
+
toggleChildren,
|
|
16418
|
+
expandAllDescendants,
|
|
16419
|
+
totalDescendants,
|
|
16420
|
+
allDescendantsExpanded,
|
|
16421
|
+
numOfChildren
|
|
16422
|
+
}
|
|
16423
|
+
),
|
|
16424
|
+
/* @__PURE__ */ jsx(
|
|
16425
|
+
TimelineTimingCol,
|
|
16426
|
+
{
|
|
16427
|
+
span,
|
|
16428
|
+
selectedSpanId,
|
|
16429
|
+
isFaded,
|
|
16430
|
+
overallLatency,
|
|
16431
|
+
overallStartTime,
|
|
16432
|
+
color: spanUI?.color,
|
|
16433
|
+
chartWidth
|
|
16434
|
+
}
|
|
16435
|
+
),
|
|
16436
|
+
hasChildren && isExpanded && span.spans?.map((childSpan, idx, array) => {
|
|
16437
|
+
const isLast = idx === array.length - 1;
|
|
16438
|
+
return /* @__PURE__ */ jsx(
|
|
16439
|
+
TraceTimelineSpan,
|
|
16440
|
+
{
|
|
16441
|
+
span: childSpan,
|
|
16442
|
+
depth: depth + 1,
|
|
16443
|
+
onSpanClick,
|
|
16444
|
+
selectedSpanId,
|
|
16445
|
+
isLastChild: isLast,
|
|
16446
|
+
overallLatency,
|
|
16447
|
+
overallStartTime,
|
|
16448
|
+
fadedTypes,
|
|
16449
|
+
searchPhrase,
|
|
16450
|
+
expandedSpanIds,
|
|
16451
|
+
setExpandedSpanIds,
|
|
16452
|
+
featuredSpanIds,
|
|
16453
|
+
chartWidth
|
|
16454
|
+
},
|
|
16455
|
+
childSpan.id
|
|
16456
|
+
);
|
|
16457
|
+
})
|
|
16458
|
+
] });
|
|
16459
|
+
}
|
|
16460
|
+
|
|
16461
|
+
function TraceTimeline({
|
|
16462
|
+
hierarchicalSpans = [],
|
|
16463
|
+
onSpanClick,
|
|
16464
|
+
selectedSpanId,
|
|
16465
|
+
isLoading,
|
|
16466
|
+
fadedTypes,
|
|
16467
|
+
expandedSpanIds,
|
|
16468
|
+
setExpandedSpanIds,
|
|
16469
|
+
featuredSpanIds,
|
|
16470
|
+
chartWidth = "default"
|
|
16471
|
+
}) {
|
|
16472
|
+
const overallLatency = hierarchicalSpans?.[0]?.latency || 0;
|
|
16473
|
+
const overallStartTime = hierarchicalSpans?.[0]?.startTime || "";
|
|
16474
|
+
const usedSpanTypes = useMemo(() => {
|
|
16475
|
+
const collectTypes = (spans) => {
|
|
16476
|
+
const types2 = /* @__PURE__ */ new Set();
|
|
16477
|
+
for (const span of spans) {
|
|
16478
|
+
const prefix = span.type?.toLowerCase().split("_")[0];
|
|
16479
|
+
if (prefix) types2.add(prefix);
|
|
16480
|
+
if (span.spans) {
|
|
16481
|
+
for (const t of collectTypes(span.spans)) types2.add(t);
|
|
16482
|
+
}
|
|
16483
|
+
}
|
|
16484
|
+
return types2;
|
|
16485
|
+
};
|
|
16486
|
+
const types = collectTypes(hierarchicalSpans);
|
|
16487
|
+
const hasOther = [...types].some((t) => !spanTypePrefixes.includes(t));
|
|
16488
|
+
const known = spanTypePrefixes.filter((p) => p !== "other" && types.has(p));
|
|
16489
|
+
if (hasOther) known.push("other");
|
|
16490
|
+
return known;
|
|
16491
|
+
}, [hierarchicalSpans]);
|
|
16492
|
+
return /* @__PURE__ */ jsx(Fragment, { children: isLoading ? /* @__PURE__ */ jsxs(
|
|
16493
|
+
"div",
|
|
16494
|
+
{
|
|
16495
|
+
className: cn(
|
|
16496
|
+
"flex items-center text-ui-sm gap-3 bg-surface3/50 rounded-md p-3 justify-center text-neutral3",
|
|
16497
|
+
"[&_svg]:w-[1.25em] [&_svg]:h-[1.25em] [&_svg]:opacity-50"
|
|
16498
|
+
),
|
|
16499
|
+
children: [
|
|
16500
|
+
/* @__PURE__ */ jsx(Spinner, {}),
|
|
16501
|
+
" Loading Trace Timeline ..."
|
|
16502
|
+
]
|
|
16503
|
+
}
|
|
16504
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16505
|
+
usedSpanTypes.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3 px-2 py-1.5 justify-end", children: usedSpanTypes.map((type) => {
|
|
16506
|
+
const spanUI = getSpanTypeUi(type);
|
|
16507
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-ui-sm text-neutral3", children: [
|
|
16508
|
+
/* @__PURE__ */ jsx(
|
|
16509
|
+
"span",
|
|
16510
|
+
{
|
|
16511
|
+
className: "inline-block w-1.5 h-1.5 rounded-full shrink-0",
|
|
16512
|
+
style: { backgroundColor: spanUI?.color }
|
|
16513
|
+
}
|
|
16514
|
+
),
|
|
16515
|
+
spanUI?.label || type
|
|
16516
|
+
] }, type);
|
|
16517
|
+
}) }),
|
|
16518
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-[minmax(0,1fr)_auto_auto] items-start content-start gap-y-px overflow-hidden py-1", children: hierarchicalSpans?.map((span) => /* @__PURE__ */ jsx(
|
|
16519
|
+
TraceTimelineSpan,
|
|
16520
|
+
{
|
|
16521
|
+
span,
|
|
16522
|
+
onSpanClick,
|
|
16523
|
+
selectedSpanId,
|
|
16524
|
+
overallLatency,
|
|
16525
|
+
overallStartTime,
|
|
16526
|
+
fadedTypes,
|
|
16527
|
+
featuredSpanIds,
|
|
16528
|
+
expandedSpanIds,
|
|
16529
|
+
setExpandedSpanIds,
|
|
16530
|
+
chartWidth
|
|
16531
|
+
},
|
|
16532
|
+
span.id
|
|
16533
|
+
)) })
|
|
16534
|
+
] }) });
|
|
16535
|
+
}
|
|
16536
|
+
|
|
16537
|
+
function TracesToolbar({
|
|
16538
|
+
onClear,
|
|
16539
|
+
onRemoveAll,
|
|
16540
|
+
onSave,
|
|
16541
|
+
onRemoveSaved,
|
|
16542
|
+
isLoading,
|
|
16543
|
+
filterFields,
|
|
16544
|
+
filterTokens,
|
|
16545
|
+
onFilterTokensChange,
|
|
16546
|
+
autoFocusFilterFieldId
|
|
16547
|
+
}) {
|
|
16548
|
+
const hasActiveFilters = filterTokens.length > 0;
|
|
16549
|
+
const hasNonDefaultFilter = filterTokens.some((token) => isNonDefaultFilter$1(token, filterFields));
|
|
16550
|
+
return (
|
|
16551
|
+
// 1fr | auto — pills wrap in the first column; Clear stays pinned to the
|
|
16552
|
+
// top of the second column regardless of how many pill rows render.
|
|
16553
|
+
/* @__PURE__ */ jsxs("div", { className: cn("grid grid-cols-[1fr_auto] gap-3 items-start "), children: [
|
|
16554
|
+
/* @__PURE__ */ jsx(
|
|
16555
|
+
PropertyFilterApplied,
|
|
16556
|
+
{
|
|
16557
|
+
fields: filterFields,
|
|
16558
|
+
tokens: filterTokens,
|
|
16559
|
+
onTokensChange: onFilterTokensChange,
|
|
16560
|
+
disabled: isLoading,
|
|
16561
|
+
autoFocusFieldId: autoFocusFilterFieldId
|
|
16562
|
+
}
|
|
16563
|
+
),
|
|
16564
|
+
hasActiveFilters && /* @__PURE__ */ jsx(
|
|
16565
|
+
PropertyFilterActions,
|
|
16566
|
+
{
|
|
16567
|
+
disabled: isLoading,
|
|
16568
|
+
onClear: hasNonDefaultFilter ? onClear : void 0,
|
|
16569
|
+
onRemoveAll,
|
|
16570
|
+
onSave,
|
|
16571
|
+
onRemoveSaved
|
|
16572
|
+
}
|
|
16573
|
+
)
|
|
16574
|
+
] })
|
|
16575
|
+
);
|
|
16576
|
+
}
|
|
16577
|
+
function isNonDefaultFilter$1(token, fields) {
|
|
16578
|
+
const field = fields.find((f) => f.id === token.fieldId);
|
|
16579
|
+
if (!field) return false;
|
|
16580
|
+
if (field.kind === "text") {
|
|
16581
|
+
return typeof token.value === "string" && token.value.trim() !== "";
|
|
16582
|
+
}
|
|
16583
|
+
if (field.kind === "pick-multi") {
|
|
16584
|
+
if (field.multi) return Array.isArray(token.value) && token.value.length > 0;
|
|
16585
|
+
return typeof token.value === "string" && token.value !== "" && token.value !== "Any";
|
|
16586
|
+
}
|
|
16587
|
+
if (field.kind === "multi-select") {
|
|
16588
|
+
return Array.isArray(token.value) && token.value.length > 0;
|
|
16589
|
+
}
|
|
16590
|
+
return false;
|
|
16591
|
+
}
|
|
16592
|
+
|
|
16593
|
+
function TraceDataPanelView({
|
|
16594
|
+
traceId,
|
|
16595
|
+
spans,
|
|
16596
|
+
isLoading,
|
|
16597
|
+
onClose,
|
|
16598
|
+
onSpanSelect,
|
|
16599
|
+
onEvaluateTrace,
|
|
16600
|
+
onSaveAsDatasetItem,
|
|
16601
|
+
initialSpanId,
|
|
16602
|
+
onPrevious,
|
|
16603
|
+
onNext,
|
|
16604
|
+
collapsed: controlledCollapsed,
|
|
16605
|
+
onCollapsedChange,
|
|
16606
|
+
placement,
|
|
16607
|
+
timelineChartWidth = "default",
|
|
16608
|
+
LinkComponent,
|
|
16609
|
+
traceHref
|
|
16610
|
+
}) {
|
|
16611
|
+
const isOnTracePage = placement === "trace-page";
|
|
16612
|
+
const [internalCollapsed, setInternalCollapsed] = useState(false);
|
|
16613
|
+
const collapsed = controlledCollapsed ?? internalCollapsed;
|
|
16614
|
+
const setCollapsed = onCollapsedChange ?? setInternalCollapsed;
|
|
16615
|
+
const contentRef = useRef(null);
|
|
16616
|
+
const [selectedSpanId, setSelectedSpanId] = useState(initialSpanId ?? void 0);
|
|
16617
|
+
useEffect(() => {
|
|
16618
|
+
if (!initialSpanId) {
|
|
16619
|
+
setSelectedSpanId(void 0);
|
|
16620
|
+
onSpanSelect?.(void 0);
|
|
16621
|
+
return;
|
|
16622
|
+
}
|
|
16623
|
+
if (!spans) return;
|
|
16624
|
+
const found = spans.find((s) => s.spanId === initialSpanId);
|
|
16625
|
+
if (found) {
|
|
16626
|
+
setSelectedSpanId(initialSpanId);
|
|
16627
|
+
onSpanSelect?.(initialSpanId);
|
|
16628
|
+
} else {
|
|
16629
|
+
setSelectedSpanId(void 0);
|
|
16630
|
+
onSpanSelect?.(void 0);
|
|
16631
|
+
}
|
|
16632
|
+
}, [initialSpanId, spans]);
|
|
16633
|
+
useEffect(() => {
|
|
16634
|
+
if (!selectedSpanId || !contentRef.current) return;
|
|
16635
|
+
const el = contentRef.current.querySelector(`[data-span-id="${selectedSpanId}"]`);
|
|
16636
|
+
el?.scrollIntoView({ block: "nearest" });
|
|
16637
|
+
}, [selectedSpanId]);
|
|
16638
|
+
const hierarchicalSpans = useMemo(() => formatHierarchicalSpans(spans ?? []), [spans]);
|
|
16639
|
+
const [expandedSpanIds, setExpandedSpanIds] = useState([]);
|
|
16640
|
+
useEffect(() => {
|
|
16641
|
+
if (hierarchicalSpans.length > 0) {
|
|
16642
|
+
setExpandedSpanIds(getAllSpanIds(hierarchicalSpans));
|
|
16643
|
+
}
|
|
16644
|
+
}, [hierarchicalSpans]);
|
|
16645
|
+
const rootSpan = useMemo(() => spans?.find((s) => s.parentSpanId == null), [spans]);
|
|
16646
|
+
const handleSpanClick = (id) => {
|
|
16647
|
+
const newId = selectedSpanId === id ? void 0 : id;
|
|
16648
|
+
setSelectedSpanId(newId);
|
|
16649
|
+
onSpanSelect?.(newId);
|
|
16650
|
+
};
|
|
16651
|
+
const showOpenTracePageLink = !isOnTracePage && LinkComponent && traceHref;
|
|
16652
|
+
return /* @__PURE__ */ jsxs(DataPanel, { collapsed, children: [
|
|
16653
|
+
/* @__PURE__ */ jsx(DataPanel.Header, { children: isOnTracePage ? /* @__PURE__ */ jsx(DataPanel.Heading, { children: "Trace Timeline" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16654
|
+
/* @__PURE__ */ jsxs(DataPanel.Heading, { children: [
|
|
16655
|
+
"Trace ",
|
|
16656
|
+
/* @__PURE__ */ jsxs("b", { children: [
|
|
16657
|
+
"# ",
|
|
16658
|
+
truncateString(traceId, 12)
|
|
16659
|
+
] })
|
|
16660
|
+
] }),
|
|
16661
|
+
/* @__PURE__ */ jsxs(ButtonsGroup, { className: "ml-auto shrink-0", children: [
|
|
16662
|
+
onCollapsedChange && /* @__PURE__ */ jsx(
|
|
16663
|
+
ButtonWithTooltip,
|
|
16664
|
+
{
|
|
16665
|
+
size: "md",
|
|
16666
|
+
tooltipContent: collapsed ? "Expand panel" : "Collapse panel",
|
|
16667
|
+
onClick: () => setCollapsed(!collapsed),
|
|
16668
|
+
children: collapsed ? /* @__PURE__ */ jsx(ChevronsUpDownIcon, {}) : /* @__PURE__ */ jsx(ChevronsDownUpIcon, {})
|
|
16669
|
+
}
|
|
16670
|
+
),
|
|
16671
|
+
/* @__PURE__ */ jsx(
|
|
16672
|
+
DataPanel.NextPrevNav,
|
|
16673
|
+
{
|
|
16674
|
+
onPrevious,
|
|
16675
|
+
onNext,
|
|
16676
|
+
previousLabel: "Previous trace",
|
|
16677
|
+
nextLabel: "Next trace"
|
|
16678
|
+
}
|
|
16679
|
+
),
|
|
16680
|
+
showOpenTracePageLink && /* @__PURE__ */ jsx(
|
|
16681
|
+
ButtonWithTooltip,
|
|
16682
|
+
{
|
|
16683
|
+
as: LinkComponent,
|
|
16684
|
+
href: traceHref,
|
|
16685
|
+
size: "md",
|
|
16686
|
+
tooltipContent: "Open trace page",
|
|
16687
|
+
"aria-label": "Open trace page",
|
|
16688
|
+
children: /* @__PURE__ */ jsx(Link2Icon, {})
|
|
16689
|
+
}
|
|
16690
|
+
),
|
|
16691
|
+
/* @__PURE__ */ jsx(DataPanel.CloseButton, { onClick: onClose })
|
|
16692
|
+
] })
|
|
16693
|
+
] }) }),
|
|
16694
|
+
!collapsed && (isLoading ? /* @__PURE__ */ jsx(DataPanel.LoadingData, { children: "Loading trace..." }) : hierarchicalSpans.length === 0 ? /* @__PURE__ */ jsx(DataPanel.NoData, { children: "No spans found for this trace." }) : /* @__PURE__ */ jsxs(DataPanel.Content, { ref: contentRef, children: [
|
|
16695
|
+
!isOnTracePage && rootSpan && /* @__PURE__ */ jsx(TraceKeysAndValues, { rootSpan, className: "mb-6" }),
|
|
16696
|
+
!isOnTracePage && (onEvaluateTrace || onSaveAsDatasetItem) && /* @__PURE__ */ jsxs("div", { className: "mb-6 flex justify-between items-center gap-4", children: [
|
|
16697
|
+
onEvaluateTrace && /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: onEvaluateTrace, children: [
|
|
16698
|
+
/* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(CircleGaugeIcon, {}) }),
|
|
16699
|
+
"Evaluate Trace"
|
|
16700
|
+
] }),
|
|
16701
|
+
onSaveAsDatasetItem && /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: () => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId }), children: [
|
|
16702
|
+
/* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(SaveIcon, {}) }),
|
|
16703
|
+
"Save as Dataset Item"
|
|
16704
|
+
] })
|
|
16705
|
+
] }),
|
|
16706
|
+
/* @__PURE__ */ jsx(
|
|
16707
|
+
TraceTimeline,
|
|
16708
|
+
{
|
|
16709
|
+
hierarchicalSpans,
|
|
16710
|
+
onSpanClick: handleSpanClick,
|
|
16711
|
+
selectedSpanId,
|
|
16712
|
+
expandedSpanIds,
|
|
16713
|
+
setExpandedSpanIds,
|
|
16714
|
+
chartWidth: timelineChartWidth
|
|
16715
|
+
}
|
|
16716
|
+
)
|
|
16717
|
+
] }))
|
|
16718
|
+
] });
|
|
16719
|
+
}
|
|
16720
|
+
|
|
16721
|
+
function getInputPreview(input, maxLength = 100) {
|
|
16722
|
+
if (input == null) return "";
|
|
16723
|
+
const messageArray = Array.isArray(input) ? input : input && typeof input === "object" && !Array.isArray(input) && Array.isArray(input.messages) ? input.messages : null;
|
|
16724
|
+
if (messageArray) {
|
|
16725
|
+
const messages = messageArray;
|
|
16726
|
+
const userMessages = messages.filter((m) => m?.role === "user").map((m) => {
|
|
16727
|
+
if (typeof m.content === "string") return m.content;
|
|
16728
|
+
if (Array.isArray(m.content)) {
|
|
16729
|
+
return m.content.map((part) => {
|
|
16730
|
+
if (typeof part === "string") return part;
|
|
16731
|
+
if (part?.type === "text" && typeof part.text === "string") return part.text;
|
|
16732
|
+
return "";
|
|
16733
|
+
}).filter(Boolean).join(" ");
|
|
16734
|
+
}
|
|
16735
|
+
return "";
|
|
16736
|
+
}).filter(Boolean);
|
|
16737
|
+
const joined = userMessages.join(" | ");
|
|
16738
|
+
if (joined.length > maxLength) {
|
|
16739
|
+
return joined.slice(0, maxLength) + "…";
|
|
16740
|
+
}
|
|
16741
|
+
return joined;
|
|
16742
|
+
}
|
|
16743
|
+
if (typeof input === "string") {
|
|
16744
|
+
if (input.length > maxLength) {
|
|
16745
|
+
return input.slice(0, maxLength) + "…";
|
|
16746
|
+
}
|
|
16747
|
+
return input;
|
|
16748
|
+
}
|
|
16749
|
+
const str = JSON.stringify(input);
|
|
16750
|
+
if (str.length > maxLength) {
|
|
16751
|
+
return str.slice(0, maxLength) + "…";
|
|
16752
|
+
}
|
|
16753
|
+
return str;
|
|
16754
|
+
}
|
|
16755
|
+
function isTokenLimitExceeded(span) {
|
|
16756
|
+
return span?.attributes?.finishReason === "length";
|
|
16757
|
+
}
|
|
16758
|
+
function getTokenLimitMessage(span) {
|
|
16759
|
+
const usage = span?.attributes?.usage;
|
|
16760
|
+
if (!usage) {
|
|
16761
|
+
return `The model stopped generating because it reached the maximum token limit. The response was truncated and may be incomplete.`;
|
|
16762
|
+
}
|
|
16763
|
+
const inputTokens = usage.inputTokens ?? 0;
|
|
16764
|
+
const outputTokens = usage.outputTokens ?? 0;
|
|
16765
|
+
const totalTokens = usage.totalTokens ?? inputTokens + outputTokens;
|
|
16766
|
+
if (inputTokens > 0 || outputTokens > 0) {
|
|
16767
|
+
return `The model stopped generating because it reached the maximum token limit. The response was truncated and may be incomplete.
|
|
16768
|
+
|
|
16769
|
+
Token usage: ${inputTokens} input + ${outputTokens} output = ${totalTokens} total`;
|
|
16770
|
+
}
|
|
16771
|
+
return `The model stopped generating because it reached the maximum token limit (${totalTokens} tokens). The response was truncated and may be incomplete.`;
|
|
16772
|
+
}
|
|
16773
|
+
|
|
16774
|
+
function buildDialogTitle(sectionTitle, icon, span) {
|
|
16775
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16776
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-neutral2 uppercase tracking-widest [&>svg]:size-3.5", children: [
|
|
16777
|
+
icon,
|
|
16778
|
+
sectionTitle
|
|
16779
|
+
] }),
|
|
16780
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
16781
|
+
"› Span ",
|
|
16782
|
+
/* @__PURE__ */ jsxs("b", { className: "text-neutral3", children: [
|
|
16783
|
+
"#",
|
|
16784
|
+
span.spanId
|
|
16785
|
+
] })
|
|
16786
|
+
] }),
|
|
16787
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
16788
|
+
"› Trace ",
|
|
16789
|
+
/* @__PURE__ */ jsxs("b", { className: "text-neutral3", children: [
|
|
16790
|
+
"#",
|
|
16791
|
+
span.traceId
|
|
16792
|
+
] })
|
|
16793
|
+
] })
|
|
16794
|
+
] });
|
|
16795
|
+
}
|
|
16796
|
+
function SpanDataPanelView({
|
|
16797
|
+
traceId,
|
|
16798
|
+
spanId,
|
|
16799
|
+
span,
|
|
16800
|
+
isLoading,
|
|
16801
|
+
onClose,
|
|
16802
|
+
onPrevious,
|
|
16803
|
+
onNext,
|
|
16804
|
+
activeTab,
|
|
16805
|
+
onTabChange,
|
|
16806
|
+
scoringTabSlot,
|
|
16807
|
+
scoringTabBadge
|
|
16808
|
+
}) {
|
|
16809
|
+
return /* @__PURE__ */ jsxs(DataPanel, { children: [
|
|
16810
|
+
/* @__PURE__ */ jsxs(DataPanel.Header, { children: [
|
|
16811
|
+
/* @__PURE__ */ jsxs(DataPanel.Heading, { children: [
|
|
16812
|
+
"Span ",
|
|
16813
|
+
/* @__PURE__ */ jsxs("b", { children: [
|
|
16814
|
+
"# ",
|
|
16815
|
+
spanId
|
|
16816
|
+
] })
|
|
16817
|
+
] }),
|
|
16818
|
+
/* @__PURE__ */ jsxs(ButtonsGroup, { className: "ml-auto shrink-0", children: [
|
|
16819
|
+
/* @__PURE__ */ jsx(
|
|
16820
|
+
DataPanel.NextPrevNav,
|
|
16821
|
+
{
|
|
16822
|
+
onPrevious,
|
|
16823
|
+
onNext,
|
|
16824
|
+
previousLabel: "Previous span",
|
|
16825
|
+
nextLabel: "Next span"
|
|
16826
|
+
}
|
|
16827
|
+
),
|
|
16828
|
+
/* @__PURE__ */ jsx(DataPanel.CloseButton, { onClick: onClose })
|
|
16829
|
+
] })
|
|
16830
|
+
] }),
|
|
16831
|
+
isLoading ? /* @__PURE__ */ jsx(DataPanel.LoadingData, { children: "Loading span details..." }) : !span ? /* @__PURE__ */ jsx(DataPanel.NoData, { children: "Span not found." }) : /* @__PURE__ */ jsx(
|
|
16832
|
+
SpanDataPanelContent,
|
|
16833
|
+
{
|
|
16834
|
+
span,
|
|
16835
|
+
traceId,
|
|
16836
|
+
spanId,
|
|
16837
|
+
activeTab,
|
|
16838
|
+
onTabChange,
|
|
16839
|
+
scoringTabSlot,
|
|
16840
|
+
scoringTabBadge
|
|
16841
|
+
}
|
|
16842
|
+
)
|
|
16843
|
+
] });
|
|
16844
|
+
}
|
|
16845
|
+
function SpanDataPanelContent({
|
|
16846
|
+
span,
|
|
16847
|
+
traceId,
|
|
16848
|
+
spanId,
|
|
16849
|
+
activeTab,
|
|
16850
|
+
onTabChange,
|
|
16851
|
+
scoringTabSlot,
|
|
16852
|
+
scoringTabBadge
|
|
16853
|
+
}) {
|
|
16854
|
+
const durationMs = span.startedAt && span.endedAt ? new Date(span.endedAt).getTime() - new Date(span.startedAt).getTime() : null;
|
|
16855
|
+
const usage = span.attributes?.usage;
|
|
16856
|
+
const detailsBody = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16857
|
+
isTokenLimitExceeded(span) && /* @__PURE__ */ jsxs(Alert, { variant: "warning", className: "mb-3", children: [
|
|
16858
|
+
/* @__PURE__ */ jsx(AlertTitle, { children: "Token Limit Exceeded" }),
|
|
16859
|
+
/* @__PURE__ */ jsx(AlertDescription, { as: "p", children: getTokenLimitMessage(span) })
|
|
16860
|
+
] }),
|
|
16861
|
+
usage && /* @__PURE__ */ jsx(SpanTokenUsage, { usage, className: "mb-3" }),
|
|
16862
|
+
/* @__PURE__ */ jsxs(DataKeysAndValues, { children: [
|
|
16863
|
+
span.parentSpanId == null && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16864
|
+
span.traceId && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16865
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Trace Id" }),
|
|
16866
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.ValueWithCopyBtn, { copyTooltip: "Copy Trace Id to clipboard", copyValue: span.traceId, children: span.traceId })
|
|
16867
|
+
] }),
|
|
16868
|
+
span.tags && span.tags.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16869
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Tags" }),
|
|
16870
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: span.tags.join(", ") })
|
|
16871
|
+
] }),
|
|
16872
|
+
span.runId && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16873
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Run Id" }),
|
|
16874
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.ValueWithCopyBtn, { copyTooltip: "Copy Run Id to clipboard", copyValue: span.runId, children: span.runId })
|
|
16875
|
+
] }),
|
|
16876
|
+
span.threadId && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16877
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Thread Id" }),
|
|
16878
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.ValueWithCopyBtn, { copyTooltip: "Copy Thread Id to clipboard", copyValue: span.threadId, children: span.threadId })
|
|
16879
|
+
] }),
|
|
16880
|
+
span.sessionId && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16881
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Session Id" }),
|
|
16882
|
+
/* @__PURE__ */ jsx(
|
|
16883
|
+
DataKeysAndValues.ValueWithCopyBtn,
|
|
16884
|
+
{
|
|
16885
|
+
copyTooltip: "Copy Session Id to clipboard",
|
|
16886
|
+
copyValue: span.sessionId,
|
|
16887
|
+
children: span.sessionId
|
|
16888
|
+
}
|
|
16889
|
+
)
|
|
16890
|
+
] }),
|
|
16891
|
+
span.requestId && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16892
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Request Id" }),
|
|
16893
|
+
/* @__PURE__ */ jsx(
|
|
16894
|
+
DataKeysAndValues.ValueWithCopyBtn,
|
|
16895
|
+
{
|
|
16896
|
+
copyTooltip: "Copy Request Id to clipboard",
|
|
16897
|
+
copyValue: span.requestId,
|
|
16898
|
+
children: span.requestId
|
|
16899
|
+
}
|
|
16900
|
+
)
|
|
16901
|
+
] }),
|
|
16902
|
+
span.resourceId && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16903
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Resource Id" }),
|
|
16904
|
+
/* @__PURE__ */ jsx(
|
|
16905
|
+
DataKeysAndValues.ValueWithCopyBtn,
|
|
16906
|
+
{
|
|
16907
|
+
copyTooltip: "Copy Resource Id to clipboard",
|
|
16908
|
+
copyValue: span.resourceId,
|
|
16909
|
+
children: span.resourceId
|
|
16910
|
+
}
|
|
16911
|
+
)
|
|
16912
|
+
] }),
|
|
16913
|
+
span.userId && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16914
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "User Id" }),
|
|
16915
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.ValueWithCopyBtn, { copyTooltip: "Copy User Id to clipboard", copyValue: span.userId, children: span.userId })
|
|
16916
|
+
] }),
|
|
16917
|
+
span.organizationId && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16918
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Organization Id" }),
|
|
16919
|
+
/* @__PURE__ */ jsx(
|
|
16920
|
+
DataKeysAndValues.ValueWithCopyBtn,
|
|
16921
|
+
{
|
|
16922
|
+
copyTooltip: "Copy Organization Id to clipboard",
|
|
16923
|
+
copyValue: span.organizationId,
|
|
16924
|
+
children: span.organizationId
|
|
16925
|
+
}
|
|
16926
|
+
)
|
|
16927
|
+
] }),
|
|
16928
|
+
span.experimentId && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16929
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Experiment Id" }),
|
|
16930
|
+
/* @__PURE__ */ jsx(
|
|
16931
|
+
DataKeysAndValues.ValueWithCopyBtn,
|
|
16932
|
+
{
|
|
16933
|
+
copyTooltip: "Copy Experiment Id to clipboard",
|
|
16934
|
+
copyValue: span.experimentId,
|
|
16935
|
+
children: span.experimentId
|
|
16936
|
+
}
|
|
16937
|
+
)
|
|
16938
|
+
] })
|
|
16939
|
+
] }),
|
|
16940
|
+
span.name && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16941
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Name" }),
|
|
16942
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: span.name })
|
|
16943
|
+
] }),
|
|
16944
|
+
span.spanType && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16945
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Type" }),
|
|
16946
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: span.spanType })
|
|
16947
|
+
] }),
|
|
16948
|
+
span.startedAt && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16949
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Started" }),
|
|
16950
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: format(new Date(span.startedAt), "MMM dd, HH:mm:ss.SSS") })
|
|
16951
|
+
] }),
|
|
16952
|
+
span.endedAt && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16953
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Ended" }),
|
|
16954
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: format(new Date(span.endedAt), "MMM dd, HH:mm:ss.SSS") })
|
|
16955
|
+
] }),
|
|
16956
|
+
durationMs != null && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16957
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Duration" }),
|
|
16958
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: durationMs < 1e3 ? `${durationMs}ms` : `${(durationMs / 1e3).toFixed(2)}s` })
|
|
16959
|
+
] })
|
|
16960
|
+
] }),
|
|
16961
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-3 mt-3", children: [
|
|
16962
|
+
/* @__PURE__ */ jsx(
|
|
16963
|
+
DataPanel.CodeSection,
|
|
16964
|
+
{
|
|
16965
|
+
title: "Input",
|
|
16966
|
+
dialogTitle: buildDialogTitle("Input", /* @__PURE__ */ jsx(FileInputIcon, {}), { spanId, traceId }),
|
|
16967
|
+
icon: /* @__PURE__ */ jsx(FileInputIcon, {}),
|
|
16968
|
+
codeStr: JSON.stringify(span.input ?? null, null, 2)
|
|
16969
|
+
}
|
|
16970
|
+
),
|
|
16971
|
+
/* @__PURE__ */ jsx(
|
|
16972
|
+
DataPanel.CodeSection,
|
|
16973
|
+
{
|
|
16974
|
+
title: "Output",
|
|
16975
|
+
dialogTitle: buildDialogTitle("Output", /* @__PURE__ */ jsx(FileOutputIcon, {}), { spanId, traceId }),
|
|
16976
|
+
icon: /* @__PURE__ */ jsx(FileOutputIcon, {}),
|
|
16977
|
+
codeStr: JSON.stringify(span.output ?? null, null, 2)
|
|
16978
|
+
}
|
|
16979
|
+
),
|
|
16980
|
+
/* @__PURE__ */ jsx(
|
|
16981
|
+
DataPanel.CodeSection,
|
|
16982
|
+
{
|
|
16983
|
+
title: "Metadata",
|
|
16984
|
+
dialogTitle: buildDialogTitle("Metadata", /* @__PURE__ */ jsx(BracesIcon, {}), { spanId, traceId }),
|
|
16985
|
+
icon: /* @__PURE__ */ jsx(BracesIcon, {}),
|
|
16986
|
+
codeStr: JSON.stringify(span.metadata ?? null, null, 2)
|
|
16987
|
+
}
|
|
16988
|
+
),
|
|
16989
|
+
/* @__PURE__ */ jsx(
|
|
16990
|
+
DataPanel.CodeSection,
|
|
16991
|
+
{
|
|
16992
|
+
title: "Attributes",
|
|
16993
|
+
dialogTitle: buildDialogTitle("Attributes", /* @__PURE__ */ jsx(BracesIcon, {}), { spanId, traceId }),
|
|
16994
|
+
icon: /* @__PURE__ */ jsx(BracesIcon, {}),
|
|
16995
|
+
codeStr: JSON.stringify(span.attributes ?? null, null, 2)
|
|
16996
|
+
}
|
|
16997
|
+
)
|
|
16998
|
+
] })
|
|
16999
|
+
] });
|
|
17000
|
+
if (!scoringTabSlot) {
|
|
17001
|
+
return /* @__PURE__ */ jsx(DataPanel.Content, { children: detailsBody });
|
|
17002
|
+
}
|
|
17003
|
+
return /* @__PURE__ */ jsx(DataPanel.Content, { children: /* @__PURE__ */ jsxs(Tabs, { defaultTab: "details", value: activeTab, onValueChange: onTabChange, children: [
|
|
17004
|
+
/* @__PURE__ */ jsxs(TabList, { children: [
|
|
17005
|
+
/* @__PURE__ */ jsx(Tab, { value: "details", children: "Details" }),
|
|
17006
|
+
/* @__PURE__ */ jsxs(Tab, { value: "scoring", children: [
|
|
17007
|
+
"Scoring ",
|
|
17008
|
+
scoringTabBadge != null && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
17009
|
+
"(",
|
|
17010
|
+
scoringTabBadge,
|
|
17011
|
+
")"
|
|
17012
|
+
] })
|
|
17013
|
+
] })
|
|
17014
|
+
] }),
|
|
17015
|
+
/* @__PURE__ */ jsx(TabContent, { value: "details", children: detailsBody }),
|
|
17016
|
+
/* @__PURE__ */ jsx(TabContent, { value: "scoring", children: scoringTabSlot({ span, traceId, spanId }) })
|
|
17017
|
+
] }) });
|
|
17018
|
+
}
|
|
17019
|
+
|
|
17020
|
+
const KV$1 = DataDetailsPanel.KeyValueList;
|
|
17021
|
+
function SpanDetailsView({ spanId, span, isLoading, onClose }) {
|
|
17022
|
+
const durationMs = span?.startedAt && span?.endedAt ? new Date(span.endedAt).getTime() - new Date(span.startedAt).getTime() : null;
|
|
17023
|
+
return /* @__PURE__ */ jsxs(DataDetailsPanel, { children: [
|
|
17024
|
+
/* @__PURE__ */ jsxs(DataDetailsPanel.Header, { children: [
|
|
17025
|
+
/* @__PURE__ */ jsxs(DataDetailsPanel.Heading, { children: [
|
|
17026
|
+
"Span ",
|
|
17027
|
+
/* @__PURE__ */ jsxs("b", { children: [
|
|
17028
|
+
"# ",
|
|
17029
|
+
spanId
|
|
17030
|
+
] })
|
|
17031
|
+
] }),
|
|
17032
|
+
/* @__PURE__ */ jsx(DataDetailsPanel.CloseButton, { onClick: onClose })
|
|
17033
|
+
] }),
|
|
17034
|
+
isLoading ? /* @__PURE__ */ jsx(DataDetailsPanel.LoadingData, { children: "Loading span..." }) : !span ? /* @__PURE__ */ jsx(DataDetailsPanel.NoData, { children: "Span not found." }) : /* @__PURE__ */ jsxs(DataDetailsPanel.Content, { children: [
|
|
17035
|
+
/* @__PURE__ */ jsxs(KV$1, { children: [
|
|
17036
|
+
span.spanType && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
17037
|
+
/* @__PURE__ */ jsx(KV$1.Key, { children: "Type" }),
|
|
17038
|
+
/* @__PURE__ */ jsx(KV$1.Value, { children: span.spanType })
|
|
17039
|
+
] }),
|
|
17040
|
+
span.startedAt && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
17041
|
+
/* @__PURE__ */ jsx(KV$1.Key, { children: "Started" }),
|
|
17042
|
+
/* @__PURE__ */ jsx(KV$1.Value, { children: format(new Date(span.startedAt), "MMM dd, HH:mm:ss.SSS") })
|
|
17043
|
+
] }),
|
|
17044
|
+
span.endedAt && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
17045
|
+
/* @__PURE__ */ jsx(KV$1.Key, { children: "Ended" }),
|
|
17046
|
+
/* @__PURE__ */ jsx(KV$1.Value, { children: format(new Date(span.endedAt), "MMM dd, HH:mm:ss.SSS") })
|
|
17047
|
+
] }),
|
|
17048
|
+
durationMs != null && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
17049
|
+
/* @__PURE__ */ jsx(KV$1.Key, { children: "Duration" }),
|
|
17050
|
+
/* @__PURE__ */ jsx(KV$1.Value, { children: durationMs < 1e3 ? `${durationMs}ms` : `${(durationMs / 1e3).toFixed(2)}s` })
|
|
17051
|
+
] })
|
|
17052
|
+
] }),
|
|
17053
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
17054
|
+
/* @__PURE__ */ jsx(
|
|
17055
|
+
DataDetailsPanel.CodeSection,
|
|
17056
|
+
{
|
|
17057
|
+
title: "Input",
|
|
17058
|
+
icon: /* @__PURE__ */ jsx(FileInputIcon, {}),
|
|
17059
|
+
codeStr: JSON.stringify(span.input ?? null, null, 2)
|
|
17060
|
+
}
|
|
17061
|
+
),
|
|
17062
|
+
/* @__PURE__ */ jsx(
|
|
17063
|
+
DataDetailsPanel.CodeSection,
|
|
17064
|
+
{
|
|
17065
|
+
title: "Output",
|
|
17066
|
+
icon: /* @__PURE__ */ jsx(FileOutputIcon, {}),
|
|
17067
|
+
codeStr: JSON.stringify(span.output ?? null, null, 2)
|
|
17068
|
+
}
|
|
17069
|
+
),
|
|
17070
|
+
/* @__PURE__ */ jsx(
|
|
17071
|
+
DataDetailsPanel.CodeSection,
|
|
17072
|
+
{
|
|
17073
|
+
title: "Metadata",
|
|
17074
|
+
icon: /* @__PURE__ */ jsx(BracesIcon, {}),
|
|
17075
|
+
codeStr: JSON.stringify(span.metadata ?? null, null, 2)
|
|
17076
|
+
}
|
|
17077
|
+
),
|
|
17078
|
+
/* @__PURE__ */ jsx(
|
|
17079
|
+
DataDetailsPanel.CodeSection,
|
|
17080
|
+
{
|
|
17081
|
+
title: "Attributes",
|
|
17082
|
+
icon: /* @__PURE__ */ jsx(BracesIcon, {}),
|
|
17083
|
+
codeStr: JSON.stringify(span.attributes ?? null, null, 2)
|
|
17084
|
+
}
|
|
17085
|
+
)
|
|
17086
|
+
] })
|
|
17087
|
+
] });
|
|
17088
|
+
}
|
|
17089
|
+
|
|
17090
|
+
function TraceDetailsView({
|
|
17091
|
+
traceId,
|
|
17092
|
+
spans,
|
|
17093
|
+
isLoading,
|
|
17094
|
+
onClose,
|
|
17095
|
+
onSpanSelect,
|
|
17096
|
+
selectedSpanId
|
|
17097
|
+
}) {
|
|
17098
|
+
const hierarchicalSpans = useMemo(() => formatHierarchicalSpans(spans ?? []), [spans]);
|
|
17099
|
+
const [expandedSpanIds, setExpandedSpanIds] = useState([]);
|
|
17100
|
+
useEffect(() => {
|
|
17101
|
+
if (hierarchicalSpans.length > 0) {
|
|
17102
|
+
setExpandedSpanIds(getAllSpanIds(hierarchicalSpans));
|
|
17103
|
+
}
|
|
17104
|
+
}, [hierarchicalSpans]);
|
|
17105
|
+
const handleSpanClick = (id) => {
|
|
17106
|
+
onSpanSelect?.(selectedSpanId === id ? void 0 : id);
|
|
17107
|
+
};
|
|
17108
|
+
return /* @__PURE__ */ jsxs(DataDetailsPanel, { children: [
|
|
17109
|
+
/* @__PURE__ */ jsxs(DataDetailsPanel.Header, { children: [
|
|
17110
|
+
/* @__PURE__ */ jsxs(DataDetailsPanel.Heading, { children: [
|
|
17111
|
+
"Trace ",
|
|
17112
|
+
/* @__PURE__ */ jsxs("b", { children: [
|
|
17113
|
+
"# ",
|
|
17114
|
+
traceId
|
|
17115
|
+
] })
|
|
17116
|
+
] }),
|
|
17117
|
+
/* @__PURE__ */ jsx(DataDetailsPanel.CloseButton, { onClick: onClose })
|
|
17118
|
+
] }),
|
|
17119
|
+
isLoading ? /* @__PURE__ */ jsx(DataDetailsPanel.LoadingData, { children: "Loading trace..." }) : hierarchicalSpans.length === 0 ? /* @__PURE__ */ jsx(DataDetailsPanel.NoData, { children: "No spans found for this trace." }) : /* @__PURE__ */ jsx(DataDetailsPanel.Content, { children: /* @__PURE__ */ jsx(
|
|
17120
|
+
TraceTimeline,
|
|
17121
|
+
{
|
|
17122
|
+
hierarchicalSpans,
|
|
17123
|
+
onSpanClick: handleSpanClick,
|
|
17124
|
+
selectedSpanId: selectedSpanId ?? void 0,
|
|
17125
|
+
expandedSpanIds,
|
|
17126
|
+
setExpandedSpanIds
|
|
17127
|
+
}
|
|
17128
|
+
) })
|
|
17129
|
+
] });
|
|
17130
|
+
}
|
|
17131
|
+
|
|
17132
|
+
function TracesLayout({
|
|
17133
|
+
listSlot,
|
|
17134
|
+
tracePanelSlot,
|
|
17135
|
+
spanPanelSlot,
|
|
17136
|
+
scorePanelSlot,
|
|
17137
|
+
traceCollapsed
|
|
17138
|
+
}) {
|
|
17139
|
+
const hasSidePanel = !!tracePanelSlot;
|
|
17140
|
+
return /* @__PURE__ */ jsxs(
|
|
17141
|
+
"div",
|
|
17142
|
+
{
|
|
17143
|
+
className: cn(
|
|
17144
|
+
"grid max-h-full min-h-0 gap-4 items-start ",
|
|
17145
|
+
hasSidePanel ? "grid-cols-[1fr_1fr]" : "grid-cols-[1fr]"
|
|
17146
|
+
),
|
|
17147
|
+
children: [
|
|
17148
|
+
listSlot,
|
|
17149
|
+
hasSidePanel && /* @__PURE__ */ jsxs(
|
|
17150
|
+
"div",
|
|
17151
|
+
{
|
|
17152
|
+
className: cn(
|
|
17153
|
+
"grid gap-4 max-h-full overflow-auto",
|
|
17154
|
+
scorePanelSlot ? traceCollapsed ? "grid-rows-[auto_3fr_3fr]" : "grid-rows-[2fr_3fr_3fr]" : spanPanelSlot ? traceCollapsed ? "grid-rows-[auto_3fr]" : "grid-rows-[2fr_3fr]" : traceCollapsed ? "grid-rows-[auto]" : "grid-rows-[1fr]"
|
|
17155
|
+
),
|
|
17156
|
+
children: [
|
|
17157
|
+
tracePanelSlot,
|
|
17158
|
+
spanPanelSlot,
|
|
17159
|
+
scorePanelSlot
|
|
17160
|
+
]
|
|
17161
|
+
}
|
|
17162
|
+
)
|
|
17163
|
+
]
|
|
17164
|
+
}
|
|
17165
|
+
);
|
|
17166
|
+
}
|
|
17167
|
+
|
|
17168
|
+
function groupTracesByThread(traces) {
|
|
17169
|
+
const threadMap = /* @__PURE__ */ new Map();
|
|
17170
|
+
const ungrouped = [];
|
|
17171
|
+
for (const trace of traces) {
|
|
17172
|
+
if (trace.threadId) {
|
|
17173
|
+
const existing = threadMap.get(trace.threadId);
|
|
17174
|
+
if (existing) {
|
|
17175
|
+
existing.push(trace);
|
|
17176
|
+
} else {
|
|
17177
|
+
threadMap.set(trace.threadId, [trace]);
|
|
17178
|
+
}
|
|
17179
|
+
} else {
|
|
17180
|
+
ungrouped.push(trace);
|
|
17181
|
+
}
|
|
17182
|
+
}
|
|
17183
|
+
const groups = Array.from(threadMap.entries()).map(([threadId, traces2]) => ({
|
|
17184
|
+
threadId,
|
|
17185
|
+
traces: traces2
|
|
17186
|
+
}));
|
|
17187
|
+
groups.sort((a, b) => {
|
|
17188
|
+
const aLatest = Math.max(...a.traces.map((t) => new Date(t.createdAt).getTime()));
|
|
17189
|
+
const bLatest = Math.max(...b.traces.map((t) => new Date(t.createdAt).getTime()));
|
|
17190
|
+
return bLatest - aLatest;
|
|
17191
|
+
});
|
|
17192
|
+
return { groups, ungrouped };
|
|
17193
|
+
}
|
|
17194
|
+
|
|
17195
|
+
const COLUMNS$1 = "auto auto auto auto minmax(5rem,1fr) auto auto";
|
|
17196
|
+
function TracesListView({
|
|
17197
|
+
traces,
|
|
17198
|
+
isLoading,
|
|
17199
|
+
isFetchingNextPage,
|
|
17200
|
+
hasNextPage,
|
|
17201
|
+
setEndOfListElement,
|
|
17202
|
+
filtersApplied,
|
|
17203
|
+
featuredTraceId,
|
|
17204
|
+
onTraceClick,
|
|
17205
|
+
groupByThread,
|
|
17206
|
+
threadTitles
|
|
17207
|
+
}) {
|
|
17208
|
+
if (isLoading) {
|
|
17209
|
+
return /* @__PURE__ */ jsx(DataListSkeleton, { columns: COLUMNS$1 });
|
|
17210
|
+
}
|
|
17211
|
+
const renderRows = (rows) => rows.map((trace) => {
|
|
17212
|
+
const isFeatured = trace.traceId === featuredTraceId;
|
|
17213
|
+
const displayDate = trace.startedAt ?? trace.createdAt;
|
|
17214
|
+
const entityName = trace.entityName || trace.entityId || trace.attributes?.agentId || trace.attributes?.workflowId;
|
|
17215
|
+
return /* @__PURE__ */ jsxs(
|
|
17216
|
+
TracesDataList.RowButton,
|
|
17217
|
+
{
|
|
17218
|
+
onClick: () => onTraceClick(trace),
|
|
17219
|
+
className: cn(isFeatured && "bg-surface4"),
|
|
17220
|
+
children: [
|
|
17221
|
+
/* @__PURE__ */ jsx(TracesDataList.IdCell, { traceId: trace.traceId }),
|
|
17222
|
+
/* @__PURE__ */ jsx(TracesDataList.DateCell, { timestamp: displayDate }),
|
|
17223
|
+
/* @__PURE__ */ jsx(TracesDataList.TimeCell, { timestamp: displayDate }),
|
|
17224
|
+
/* @__PURE__ */ jsx(TracesDataList.NameCell, { name: trace.name }),
|
|
17225
|
+
/* @__PURE__ */ jsx(TracesDataList.InputCell, { input: getInputPreview(trace.input) }),
|
|
17226
|
+
/* @__PURE__ */ jsx(TracesDataList.EntityCell, { entityType: trace.entityType, entityName }),
|
|
17227
|
+
/* @__PURE__ */ jsx(TracesDataList.StatusCell, { status: trace.attributes?.status })
|
|
17228
|
+
]
|
|
17229
|
+
},
|
|
17230
|
+
trace.traceId
|
|
17231
|
+
);
|
|
17232
|
+
});
|
|
17233
|
+
return /* @__PURE__ */ jsxs(TracesDataList, { columns: COLUMNS$1, className: "min-w-0", children: [
|
|
17234
|
+
/* @__PURE__ */ jsxs(TracesDataList.Top, { children: [
|
|
17235
|
+
/* @__PURE__ */ jsx(TracesDataList.TopCell, { children: "ID" }),
|
|
17236
|
+
/* @__PURE__ */ jsx(TracesDataList.TopCell, { children: "Date" }),
|
|
17237
|
+
/* @__PURE__ */ jsx(TracesDataList.TopCell, { children: "Time" }),
|
|
17238
|
+
/* @__PURE__ */ jsx(TracesDataList.TopCell, { children: "Name" }),
|
|
17239
|
+
/* @__PURE__ */ jsx(TracesDataList.TopCell, { children: "Input" }),
|
|
17240
|
+
/* @__PURE__ */ jsx(TracesDataList.TopCell, { children: "Entity" }),
|
|
17241
|
+
/* @__PURE__ */ jsx(TracesDataList.TopCell, { children: "Status" })
|
|
17242
|
+
] }),
|
|
17243
|
+
traces.length === 0 ? /* @__PURE__ */ jsx(
|
|
17244
|
+
TracesDataList.NoMatch,
|
|
17245
|
+
{
|
|
17246
|
+
message: filtersApplied ? "No traces found for applied filters" : "No traces found yet"
|
|
17247
|
+
}
|
|
17248
|
+
) : groupByThread ? (() => {
|
|
17249
|
+
const { groups, ungrouped } = groupTracesByThread(traces);
|
|
17250
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
17251
|
+
groups.map((group) => /* @__PURE__ */ jsxs(React__default.Fragment, { children: [
|
|
17252
|
+
/* @__PURE__ */ jsx(TracesDataList.Subheader, { children: /* @__PURE__ */ jsxs(TracesDataList.SubHeading, { className: "flex gap-2", children: [
|
|
17253
|
+
/* @__PURE__ */ jsx("span", { className: "uppercase", children: "Thread" }),
|
|
17254
|
+
threadTitles?.[group.threadId] && /* @__PURE__ */ jsxs("b", { children: [
|
|
17255
|
+
"'",
|
|
17256
|
+
threadTitles[group.threadId],
|
|
17257
|
+
"'"
|
|
17258
|
+
] }),
|
|
17259
|
+
/* @__PURE__ */ jsxs("b", { children: [
|
|
17260
|
+
"# ",
|
|
17261
|
+
group.threadId
|
|
17262
|
+
] }),
|
|
17263
|
+
/* @__PURE__ */ jsxs("span", { className: "text-neutral2", children: [
|
|
17264
|
+
"(",
|
|
17265
|
+
group.traces.length,
|
|
17266
|
+
")"
|
|
17267
|
+
] })
|
|
17268
|
+
] }) }),
|
|
17269
|
+
renderRows(group.traces)
|
|
17270
|
+
] }, group.threadId)),
|
|
17271
|
+
ungrouped.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
17272
|
+
/* @__PURE__ */ jsx(TracesDataList.Subheader, { children: /* @__PURE__ */ jsxs(TracesDataList.SubHeading, { className: "flex gap-2 uppercase", children: [
|
|
17273
|
+
/* @__PURE__ */ jsx("span", { children: "No thread" }),
|
|
17274
|
+
/* @__PURE__ */ jsxs("span", { className: "text-neutral2", children: [
|
|
17275
|
+
"(",
|
|
17276
|
+
ungrouped.length,
|
|
17277
|
+
")"
|
|
17278
|
+
] })
|
|
17279
|
+
] }) }),
|
|
17280
|
+
renderRows(ungrouped)
|
|
17281
|
+
] })
|
|
17282
|
+
] });
|
|
17283
|
+
})() : renderRows(traces),
|
|
17284
|
+
traces.length > 0 && /* @__PURE__ */ jsx(
|
|
17285
|
+
TracesDataList.NextPageLoading,
|
|
17286
|
+
{
|
|
17287
|
+
isLoading: isFetchingNextPage,
|
|
17288
|
+
hasMore: hasNextPage,
|
|
17289
|
+
setEndOfListElement
|
|
17290
|
+
}
|
|
17291
|
+
)
|
|
17292
|
+
] });
|
|
17293
|
+
}
|
|
17294
|
+
|
|
17295
|
+
function TracesErrorContent({ error, resource, errorTitle }) {
|
|
17296
|
+
if (is401UnauthorizedError(error)) return /* @__PURE__ */ jsx(SessionExpired, {});
|
|
17297
|
+
if (is403ForbiddenError(error)) return /* @__PURE__ */ jsx(PermissionDenied, { resource });
|
|
17298
|
+
const parsed = error instanceof Error ? parseError(error) : void 0;
|
|
17299
|
+
return /* @__PURE__ */ jsx(ErrorState, { title: errorTitle, message: parsed?.error ?? "Unknown error" });
|
|
17300
|
+
}
|
|
17301
|
+
|
|
17302
|
+
const IMMUTABLE_CACHE_TIME$1 = 1e3 * 60 * 60 * 24 * 30;
|
|
17303
|
+
function useSpanDetail(traceId, spanId) {
|
|
17304
|
+
const client = useMastraClient();
|
|
17305
|
+
return useQuery({
|
|
17306
|
+
queryKey: ["span-detail", traceId, spanId],
|
|
17307
|
+
queryFn: async () => {
|
|
17308
|
+
if (!traceId || !spanId) {
|
|
17309
|
+
throw new Error("Trace ID and Span ID are required");
|
|
17310
|
+
}
|
|
17311
|
+
return client.getSpan(traceId, spanId);
|
|
17312
|
+
},
|
|
17313
|
+
enabled: !!traceId && !!spanId,
|
|
17314
|
+
staleTime: (query) => {
|
|
17315
|
+
const data = query.state.data;
|
|
17316
|
+
if (data?.span?.endedAt) {
|
|
17317
|
+
return IMMUTABLE_CACHE_TIME$1;
|
|
17318
|
+
}
|
|
17319
|
+
return 0;
|
|
17320
|
+
}
|
|
17321
|
+
});
|
|
17322
|
+
}
|
|
17323
|
+
|
|
17324
|
+
const IMMUTABLE_CACHE_TIME = 1e3 * 60 * 60 * 24 * 30;
|
|
17325
|
+
function useTraceLightSpans(traceId) {
|
|
17326
|
+
const client = useMastraClient();
|
|
17327
|
+
return useQuery({
|
|
17328
|
+
queryKey: ["trace-light-spans", traceId],
|
|
17329
|
+
queryFn: async () => {
|
|
17330
|
+
if (!traceId) {
|
|
17331
|
+
throw new Error("Trace ID is required");
|
|
17332
|
+
}
|
|
17333
|
+
const res = await client.getTraceLight(traceId);
|
|
17334
|
+
return res;
|
|
17335
|
+
},
|
|
17336
|
+
enabled: !!traceId,
|
|
17337
|
+
staleTime: (query) => {
|
|
17338
|
+
const data = query.state.data;
|
|
17339
|
+
const isFinished = data?.spans.every((d) => Boolean(d.endedAt));
|
|
17340
|
+
if (isFinished) {
|
|
17341
|
+
return IMMUTABLE_CACHE_TIME;
|
|
17342
|
+
}
|
|
17343
|
+
return 0;
|
|
17344
|
+
}
|
|
17345
|
+
});
|
|
17346
|
+
}
|
|
17347
|
+
|
|
17348
|
+
function useTraceSpans(traceId) {
|
|
17349
|
+
const client = useMastraClient();
|
|
17350
|
+
return useQuery({
|
|
17351
|
+
queryKey: ["trace-spans", traceId],
|
|
17352
|
+
queryFn: async () => {
|
|
17353
|
+
if (!traceId) {
|
|
17354
|
+
throw new Error("Trace ID is required");
|
|
17355
|
+
}
|
|
17356
|
+
const res = await client.getTrace(traceId);
|
|
17357
|
+
return res;
|
|
17358
|
+
},
|
|
17359
|
+
enabled: !!traceId
|
|
17360
|
+
});
|
|
17361
|
+
}
|
|
17362
|
+
|
|
17363
|
+
const fetchTracesFn = async ({
|
|
17364
|
+
client,
|
|
17365
|
+
page,
|
|
17366
|
+
perPage,
|
|
17367
|
+
filters
|
|
17368
|
+
}) => {
|
|
17369
|
+
return client.listTraces({
|
|
17370
|
+
pagination: {
|
|
17371
|
+
page,
|
|
17372
|
+
perPage
|
|
17373
|
+
},
|
|
17374
|
+
filters
|
|
17375
|
+
});
|
|
17376
|
+
};
|
|
17377
|
+
const TRACES_PER_PAGE = 25;
|
|
17378
|
+
function getTracesNextPageParam(lastPage, _allPages, lastPageParam) {
|
|
17379
|
+
if (lastPage?.pagination?.hasMore) {
|
|
17380
|
+
return lastPageParam + 1;
|
|
17381
|
+
}
|
|
17382
|
+
return void 0;
|
|
17383
|
+
}
|
|
17384
|
+
function selectUniqueTraces(data) {
|
|
17385
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17386
|
+
const spans = data.pages.flatMap((page) => page.spans ?? []).filter((span) => {
|
|
17387
|
+
if (seen.has(span.traceId)) return false;
|
|
17388
|
+
seen.add(span.traceId);
|
|
17389
|
+
return true;
|
|
17390
|
+
});
|
|
17391
|
+
const threadTitles = {};
|
|
17392
|
+
for (const page of data.pages) {
|
|
17393
|
+
if (page.threadTitles) {
|
|
17394
|
+
Object.assign(threadTitles, page.threadTitles);
|
|
17395
|
+
}
|
|
17396
|
+
}
|
|
17397
|
+
return { spans, threadTitles };
|
|
17398
|
+
}
|
|
17399
|
+
const useTraces = ({ filters }) => {
|
|
17400
|
+
const client = useMastraClient();
|
|
17401
|
+
const { inView: isEndOfListInView, setRef: setEndOfListElement } = useInView();
|
|
17402
|
+
const query = useInfiniteQuery({
|
|
17403
|
+
queryKey: ["traces", filters],
|
|
17404
|
+
queryFn: ({ pageParam }) => fetchTracesFn({
|
|
17405
|
+
client,
|
|
17406
|
+
page: pageParam,
|
|
17407
|
+
perPage: TRACES_PER_PAGE,
|
|
17408
|
+
filters
|
|
17409
|
+
}),
|
|
17410
|
+
initialPageParam: 0,
|
|
17411
|
+
getNextPageParam: getTracesNextPageParam,
|
|
17412
|
+
select: selectUniqueTraces,
|
|
17413
|
+
placeholderData: keepPreviousData,
|
|
17414
|
+
retry: false,
|
|
17415
|
+
// Disable polling on 403 to prevent flickering
|
|
17416
|
+
refetchInterval: (query2) => is403ForbiddenError(query2.state.error) ? false : 3e3
|
|
17417
|
+
});
|
|
17418
|
+
const { hasNextPage, isFetchingNextPage, fetchNextPage } = query;
|
|
17419
|
+
useEffect(() => {
|
|
17420
|
+
if (isEndOfListInView && hasNextPage && !isFetchingNextPage) {
|
|
17421
|
+
void fetchNextPage();
|
|
17422
|
+
}
|
|
17423
|
+
}, [isEndOfListInView, hasNextPage, isFetchingNextPage, fetchNextPage]);
|
|
17424
|
+
return { ...query, setEndOfListElement };
|
|
17425
|
+
};
|
|
17426
|
+
|
|
17427
|
+
const useTags = () => {
|
|
17428
|
+
const client = useMastraClient();
|
|
17429
|
+
return useQuery({
|
|
17430
|
+
queryKey: ["observability-tags"],
|
|
17431
|
+
queryFn: async () => {
|
|
17432
|
+
try {
|
|
17433
|
+
return await client.getTags();
|
|
17434
|
+
} catch {
|
|
17435
|
+
return { tags: [] };
|
|
17436
|
+
}
|
|
17437
|
+
},
|
|
17438
|
+
select: (data) => data?.tags ?? [],
|
|
17439
|
+
retry: false
|
|
17440
|
+
});
|
|
17441
|
+
};
|
|
17442
|
+
|
|
17443
|
+
const ROOT_ENTITY_TYPES = {
|
|
17444
|
+
AGENT: EntityType.AGENT,
|
|
17445
|
+
WORKFLOW: EntityType.WORKFLOW_RUN,
|
|
17446
|
+
SCORER: EntityType.SCORER,
|
|
17447
|
+
INGEST: EntityType.RAG_INGESTION
|
|
17448
|
+
};
|
|
17449
|
+
const ROOT_ENTITY_TYPE_OPTIONS = [
|
|
17450
|
+
{ label: "Agent", entityType: ROOT_ENTITY_TYPES.AGENT },
|
|
17451
|
+
{ label: "Workflow", entityType: ROOT_ENTITY_TYPES.WORKFLOW },
|
|
17452
|
+
{ label: "Scorer", entityType: ROOT_ENTITY_TYPES.SCORER },
|
|
17453
|
+
{ label: "Ingest", entityType: ROOT_ENTITY_TYPES.INGEST }
|
|
17454
|
+
];
|
|
17455
|
+
const TRACE_STATUS_OPTIONS = [
|
|
17456
|
+
{ label: "Running", value: "running" },
|
|
17457
|
+
{ label: "Success", value: "success" },
|
|
17458
|
+
{ label: "Error", value: "error" }
|
|
17459
|
+
];
|
|
17460
|
+
const TRACE_SYNTHETIC_FILTER_FIELD_IDS = ["rootEntityType", "status"];
|
|
17461
|
+
const TRACE_ROOT_ENTITY_TYPE_PARAM = "rootEntityType";
|
|
17462
|
+
const TRACE_STATUS_PARAM = "status";
|
|
17463
|
+
const TRACE_DATE_PRESET_PARAM = "datePreset";
|
|
17464
|
+
const TRACE_DATE_FROM_PARAM = "dateFrom";
|
|
17465
|
+
const TRACE_DATE_TO_PARAM = "dateTo";
|
|
17466
|
+
const TRACE_DATE_PRESET_VALUES = /* @__PURE__ */ new Set([
|
|
17467
|
+
"all",
|
|
17468
|
+
"last-24h",
|
|
17469
|
+
"last-3d",
|
|
17470
|
+
"last-7d",
|
|
17471
|
+
"last-14d",
|
|
17472
|
+
"last-30d",
|
|
17473
|
+
"custom"
|
|
17474
|
+
]);
|
|
17475
|
+
const TRACE_PROPERTY_FILTER_PARAM_BY_FIELD = {
|
|
17476
|
+
tags: "filterTags",
|
|
17477
|
+
entityId: "filterEntityId",
|
|
17478
|
+
entityName: "filterEntityName",
|
|
17479
|
+
traceId: "filterTraceId",
|
|
17480
|
+
runId: "filterRunId",
|
|
17481
|
+
threadId: "filterThreadId",
|
|
17482
|
+
sessionId: "filterSessionId",
|
|
17483
|
+
requestId: "filterRequestId",
|
|
17484
|
+
resourceId: "filterResourceId",
|
|
17485
|
+
userId: "filterUserId",
|
|
17486
|
+
organizationId: "filterOrganizationId",
|
|
17487
|
+
serviceName: "filterServiceName",
|
|
17488
|
+
environment: "filterEnvironment",
|
|
17489
|
+
experimentId: "filterExperimentId"
|
|
17490
|
+
};
|
|
17491
|
+
const TRACE_PROPERTY_FILTER_FIELD_IDS = Object.keys(TRACE_PROPERTY_FILTER_PARAM_BY_FIELD);
|
|
17492
|
+
const TRACE_STATUS_VALUES = /* @__PURE__ */ new Set(["running", "success", "error"]);
|
|
17493
|
+
const DEFAULT_TRACE_FILTERS_STORAGE_KEY = "mastra:traces:saved-filters";
|
|
17494
|
+
function saveTraceFiltersToStorage(params, storageKey = DEFAULT_TRACE_FILTERS_STORAGE_KEY) {
|
|
17495
|
+
const serialized = getPreservedTraceFilterParams(params);
|
|
17496
|
+
const preset = params.get(TRACE_DATE_PRESET_PARAM);
|
|
17497
|
+
if (preset) serialized.set(TRACE_DATE_PRESET_PARAM, preset);
|
|
17498
|
+
const from = params.get(TRACE_DATE_FROM_PARAM);
|
|
17499
|
+
if (from) serialized.set(TRACE_DATE_FROM_PARAM, from);
|
|
17500
|
+
const to = params.get(TRACE_DATE_TO_PARAM);
|
|
17501
|
+
if (to) serialized.set(TRACE_DATE_TO_PARAM, to);
|
|
17502
|
+
try {
|
|
17503
|
+
localStorage.setItem(storageKey, serialized.toString());
|
|
17504
|
+
} catch {
|
|
17505
|
+
}
|
|
17506
|
+
}
|
|
17507
|
+
function clearSavedTraceFilters(storageKey = DEFAULT_TRACE_FILTERS_STORAGE_KEY) {
|
|
17508
|
+
try {
|
|
17509
|
+
localStorage.removeItem(storageKey);
|
|
17510
|
+
} catch {
|
|
17511
|
+
}
|
|
17512
|
+
}
|
|
17513
|
+
function loadTraceFiltersFromStorage(storageKey = DEFAULT_TRACE_FILTERS_STORAGE_KEY) {
|
|
17514
|
+
try {
|
|
17515
|
+
const raw = localStorage.getItem(storageKey);
|
|
17516
|
+
if (!raw) return null;
|
|
17517
|
+
const parsed = new URLSearchParams(raw);
|
|
17518
|
+
return parsed.toString() ? parsed : null;
|
|
17519
|
+
} catch {
|
|
17520
|
+
return null;
|
|
17521
|
+
}
|
|
17522
|
+
}
|
|
17523
|
+
function hasAnyTraceFilterParams(params) {
|
|
17524
|
+
if (params.has(TRACE_DATE_PRESET_PARAM)) return true;
|
|
17525
|
+
if (params.has(TRACE_DATE_FROM_PARAM)) return true;
|
|
17526
|
+
if (params.has(TRACE_DATE_TO_PARAM)) return true;
|
|
17527
|
+
if (params.has(TRACE_ROOT_ENTITY_TYPE_PARAM)) return true;
|
|
17528
|
+
if (params.has(TRACE_STATUS_PARAM)) return true;
|
|
17529
|
+
for (const fieldId of TRACE_PROPERTY_FILTER_FIELD_IDS) {
|
|
17530
|
+
if (params.has(TRACE_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId])) return true;
|
|
17531
|
+
}
|
|
17532
|
+
return false;
|
|
17533
|
+
}
|
|
17534
|
+
function createTracePropertyFilterFields({
|
|
17535
|
+
availableTags,
|
|
17536
|
+
availableRootEntityNames,
|
|
17537
|
+
availableServiceNames,
|
|
17538
|
+
availableEnvironments,
|
|
17539
|
+
loading
|
|
17540
|
+
}) {
|
|
17541
|
+
const fields = [
|
|
17542
|
+
{
|
|
17543
|
+
id: "rootEntityType",
|
|
17544
|
+
label: "Primitive Type",
|
|
17545
|
+
kind: "pick-multi",
|
|
17546
|
+
searchable: false,
|
|
17547
|
+
options: ROOT_ENTITY_TYPE_OPTIONS.map((o) => ({ label: o.label, value: o.entityType })),
|
|
17548
|
+
placeholder: "Choose entity type",
|
|
17549
|
+
emptyText: "No entity types."
|
|
17550
|
+
},
|
|
17551
|
+
{
|
|
17552
|
+
id: "entityName",
|
|
17553
|
+
label: "Primitive Name",
|
|
17554
|
+
kind: "pick-multi",
|
|
17555
|
+
options: availableRootEntityNames.map((name) => ({ label: name, value: name })),
|
|
17556
|
+
placeholder: "Choose entity names",
|
|
17557
|
+
emptyText: "No entity names found.",
|
|
17558
|
+
isLoading: loading?.entityNames
|
|
17559
|
+
},
|
|
17560
|
+
{ id: "entityId", label: "Primitive ID", kind: "text" },
|
|
17561
|
+
{
|
|
17562
|
+
id: "status",
|
|
17563
|
+
label: "Status",
|
|
17564
|
+
kind: "pick-multi",
|
|
17565
|
+
searchable: false,
|
|
17566
|
+
options: TRACE_STATUS_OPTIONS.map((o) => ({ label: o.label, value: o.value })),
|
|
17567
|
+
placeholder: "Choose status",
|
|
17568
|
+
emptyText: "No statuses."
|
|
17569
|
+
},
|
|
17570
|
+
{
|
|
17571
|
+
id: "tags",
|
|
17572
|
+
label: "Tags",
|
|
17573
|
+
kind: "pick-multi",
|
|
17574
|
+
multi: true,
|
|
17575
|
+
options: availableTags.map((tag) => ({ label: tag, value: tag })),
|
|
17576
|
+
placeholder: "Choose tags",
|
|
17577
|
+
emptyText: "No tags found.",
|
|
17578
|
+
isLoading: loading?.tags
|
|
17579
|
+
},
|
|
17580
|
+
{
|
|
17581
|
+
id: "serviceName",
|
|
17582
|
+
label: "Service Name",
|
|
17583
|
+
kind: "pick-multi",
|
|
17584
|
+
options: availableServiceNames.map((name) => ({ label: name, value: name })),
|
|
17585
|
+
placeholder: "Choose service names",
|
|
17586
|
+
emptyText: "No service names found.",
|
|
17587
|
+
isLoading: loading?.serviceNames
|
|
17588
|
+
},
|
|
17589
|
+
{
|
|
17590
|
+
id: "environment",
|
|
17591
|
+
label: "Environment",
|
|
17592
|
+
kind: "pick-multi",
|
|
17593
|
+
options: availableEnvironments.map((env) => ({ label: env, value: env })),
|
|
17594
|
+
placeholder: "Choose environments",
|
|
17595
|
+
emptyText: "No environments found.",
|
|
17596
|
+
isLoading: loading?.environments
|
|
17597
|
+
},
|
|
17598
|
+
{ id: "traceId", label: "Trace ID", kind: "text" },
|
|
17599
|
+
{ id: "runId", label: "Run ID", kind: "text" },
|
|
17600
|
+
{ id: "threadId", label: "Thread ID", kind: "text" },
|
|
17601
|
+
{ id: "sessionId", label: "Session ID", kind: "text" },
|
|
17602
|
+
{ id: "requestId", label: "Request ID", kind: "text" },
|
|
17603
|
+
{ id: "resourceId", label: "Resource ID", kind: "text" },
|
|
17604
|
+
{ id: "userId", label: "User ID", kind: "text" },
|
|
17605
|
+
{ id: "organizationId", label: "Organization ID", kind: "text" },
|
|
17606
|
+
{ id: "experimentId", label: "Experiment ID", kind: "text" }
|
|
17607
|
+
];
|
|
17608
|
+
const byLabel = (a, b) => a.label.localeCompare(b.label);
|
|
17609
|
+
const pickMulti = fields.filter((f) => f.kind === "pick-multi").sort(byLabel);
|
|
17610
|
+
const text = fields.filter((f) => f.kind === "text").sort(byLabel);
|
|
17611
|
+
return [...pickMulti, ...text];
|
|
17612
|
+
}
|
|
17613
|
+
function getTracePropertyFilterTokens(searchParams) {
|
|
17614
|
+
const tokens = [];
|
|
17615
|
+
const paramToFieldId = /* @__PURE__ */ new Map([
|
|
17616
|
+
[TRACE_ROOT_ENTITY_TYPE_PARAM, "rootEntityType"],
|
|
17617
|
+
[TRACE_STATUS_PARAM, "status"]
|
|
17618
|
+
]);
|
|
17619
|
+
for (const fieldId of TRACE_PROPERTY_FILTER_FIELD_IDS) {
|
|
17620
|
+
paramToFieldId.set(TRACE_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId], fieldId);
|
|
17621
|
+
}
|
|
17622
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17623
|
+
for (const [paramName] of searchParams.entries()) {
|
|
17624
|
+
const fieldId = paramToFieldId.get(paramName);
|
|
17625
|
+
if (!fieldId || seen.has(fieldId)) continue;
|
|
17626
|
+
seen.add(fieldId);
|
|
17627
|
+
if (fieldId === "tags") {
|
|
17628
|
+
const raw = searchParams.getAll(paramName);
|
|
17629
|
+
if (raw.length === 0) continue;
|
|
17630
|
+
tokens.push({ fieldId, value: raw.filter(Boolean) });
|
|
17631
|
+
continue;
|
|
17632
|
+
}
|
|
17633
|
+
const value = searchParams.get(paramName);
|
|
17634
|
+
if (value !== null) tokens.push({ fieldId, value });
|
|
17635
|
+
}
|
|
17636
|
+
return tokens;
|
|
17637
|
+
}
|
|
17638
|
+
function getPreservedTraceFilterParams(searchParams) {
|
|
17639
|
+
const next = new URLSearchParams();
|
|
17640
|
+
const rootEntityType = searchParams.get(TRACE_ROOT_ENTITY_TYPE_PARAM);
|
|
17641
|
+
if (rootEntityType) next.set(TRACE_ROOT_ENTITY_TYPE_PARAM, rootEntityType);
|
|
17642
|
+
const status = searchParams.get(TRACE_STATUS_PARAM);
|
|
17643
|
+
if (status) next.set(TRACE_STATUS_PARAM, status);
|
|
17644
|
+
for (const fieldId of TRACE_PROPERTY_FILTER_FIELD_IDS) {
|
|
17645
|
+
const param = TRACE_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId];
|
|
17646
|
+
if (fieldId === "tags") {
|
|
17647
|
+
for (const value2 of searchParams.getAll(param)) {
|
|
17648
|
+
next.append(param, value2);
|
|
17649
|
+
}
|
|
17650
|
+
continue;
|
|
17651
|
+
}
|
|
17652
|
+
const value = searchParams.get(param);
|
|
17653
|
+
if (value) {
|
|
17654
|
+
next.set(param, value);
|
|
17655
|
+
}
|
|
17656
|
+
}
|
|
17657
|
+
return next;
|
|
17658
|
+
}
|
|
17659
|
+
function applyTracePropertyFilterTokens(params, tokens) {
|
|
17660
|
+
params.delete(TRACE_ROOT_ENTITY_TYPE_PARAM);
|
|
17661
|
+
params.delete(TRACE_STATUS_PARAM);
|
|
17662
|
+
for (const fieldId of TRACE_PROPERTY_FILTER_FIELD_IDS) {
|
|
17663
|
+
params.delete(TRACE_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId]);
|
|
17664
|
+
}
|
|
17665
|
+
for (const token of tokens) {
|
|
17666
|
+
if (token.fieldId === "rootEntityType" && typeof token.value === "string") {
|
|
17667
|
+
params.set(TRACE_ROOT_ENTITY_TYPE_PARAM, token.value);
|
|
17668
|
+
continue;
|
|
17669
|
+
}
|
|
17670
|
+
if (token.fieldId === "status" && typeof token.value === "string") {
|
|
17671
|
+
params.set(TRACE_STATUS_PARAM, token.value);
|
|
17672
|
+
continue;
|
|
17673
|
+
}
|
|
17674
|
+
const param = TRACE_PROPERTY_FILTER_PARAM_BY_FIELD[token.fieldId];
|
|
17675
|
+
if (!param) continue;
|
|
17676
|
+
if (token.fieldId === "tags" && Array.isArray(token.value)) {
|
|
17677
|
+
if (token.value.length === 0) {
|
|
17678
|
+
params.append(param, "");
|
|
17679
|
+
} else {
|
|
17680
|
+
for (const value of token.value) {
|
|
17681
|
+
params.append(param, value);
|
|
17682
|
+
}
|
|
17683
|
+
}
|
|
17684
|
+
continue;
|
|
17685
|
+
}
|
|
17686
|
+
if (typeof token.value === "string") {
|
|
17687
|
+
params.set(param, token.value.trim());
|
|
17688
|
+
}
|
|
17689
|
+
}
|
|
17690
|
+
}
|
|
17691
|
+
function buildTraceListFilters({
|
|
17692
|
+
rootEntityType,
|
|
17693
|
+
status,
|
|
17694
|
+
dateFrom,
|
|
17695
|
+
dateTo,
|
|
17696
|
+
tokens
|
|
17697
|
+
}) {
|
|
17698
|
+
const filters = {};
|
|
17699
|
+
if (rootEntityType) {
|
|
17700
|
+
filters.entityType = rootEntityType;
|
|
17701
|
+
}
|
|
17702
|
+
if (status) {
|
|
17703
|
+
filters.status = status;
|
|
17704
|
+
}
|
|
17705
|
+
if (dateFrom) {
|
|
17706
|
+
filters.startedAt = { start: dateFrom };
|
|
17707
|
+
}
|
|
17708
|
+
if (dateTo) {
|
|
17709
|
+
filters.endedAt = { end: dateTo };
|
|
17710
|
+
}
|
|
17711
|
+
for (const token of tokens) {
|
|
17712
|
+
if (token.fieldId === "tags") {
|
|
17713
|
+
if (Array.isArray(token.value) && token.value.length > 0) {
|
|
17714
|
+
filters.tags = token.value;
|
|
17715
|
+
} else if (typeof token.value === "string" && token.value.trim()) {
|
|
17716
|
+
filters.tags = [token.value.trim()];
|
|
17717
|
+
}
|
|
17718
|
+
continue;
|
|
17719
|
+
}
|
|
17720
|
+
if (typeof token.value !== "string") continue;
|
|
17721
|
+
if (!token.value.trim()) continue;
|
|
17722
|
+
if (token.value === "Any") continue;
|
|
17723
|
+
switch (token.fieldId) {
|
|
17724
|
+
case "entityId":
|
|
17725
|
+
filters.entityId = token.value;
|
|
17726
|
+
break;
|
|
17727
|
+
case "entityName":
|
|
17728
|
+
filters.entityName = token.value;
|
|
17729
|
+
break;
|
|
17730
|
+
case "traceId":
|
|
17731
|
+
filters.traceId = token.value;
|
|
17732
|
+
break;
|
|
17733
|
+
case "runId":
|
|
17734
|
+
filters.runId = token.value;
|
|
17735
|
+
break;
|
|
17736
|
+
case "threadId":
|
|
17737
|
+
filters.threadId = token.value;
|
|
17738
|
+
break;
|
|
17739
|
+
case "sessionId":
|
|
17740
|
+
filters.sessionId = token.value;
|
|
17741
|
+
break;
|
|
17742
|
+
case "requestId":
|
|
17743
|
+
filters.requestId = token.value;
|
|
17744
|
+
break;
|
|
17745
|
+
case "resourceId":
|
|
17746
|
+
filters.resourceId = token.value;
|
|
17747
|
+
break;
|
|
17748
|
+
case "userId":
|
|
17749
|
+
filters.userId = token.value;
|
|
17750
|
+
break;
|
|
17751
|
+
case "organizationId":
|
|
17752
|
+
filters.organizationId = token.value;
|
|
17753
|
+
break;
|
|
17754
|
+
case "serviceName":
|
|
17755
|
+
filters.serviceName = token.value;
|
|
17756
|
+
break;
|
|
17757
|
+
case "environment":
|
|
17758
|
+
filters.environment = token.value;
|
|
17759
|
+
break;
|
|
17760
|
+
case "experimentId":
|
|
17761
|
+
filters.experimentId = token.value;
|
|
17762
|
+
break;
|
|
17763
|
+
}
|
|
17764
|
+
}
|
|
17765
|
+
return filters;
|
|
17766
|
+
}
|
|
17767
|
+
function neutralizeFilterTokens(filterFields, filterTokens) {
|
|
17768
|
+
return filterTokens.map((token) => {
|
|
17769
|
+
const field = filterFields.find((f) => f.id === token.fieldId);
|
|
17770
|
+
if (!field) return token;
|
|
17771
|
+
if (field.kind === "text") return { fieldId: token.fieldId, value: "" };
|
|
17772
|
+
if (field.kind === "pick-multi") {
|
|
17773
|
+
return field.multi ? { fieldId: token.fieldId, value: [] } : { fieldId: token.fieldId, value: "Any" };
|
|
17774
|
+
}
|
|
17775
|
+
return token;
|
|
17776
|
+
});
|
|
17777
|
+
}
|
|
17778
|
+
|
|
17779
|
+
const useEntityNames = ({ entityType, rootOnly = false } = {}) => {
|
|
17780
|
+
const client = useMastraClient();
|
|
17781
|
+
const queryKey = entityType ? ["observability-entity-names", "by-type", entityType] : ["observability-entity-names", "all", rootOnly ? "root-only" : "all-types"];
|
|
17782
|
+
return useQuery({
|
|
17783
|
+
queryKey,
|
|
17784
|
+
queryFn: async () => {
|
|
17785
|
+
try {
|
|
17786
|
+
if (entityType) {
|
|
17787
|
+
return await client.getEntityNames({ entityType });
|
|
17788
|
+
}
|
|
17789
|
+
if (!rootOnly) {
|
|
17790
|
+
return await client.getEntityNames();
|
|
17791
|
+
}
|
|
17792
|
+
const responses = await Promise.all(
|
|
17793
|
+
ROOT_ENTITY_TYPE_OPTIONS.map((option) => client.getEntityNames({ entityType: option.entityType }))
|
|
17794
|
+
);
|
|
17795
|
+
return {
|
|
17796
|
+
names: Array.from(new Set(responses.flatMap((response) => response?.names ?? []))).sort()
|
|
17797
|
+
};
|
|
17798
|
+
} catch {
|
|
17799
|
+
return { names: [] };
|
|
17800
|
+
}
|
|
17801
|
+
},
|
|
17802
|
+
select: (data) => data?.names ?? [],
|
|
17803
|
+
retry: false
|
|
17804
|
+
});
|
|
17805
|
+
};
|
|
17806
|
+
|
|
17807
|
+
const useEnvironments = () => {
|
|
17808
|
+
const client = useMastraClient();
|
|
17809
|
+
return useQuery({
|
|
17810
|
+
queryKey: ["observability-environments"],
|
|
17811
|
+
queryFn: async () => {
|
|
17812
|
+
try {
|
|
17813
|
+
return await client.getEnvironments();
|
|
17814
|
+
} catch {
|
|
17815
|
+
return { environments: [] };
|
|
17816
|
+
}
|
|
17817
|
+
},
|
|
17818
|
+
select: (data) => data?.environments ?? [],
|
|
17819
|
+
retry: false
|
|
17820
|
+
});
|
|
17821
|
+
};
|
|
17822
|
+
|
|
17823
|
+
const useServiceNames = () => {
|
|
17824
|
+
const client = useMastraClient();
|
|
17825
|
+
return useQuery({
|
|
17826
|
+
queryKey: ["observability-service-names"],
|
|
17827
|
+
queryFn: async () => {
|
|
17828
|
+
try {
|
|
17829
|
+
return await client.getServiceNames();
|
|
17830
|
+
} catch {
|
|
17831
|
+
return { serviceNames: [] };
|
|
17832
|
+
}
|
|
17833
|
+
},
|
|
17834
|
+
select: (data) => data?.serviceNames ?? [],
|
|
17835
|
+
retry: false
|
|
17836
|
+
});
|
|
17837
|
+
};
|
|
17838
|
+
|
|
17839
|
+
function useTraceSpanNavigation(lightSpans, featuredSpanId, onSpanChange) {
|
|
17840
|
+
const timelineSpanIds = useMemo(() => getAllSpanIds(formatHierarchicalSpans(lightSpans ?? [])), [lightSpans]);
|
|
17841
|
+
const featuredSpanIdx = featuredSpanId ? timelineSpanIds.indexOf(featuredSpanId) : -1;
|
|
17842
|
+
const handlePreviousSpan = featuredSpanIdx > 0 ? () => onSpanChange(timelineSpanIds[featuredSpanIdx - 1]) : void 0;
|
|
17843
|
+
const handleNextSpan = featuredSpanIdx >= 0 && featuredSpanIdx < timelineSpanIds.length - 1 ? () => onSpanChange(timelineSpanIds[featuredSpanIdx + 1]) : void 0;
|
|
17844
|
+
return { handlePreviousSpan, handleNextSpan, timelineSpanIds };
|
|
17845
|
+
}
|
|
17846
|
+
|
|
17847
|
+
function useTraceListNavigation(traces, featuredTraceId, onTraceChange) {
|
|
17848
|
+
const featuredTraceIdx = useMemo(
|
|
17849
|
+
() => featuredTraceId ? traces.findIndex((t) => t.traceId === featuredTraceId) : -1,
|
|
17850
|
+
[traces, featuredTraceId]
|
|
17851
|
+
);
|
|
17852
|
+
const handlePreviousTrace = featuredTraceIdx > 0 ? () => onTraceChange(traces[featuredTraceIdx - 1].traceId) : void 0;
|
|
17853
|
+
const handleNextTrace = featuredTraceIdx >= 0 && featuredTraceIdx < traces.length - 1 ? () => onTraceChange(traces[featuredTraceIdx + 1].traceId) : void 0;
|
|
17854
|
+
return { featuredTraceIdx, handlePreviousTrace, handleNextTrace };
|
|
17855
|
+
}
|
|
17856
|
+
|
|
17857
|
+
const TRACE_ID_PARAM = "traceId";
|
|
17858
|
+
const SPAN_ID_PARAM = "spanId";
|
|
17859
|
+
const TAB_PARAM = "tab";
|
|
17860
|
+
const SCORE_ID_PARAM = "scoreId";
|
|
17861
|
+
const DAY_MS$1 = 24 * 60 * 60 * 1e3;
|
|
17862
|
+
const PRESET_MS$1 = {
|
|
17863
|
+
"last-24h": DAY_MS$1,
|
|
17864
|
+
"last-3d": 3 * DAY_MS$1,
|
|
17865
|
+
"last-7d": 7 * DAY_MS$1,
|
|
17866
|
+
"last-14d": 14 * DAY_MS$1,
|
|
17867
|
+
"last-30d": 30 * DAY_MS$1
|
|
17868
|
+
};
|
|
17869
|
+
function clearSelectionParams$1(params) {
|
|
17870
|
+
params.delete(TRACE_ID_PARAM);
|
|
17871
|
+
params.delete(SPAN_ID_PARAM);
|
|
17872
|
+
params.delete(TAB_PARAM);
|
|
17873
|
+
params.delete(SCORE_ID_PARAM);
|
|
17874
|
+
}
|
|
17875
|
+
function useTraceUrlState(searchParams, setSearchParams, options) {
|
|
17876
|
+
const { onRemoveAll } = options ?? {};
|
|
17877
|
+
const datePreset = useMemo(() => {
|
|
17878
|
+
const value = searchParams.get(TRACE_DATE_PRESET_PARAM);
|
|
17879
|
+
return value && TRACE_DATE_PRESET_VALUES.has(value) ? value : "last-24h";
|
|
17880
|
+
}, [searchParams]);
|
|
17881
|
+
const dateFromParamRaw = searchParams.get(TRACE_DATE_FROM_PARAM);
|
|
17882
|
+
const dateToParamRaw = searchParams.get(TRACE_DATE_TO_PARAM);
|
|
17883
|
+
const selectedDateFrom = useMemo(() => {
|
|
17884
|
+
if (datePreset === "custom") {
|
|
17885
|
+
if (!dateFromParamRaw) return void 0;
|
|
17886
|
+
const parsed = new Date(dateFromParamRaw);
|
|
17887
|
+
return Number.isNaN(parsed.getTime()) ? void 0 : parsed;
|
|
17888
|
+
}
|
|
17889
|
+
if (datePreset === "all") return void 0;
|
|
17890
|
+
const ms = PRESET_MS$1[datePreset];
|
|
17891
|
+
return ms ? new Date(Date.now() - ms) : void 0;
|
|
17892
|
+
}, [datePreset, dateFromParamRaw]);
|
|
17893
|
+
const selectedDateTo = useMemo(() => {
|
|
17894
|
+
if (datePreset !== "custom" || !dateToParamRaw) return void 0;
|
|
17895
|
+
const parsed = new Date(dateToParamRaw);
|
|
17896
|
+
return Number.isNaN(parsed.getTime()) ? void 0 : parsed;
|
|
17897
|
+
}, [datePreset, dateToParamRaw]);
|
|
17898
|
+
const datePresetRef = useRef(datePreset);
|
|
17899
|
+
datePresetRef.current = datePreset;
|
|
17900
|
+
const traceIdParam = searchParams.get(TRACE_ID_PARAM) || void 0;
|
|
17901
|
+
const spanIdParam = searchParams.get(SPAN_ID_PARAM) || void 0;
|
|
17902
|
+
const tabParam = searchParams.get(TAB_PARAM);
|
|
17903
|
+
const spanTabParam = tabParam === "scoring" ? "scoring" : tabParam === "details" ? "details" : void 0;
|
|
17904
|
+
const scoreIdParam = searchParams.get(SCORE_ID_PARAM) || void 0;
|
|
17905
|
+
const selectedEntityOption = useMemo(
|
|
17906
|
+
() => ROOT_ENTITY_TYPE_OPTIONS.find((option) => option.entityType === searchParams.get(TRACE_ROOT_ENTITY_TYPE_PARAM)),
|
|
17907
|
+
[searchParams]
|
|
17908
|
+
);
|
|
17909
|
+
const selectedStatus = useMemo(() => {
|
|
17910
|
+
const value = searchParams.get(TRACE_STATUS_PARAM);
|
|
17911
|
+
return value && TRACE_STATUS_VALUES.has(value) ? value : void 0;
|
|
17912
|
+
}, [searchParams]);
|
|
17913
|
+
const filterTokens = useMemo(() => getTracePropertyFilterTokens(searchParams), [searchParams]);
|
|
17914
|
+
const handleTraceClick = useCallback(
|
|
17915
|
+
(traceId) => {
|
|
17916
|
+
setSearchParams(
|
|
17917
|
+
(prev) => {
|
|
17918
|
+
const next = new URLSearchParams(prev);
|
|
17919
|
+
if (traceId) {
|
|
17920
|
+
next.set(TRACE_ID_PARAM, traceId);
|
|
17921
|
+
} else {
|
|
17922
|
+
next.delete(TRACE_ID_PARAM);
|
|
17923
|
+
}
|
|
17924
|
+
next.delete(SPAN_ID_PARAM);
|
|
17925
|
+
next.delete(TAB_PARAM);
|
|
17926
|
+
next.delete(SCORE_ID_PARAM);
|
|
17927
|
+
return next;
|
|
17928
|
+
},
|
|
17929
|
+
{ replace: true }
|
|
17930
|
+
);
|
|
17931
|
+
},
|
|
17932
|
+
[setSearchParams]
|
|
17933
|
+
);
|
|
17934
|
+
const handleTraceClose = useCallback(() => handleTraceClick(""), [handleTraceClick]);
|
|
17935
|
+
const handleSpanChange = useCallback(
|
|
17936
|
+
(spanId) => {
|
|
17937
|
+
const currentSpanId = searchParams.get(SPAN_ID_PARAM) || null;
|
|
17938
|
+
if (spanId === currentSpanId) return;
|
|
17939
|
+
setSearchParams(
|
|
17940
|
+
(prev) => {
|
|
17941
|
+
const next = new URLSearchParams(prev);
|
|
17942
|
+
if (spanId) {
|
|
17943
|
+
next.set(SPAN_ID_PARAM, spanId);
|
|
17944
|
+
} else {
|
|
17945
|
+
next.delete(SPAN_ID_PARAM);
|
|
17946
|
+
}
|
|
17947
|
+
next.delete(TAB_PARAM);
|
|
17948
|
+
next.delete(SCORE_ID_PARAM);
|
|
17949
|
+
return next;
|
|
17950
|
+
},
|
|
17951
|
+
{ replace: true }
|
|
17952
|
+
);
|
|
17953
|
+
},
|
|
17954
|
+
[searchParams, setSearchParams]
|
|
17955
|
+
);
|
|
17956
|
+
const handleSpanClose = useCallback(() => handleSpanChange(null), [handleSpanChange]);
|
|
17957
|
+
const handleSpanTabChange = useCallback(
|
|
17958
|
+
(tab) => {
|
|
17959
|
+
const currentTab = searchParams.get(TAB_PARAM) || null;
|
|
17960
|
+
if (tab === currentTab) return;
|
|
17961
|
+
setSearchParams(
|
|
17962
|
+
(prev) => {
|
|
17963
|
+
const next = new URLSearchParams(prev);
|
|
17964
|
+
if (tab && tab !== "details") {
|
|
17965
|
+
next.set(TAB_PARAM, tab);
|
|
17966
|
+
} else {
|
|
17967
|
+
next.delete(TAB_PARAM);
|
|
17968
|
+
}
|
|
17969
|
+
next.delete(SCORE_ID_PARAM);
|
|
17970
|
+
return next;
|
|
17971
|
+
},
|
|
17972
|
+
{ replace: true }
|
|
17973
|
+
);
|
|
17974
|
+
},
|
|
17975
|
+
[searchParams, setSearchParams]
|
|
17976
|
+
);
|
|
17977
|
+
const handleScoreChange = useCallback(
|
|
17978
|
+
(scoreId) => {
|
|
17979
|
+
const currentScoreId = searchParams.get(SCORE_ID_PARAM) || null;
|
|
17980
|
+
if (scoreId === currentScoreId) return;
|
|
17981
|
+
setSearchParams(
|
|
17982
|
+
(prev) => {
|
|
17983
|
+
const next = new URLSearchParams(prev);
|
|
17984
|
+
if (scoreId) {
|
|
17985
|
+
next.set(SCORE_ID_PARAM, scoreId);
|
|
17986
|
+
} else {
|
|
17987
|
+
next.delete(SCORE_ID_PARAM);
|
|
17988
|
+
}
|
|
17989
|
+
return next;
|
|
17990
|
+
},
|
|
17991
|
+
{ replace: true }
|
|
17992
|
+
);
|
|
17993
|
+
},
|
|
17994
|
+
[searchParams, setSearchParams]
|
|
17995
|
+
);
|
|
17996
|
+
const applyFilterTokens = useCallback(
|
|
17997
|
+
(tokens) => {
|
|
17998
|
+
setSearchParams(
|
|
17999
|
+
(prev) => {
|
|
18000
|
+
const next = new URLSearchParams(prev);
|
|
18001
|
+
applyTracePropertyFilterTokens(next, tokens);
|
|
18002
|
+
clearSelectionParams$1(next);
|
|
18003
|
+
return next;
|
|
18004
|
+
},
|
|
18005
|
+
{ replace: true }
|
|
18006
|
+
);
|
|
18007
|
+
},
|
|
18008
|
+
[setSearchParams]
|
|
18009
|
+
);
|
|
18010
|
+
const handleFilterTokensChange = applyFilterTokens;
|
|
18011
|
+
const handleDateChange = useCallback(
|
|
18012
|
+
(value, type) => {
|
|
18013
|
+
if (datePresetRef.current !== "custom") return;
|
|
18014
|
+
const param = type === "from" ? TRACE_DATE_FROM_PARAM : TRACE_DATE_TO_PARAM;
|
|
18015
|
+
setSearchParams(
|
|
18016
|
+
(prev) => {
|
|
18017
|
+
const next = new URLSearchParams(prev);
|
|
18018
|
+
if (value) {
|
|
18019
|
+
next.set(param, value.toISOString());
|
|
18020
|
+
} else {
|
|
18021
|
+
next.delete(param);
|
|
18022
|
+
}
|
|
18023
|
+
clearSelectionParams$1(next);
|
|
18024
|
+
return next;
|
|
18025
|
+
},
|
|
18026
|
+
{ replace: true }
|
|
18027
|
+
);
|
|
18028
|
+
},
|
|
18029
|
+
[setSearchParams]
|
|
18030
|
+
);
|
|
18031
|
+
const handleDatePresetChange = useCallback(
|
|
18032
|
+
(preset) => {
|
|
18033
|
+
datePresetRef.current = preset;
|
|
18034
|
+
setSearchParams(
|
|
18035
|
+
(prev) => {
|
|
18036
|
+
const next = new URLSearchParams(prev);
|
|
18037
|
+
if (preset === "last-24h") {
|
|
18038
|
+
next.delete(TRACE_DATE_PRESET_PARAM);
|
|
18039
|
+
next.delete(TRACE_DATE_FROM_PARAM);
|
|
18040
|
+
next.delete(TRACE_DATE_TO_PARAM);
|
|
18041
|
+
} else if (preset === "custom") {
|
|
18042
|
+
next.set(TRACE_DATE_PRESET_PARAM, "custom");
|
|
18043
|
+
} else {
|
|
18044
|
+
next.set(TRACE_DATE_PRESET_PARAM, preset);
|
|
18045
|
+
next.delete(TRACE_DATE_FROM_PARAM);
|
|
18046
|
+
next.delete(TRACE_DATE_TO_PARAM);
|
|
18047
|
+
}
|
|
18048
|
+
clearSelectionParams$1(next);
|
|
18049
|
+
return next;
|
|
18050
|
+
},
|
|
18051
|
+
{ replace: true }
|
|
18052
|
+
);
|
|
18053
|
+
},
|
|
18054
|
+
[setSearchParams]
|
|
18055
|
+
);
|
|
18056
|
+
const handleRemoveAll = useCallback(() => {
|
|
18057
|
+
setSearchParams(
|
|
18058
|
+
(prev) => {
|
|
18059
|
+
const next = new URLSearchParams(prev);
|
|
18060
|
+
next.delete(TRACE_ROOT_ENTITY_TYPE_PARAM);
|
|
18061
|
+
next.delete(TRACE_STATUS_PARAM);
|
|
18062
|
+
for (const fieldId of TRACE_PROPERTY_FILTER_FIELD_IDS) {
|
|
18063
|
+
next.delete(TRACE_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId]);
|
|
18064
|
+
}
|
|
18065
|
+
clearSelectionParams$1(next);
|
|
18066
|
+
return next;
|
|
18067
|
+
},
|
|
18068
|
+
{ replace: true }
|
|
18069
|
+
);
|
|
18070
|
+
onRemoveAll?.();
|
|
18071
|
+
}, [setSearchParams, onRemoveAll]);
|
|
18072
|
+
return {
|
|
18073
|
+
searchParams,
|
|
18074
|
+
setSearchParams,
|
|
18075
|
+
datePreset,
|
|
18076
|
+
selectedDateFrom,
|
|
18077
|
+
selectedDateTo,
|
|
18078
|
+
datePresetRef,
|
|
18079
|
+
traceIdParam,
|
|
18080
|
+
spanIdParam,
|
|
18081
|
+
spanTabParam,
|
|
18082
|
+
scoreIdParam,
|
|
18083
|
+
selectedEntityOption,
|
|
18084
|
+
selectedStatus,
|
|
18085
|
+
filterTokens,
|
|
18086
|
+
handleTraceClick,
|
|
18087
|
+
handleTraceClose,
|
|
18088
|
+
handleSpanChange,
|
|
18089
|
+
handleSpanClose,
|
|
18090
|
+
handleSpanTabChange,
|
|
18091
|
+
handleScoreChange,
|
|
18092
|
+
handleFilterTokensChange,
|
|
18093
|
+
handleDateChange,
|
|
18094
|
+
handleDatePresetChange,
|
|
18095
|
+
handleRemoveAll,
|
|
18096
|
+
applyFilterTokens
|
|
18097
|
+
};
|
|
18098
|
+
}
|
|
18099
|
+
|
|
18100
|
+
const DEFAULT_SAVED_MESSAGE$1 = "Trace filter settings saved.";
|
|
18101
|
+
const DEFAULT_CLEARED_MESSAGE$1 = "Trace filter settings cleared.";
|
|
18102
|
+
function useTraceFilterPersistence(searchParams, setSearchParams, options) {
|
|
18103
|
+
const { storageKey, messages, skipHydration } = options ?? {};
|
|
18104
|
+
const [hasSavedFilters, setHasSavedFilters] = useState(() => loadTraceFiltersFromStorage(storageKey) !== null);
|
|
18105
|
+
const handleSave = useCallback(() => {
|
|
18106
|
+
saveTraceFiltersToStorage(searchParams, storageKey);
|
|
18107
|
+
setHasSavedFilters(true);
|
|
18108
|
+
const text = messages?.saved ?? DEFAULT_SAVED_MESSAGE$1;
|
|
18109
|
+
if (text !== false) toast.success(text);
|
|
18110
|
+
}, [searchParams, storageKey, messages?.saved]);
|
|
18111
|
+
const handleRemoveSaved = useCallback(() => {
|
|
18112
|
+
clearSavedTraceFilters(storageKey);
|
|
18113
|
+
setHasSavedFilters(false);
|
|
18114
|
+
const text = messages?.cleared ?? DEFAULT_CLEARED_MESSAGE$1;
|
|
18115
|
+
if (text !== false) toast.success(text);
|
|
18116
|
+
}, [storageKey, messages?.cleared]);
|
|
18117
|
+
const hydratedRef = useRef(false);
|
|
18118
|
+
useEffect(() => {
|
|
18119
|
+
if (skipHydration) return;
|
|
18120
|
+
if (hydratedRef.current) return;
|
|
18121
|
+
hydratedRef.current = true;
|
|
18122
|
+
if (hasAnyTraceFilterParams(searchParams)) return;
|
|
18123
|
+
const saved = loadTraceFiltersFromStorage(storageKey);
|
|
18124
|
+
if (!saved) return;
|
|
18125
|
+
setSearchParams(
|
|
18126
|
+
(prev) => {
|
|
18127
|
+
const next = new URLSearchParams(prev);
|
|
18128
|
+
for (const [key, value] of saved) {
|
|
18129
|
+
next.append(key, value);
|
|
18130
|
+
}
|
|
18131
|
+
return next;
|
|
18132
|
+
},
|
|
18133
|
+
{ replace: true }
|
|
18134
|
+
);
|
|
18135
|
+
}, []);
|
|
18136
|
+
return { hasSavedFilters, handleSave, handleRemoveSaved };
|
|
18137
|
+
}
|
|
18138
|
+
|
|
18139
|
+
const CONTEXT_FIELD_IDS = [
|
|
18140
|
+
"environment",
|
|
18141
|
+
"serviceName",
|
|
18142
|
+
"source",
|
|
18143
|
+
"scope",
|
|
18144
|
+
"userId",
|
|
18145
|
+
"organizationId",
|
|
18146
|
+
"resourceId",
|
|
18147
|
+
"runId",
|
|
18148
|
+
"sessionId",
|
|
18149
|
+
"threadId",
|
|
18150
|
+
"requestId",
|
|
18151
|
+
"experimentId",
|
|
18152
|
+
"spanType",
|
|
18153
|
+
"entityName",
|
|
18154
|
+
"parentEntityType",
|
|
18155
|
+
"parentEntityId",
|
|
18156
|
+
"parentEntityName",
|
|
18157
|
+
"rootEntityType",
|
|
18158
|
+
"rootEntityId",
|
|
18159
|
+
"rootEntityName"
|
|
18160
|
+
];
|
|
18161
|
+
|
|
18162
|
+
const KV = DataDetailsPanel.KeyValueList;
|
|
18163
|
+
function toDate(value) {
|
|
18164
|
+
return value instanceof Date ? value : new Date(value);
|
|
18165
|
+
}
|
|
18166
|
+
function LogDetailsView({
|
|
18167
|
+
log,
|
|
18168
|
+
onClose,
|
|
18169
|
+
onTraceClick,
|
|
18170
|
+
onSpanClick,
|
|
18171
|
+
onPrevious,
|
|
18172
|
+
onNext,
|
|
18173
|
+
collapsed: controlledCollapsed,
|
|
18174
|
+
onCollapsedChange
|
|
18175
|
+
}) {
|
|
18176
|
+
const [internalCollapsed, setInternalCollapsed] = useState(false);
|
|
18177
|
+
const collapsed = controlledCollapsed ?? internalCollapsed;
|
|
18178
|
+
const setCollapsed = onCollapsedChange ?? setInternalCollapsed;
|
|
18179
|
+
const date = toDate(log.timestamp);
|
|
18180
|
+
return /* @__PURE__ */ jsxs(DataDetailsPanel, { collapsed, children: [
|
|
18181
|
+
/* @__PURE__ */ jsxs(DataDetailsPanel.Header, { children: [
|
|
18182
|
+
/* @__PURE__ */ jsxs(DataDetailsPanel.Heading, { children: [
|
|
18183
|
+
"Log ",
|
|
18184
|
+
/* @__PURE__ */ jsx("b", { children: format(date, "MMM dd, HH:mm:ss.SSS") })
|
|
18185
|
+
] }),
|
|
18186
|
+
/* @__PURE__ */ jsxs(ButtonsGroup, { className: "ml-auto shrink-0", children: [
|
|
18187
|
+
onCollapsedChange && /* @__PURE__ */ jsx(
|
|
18188
|
+
ButtonWithTooltip,
|
|
18189
|
+
{
|
|
18190
|
+
size: "md",
|
|
18191
|
+
tooltipContent: collapsed ? "Expand panel" : "Collapse panel",
|
|
18192
|
+
onClick: () => setCollapsed(!collapsed),
|
|
18193
|
+
children: collapsed ? /* @__PURE__ */ jsx(ChevronsUpDownIcon, {}) : /* @__PURE__ */ jsx(ChevronsDownUpIcon, {})
|
|
18194
|
+
}
|
|
18195
|
+
),
|
|
18196
|
+
/* @__PURE__ */ jsxs(ButtonsGroup, { spacing: "close", children: [
|
|
18197
|
+
/* @__PURE__ */ jsx(ButtonWithTooltip, { size: "md", tooltipContent: "Previous log", onClick: onPrevious, disabled: !onPrevious, children: /* @__PURE__ */ jsx(ArrowUpIcon, {}) }),
|
|
18198
|
+
/* @__PURE__ */ jsx(ButtonWithTooltip, { size: "md", tooltipContent: "Next log", onClick: onNext, disabled: !onNext, children: /* @__PURE__ */ jsx(ArrowDownIcon, {}) })
|
|
18199
|
+
] }),
|
|
18200
|
+
/* @__PURE__ */ jsx(DataDetailsPanel.CloseButton, { onClick: onClose })
|
|
18201
|
+
] })
|
|
18202
|
+
] }),
|
|
18203
|
+
!collapsed && /* @__PURE__ */ jsxs(DataDetailsPanel.Content, { children: [
|
|
18204
|
+
/* @__PURE__ */ jsx("p", { className: "text-ui-md text-neutral4 font-mono wrap-break-word whitespace-pre-wrap", children: log.message }),
|
|
18205
|
+
(log.traceId || log.spanId) && /* @__PURE__ */ jsxs("div", { className: cn("grid gap-2 my-8", "[&>button]:justify-between [&>button]:overflow-hidden"), children: [
|
|
18206
|
+
log.traceId && /* @__PURE__ */ jsxs(ButtonsGroup, { spacing: "close", className: "min-w-0 w-full", children: [
|
|
18207
|
+
/* @__PURE__ */ jsxs(
|
|
18208
|
+
Button,
|
|
18209
|
+
{
|
|
18210
|
+
size: "md",
|
|
18211
|
+
className: "min-w-0 flex-1 overflow-hidden",
|
|
18212
|
+
onClick: () => onTraceClick?.(log.traceId),
|
|
18213
|
+
children: [
|
|
18214
|
+
/* @__PURE__ */ jsx(ArrowRightIcon, {}),
|
|
18215
|
+
/* @__PURE__ */ jsx("span", { children: "Trace" }),
|
|
18216
|
+
/* @__PURE__ */ jsxs("span", { className: " ml-auto text-ui-sm text-neutral2 min-w-0 truncate", children: [
|
|
18217
|
+
"# ",
|
|
18218
|
+
log.traceId
|
|
18219
|
+
] })
|
|
18220
|
+
]
|
|
18221
|
+
}
|
|
18222
|
+
),
|
|
18223
|
+
/* @__PURE__ */ jsx(CopyButton, { content: log.traceId, size: "md", tooltip: "Copy Trace ID to clipboard" })
|
|
18224
|
+
] }),
|
|
18225
|
+
log.spanId && /* @__PURE__ */ jsxs(ButtonsGroup, { spacing: "close", className: "min-w-0 w-full", children: [
|
|
18226
|
+
/* @__PURE__ */ jsxs(
|
|
18227
|
+
Button,
|
|
18228
|
+
{
|
|
18229
|
+
size: "md",
|
|
18230
|
+
className: "min-w-0 flex-1 overflow-hidden",
|
|
18231
|
+
disabled: !log.traceId || !onSpanClick,
|
|
18232
|
+
onClick: () => log.traceId && onSpanClick?.(log.traceId, log.spanId),
|
|
18233
|
+
children: [
|
|
18234
|
+
/* @__PURE__ */ jsx(ArrowRightIcon, {}),
|
|
18235
|
+
/* @__PURE__ */ jsx("span", { children: "Span" }),
|
|
18236
|
+
/* @__PURE__ */ jsxs("span", { className: " ml-auto text-ui-sm text-neutral2 min-w-0 truncate", children: [
|
|
18237
|
+
"# ",
|
|
18238
|
+
log.spanId
|
|
18239
|
+
] })
|
|
18240
|
+
]
|
|
18241
|
+
}
|
|
18242
|
+
),
|
|
18243
|
+
/* @__PURE__ */ jsx(CopyButton, { content: log.spanId, size: "md", tooltip: "Copy Span ID to clipboard" })
|
|
18244
|
+
] })
|
|
18245
|
+
] }),
|
|
18246
|
+
/* @__PURE__ */ jsxs(KV, { className: "mb-6", children: [
|
|
18247
|
+
log.entityType && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
18248
|
+
/* @__PURE__ */ jsx(KV.Key, { children: "Entity Type" }),
|
|
18249
|
+
/* @__PURE__ */ jsx(KV.Value, { children: log.entityType })
|
|
18250
|
+
] }),
|
|
18251
|
+
log.entityName && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
18252
|
+
/* @__PURE__ */ jsx(KV.Key, { children: "Entity Name" }),
|
|
18253
|
+
/* @__PURE__ */ jsx(KV.Value, { children: log.entityName })
|
|
18254
|
+
] }),
|
|
18255
|
+
log.serviceName && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
18256
|
+
/* @__PURE__ */ jsx(KV.Key, { children: "Service" }),
|
|
18257
|
+
/* @__PURE__ */ jsx(KV.Value, { children: log.serviceName })
|
|
18258
|
+
] }),
|
|
18259
|
+
log.environment && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
18260
|
+
/* @__PURE__ */ jsx(KV.Key, { children: "Environment" }),
|
|
18261
|
+
/* @__PURE__ */ jsx(KV.Value, { children: log.environment })
|
|
18262
|
+
] }),
|
|
18263
|
+
log.source && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
18264
|
+
/* @__PURE__ */ jsx(KV.Key, { children: "Source" }),
|
|
18265
|
+
/* @__PURE__ */ jsx(KV.Value, { children: log.source })
|
|
18266
|
+
] }),
|
|
18267
|
+
log.metadata && Object.keys(log.metadata).length > 0 && /* @__PURE__ */ jsx(Fragment, { children: Object.entries(log.metadata).map(([key, value]) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
18268
|
+
/* @__PURE__ */ jsx(KV.Key, { children: key }),
|
|
18269
|
+
/* @__PURE__ */ jsx(KV.Value, { children: String(value) })
|
|
18270
|
+
] }, key)) })
|
|
18271
|
+
] }),
|
|
18272
|
+
log.data && Object.keys(log.data).length > 0 && /* @__PURE__ */ jsx(DataDetailsPanel.CodeSection, { title: "Data", codeStr: JSON.stringify(log.data, null, 2), className: "mt-6" })
|
|
18273
|
+
] })
|
|
18274
|
+
] });
|
|
18275
|
+
}
|
|
18276
|
+
|
|
18277
|
+
function LogsErrorContent({ error, resource, errorTitle }) {
|
|
18278
|
+
if (is401UnauthorizedError(error)) return /* @__PURE__ */ jsx(SessionExpired, {});
|
|
18279
|
+
if (is403ForbiddenError(error)) return /* @__PURE__ */ jsx(PermissionDenied, { resource });
|
|
18280
|
+
const message = error instanceof Error ? error.message : void 0;
|
|
18281
|
+
return /* @__PURE__ */ jsx(ErrorState, { title: errorTitle, message: message ?? "Unknown error" });
|
|
18282
|
+
}
|
|
18283
|
+
|
|
18284
|
+
function LogsLayout({ listSlot, logPanelSlot, tracePanelSlot, spanPanelSlot, logCollapsed }) {
|
|
18285
|
+
const hasSidePanel = !!logPanelSlot;
|
|
18286
|
+
return /* @__PURE__ */ jsxs(
|
|
18287
|
+
"div",
|
|
18288
|
+
{
|
|
18289
|
+
className: cn("grid h-full min-h-0 gap-4 items-start", hasSidePanel ? "grid-cols-[1fr_1fr]" : "grid-cols-[1fr]"),
|
|
18290
|
+
children: [
|
|
18291
|
+
listSlot,
|
|
18292
|
+
hasSidePanel && /* @__PURE__ */ jsxs(
|
|
18293
|
+
"div",
|
|
18294
|
+
{
|
|
18295
|
+
className: cn(
|
|
18296
|
+
"grid gap-4 h-full overflow-auto",
|
|
18297
|
+
tracePanelSlot && spanPanelSlot ? logCollapsed ? "grid-rows-[auto_1fr_1fr]" : "grid-rows-[1fr_1fr_1fr]" : tracePanelSlot ? logCollapsed ? "grid-rows-[auto_1fr]" : "grid-rows-[1fr_1fr]" : logCollapsed ? "grid-rows-[auto]" : "grid-rows-[1fr]"
|
|
18298
|
+
),
|
|
18299
|
+
children: [
|
|
18300
|
+
logPanelSlot,
|
|
18301
|
+
tracePanelSlot,
|
|
18302
|
+
spanPanelSlot
|
|
18303
|
+
]
|
|
18304
|
+
}
|
|
18305
|
+
)
|
|
18306
|
+
]
|
|
18307
|
+
}
|
|
18308
|
+
);
|
|
18309
|
+
}
|
|
18310
|
+
|
|
18311
|
+
const COLUMNS = "auto auto auto auto minmax(5rem,1fr) minmax(5rem,1fr)";
|
|
18312
|
+
function LogsListView({
|
|
18313
|
+
logs,
|
|
18314
|
+
isLoading,
|
|
18315
|
+
isFetchingNextPage,
|
|
18316
|
+
hasNextPage,
|
|
18317
|
+
setEndOfListElement,
|
|
18318
|
+
logIdMap,
|
|
18319
|
+
featuredLogId,
|
|
18320
|
+
onLogClick
|
|
18321
|
+
}) {
|
|
18322
|
+
if (isLoading) {
|
|
18323
|
+
return /* @__PURE__ */ jsx(DataListSkeleton, { columns: COLUMNS });
|
|
18324
|
+
}
|
|
18325
|
+
return /* @__PURE__ */ jsxs(LogsDataList, { columns: COLUMNS, className: "min-w-0", children: [
|
|
18326
|
+
/* @__PURE__ */ jsxs(LogsDataList.Top, { children: [
|
|
18327
|
+
/* @__PURE__ */ jsx(LogsDataList.TopCell, { children: "Date" }),
|
|
18328
|
+
/* @__PURE__ */ jsx(LogsDataList.TopCell, { children: "Time" }),
|
|
18329
|
+
/* @__PURE__ */ jsx(LogsDataList.TopCell, { children: "Level" }),
|
|
18330
|
+
/* @__PURE__ */ jsx(LogsDataList.TopCell, { children: "Entity" }),
|
|
18331
|
+
/* @__PURE__ */ jsx(LogsDataList.TopCell, { children: "Message" }),
|
|
18332
|
+
/* @__PURE__ */ jsx(LogsDataList.TopCell, { children: "Data" })
|
|
18333
|
+
] }),
|
|
18334
|
+
logs.length === 0 ? /* @__PURE__ */ jsx(LogsDataList.NoMatch, { message: "No logs match your search" }) : logs.map((log) => {
|
|
18335
|
+
const id = logIdMap.get(log);
|
|
18336
|
+
if (!id) return null;
|
|
18337
|
+
const isFeatured = id === featuredLogId;
|
|
18338
|
+
return /* @__PURE__ */ jsxs(
|
|
18339
|
+
LogsDataList.RowButton,
|
|
18340
|
+
{
|
|
18341
|
+
onClick: () => onLogClick(log),
|
|
18342
|
+
className: cn(isFeatured && "bg-surface4"),
|
|
18343
|
+
children: [
|
|
18344
|
+
/* @__PURE__ */ jsx(LogsDataList.DateCell, { timestamp: log.timestamp }),
|
|
18345
|
+
/* @__PURE__ */ jsx(LogsDataList.TimeCell, { timestamp: log.timestamp }),
|
|
18346
|
+
/* @__PURE__ */ jsx(LogsDataList.LevelCell, { level: log.level }),
|
|
18347
|
+
/* @__PURE__ */ jsx(LogsDataList.EntityCell, { entityType: log.entityType, entityName: log.entityName }),
|
|
18348
|
+
/* @__PURE__ */ jsx(LogsDataList.MessageCell, { message: log.message }),
|
|
18349
|
+
/* @__PURE__ */ jsx(LogsDataList.DataCell, { data: log.data })
|
|
18350
|
+
]
|
|
18351
|
+
},
|
|
18352
|
+
id
|
|
18353
|
+
);
|
|
18354
|
+
}),
|
|
18355
|
+
/* @__PURE__ */ jsx(
|
|
18356
|
+
LogsDataList.NextPageLoading,
|
|
18357
|
+
{
|
|
18358
|
+
isLoading: isFetchingNextPage,
|
|
18359
|
+
hasMore: hasNextPage,
|
|
18360
|
+
setEndOfListElement
|
|
18361
|
+
}
|
|
18362
|
+
)
|
|
18363
|
+
] });
|
|
18364
|
+
}
|
|
18365
|
+
|
|
18366
|
+
function LogsToolbar({
|
|
18367
|
+
onClear,
|
|
18368
|
+
onRemoveAll,
|
|
18369
|
+
onSave,
|
|
18370
|
+
onRemoveSaved,
|
|
18371
|
+
isLoading,
|
|
18372
|
+
filterFields,
|
|
18373
|
+
filterTokens,
|
|
18374
|
+
onFilterTokensChange,
|
|
18375
|
+
autoFocusFilterFieldId
|
|
18376
|
+
}) {
|
|
18377
|
+
const hasActiveFilters = filterTokens.length > 0;
|
|
18378
|
+
const hasNonDefaultFilter = filterTokens.some((token) => isNonDefaultFilter(token, filterFields));
|
|
18379
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("grid grid-cols-[1fr_auto] gap-3 items-start"), children: [
|
|
18380
|
+
/* @__PURE__ */ jsx(
|
|
18381
|
+
PropertyFilterApplied,
|
|
18382
|
+
{
|
|
18383
|
+
fields: filterFields,
|
|
18384
|
+
tokens: filterTokens,
|
|
18385
|
+
onTokensChange: onFilterTokensChange,
|
|
18386
|
+
disabled: isLoading,
|
|
18387
|
+
autoFocusFieldId: autoFocusFilterFieldId
|
|
18388
|
+
}
|
|
18389
|
+
),
|
|
18390
|
+
hasActiveFilters && /* @__PURE__ */ jsx(
|
|
18391
|
+
PropertyFilterActions,
|
|
18392
|
+
{
|
|
18393
|
+
disabled: isLoading,
|
|
18394
|
+
onClear: hasNonDefaultFilter ? onClear : void 0,
|
|
18395
|
+
onRemoveAll,
|
|
18396
|
+
onSave,
|
|
18397
|
+
onRemoveSaved
|
|
18398
|
+
}
|
|
18399
|
+
)
|
|
18400
|
+
] });
|
|
18401
|
+
}
|
|
18402
|
+
function isNonDefaultFilter(token, fields) {
|
|
18403
|
+
const field = fields.find((f) => f.id === token.fieldId);
|
|
18404
|
+
if (!field) return false;
|
|
18405
|
+
if (field.kind === "text") {
|
|
18406
|
+
return typeof token.value === "string" && token.value.trim() !== "";
|
|
18407
|
+
}
|
|
18408
|
+
if (field.kind === "pick-multi") {
|
|
18409
|
+
if (field.multi) return Array.isArray(token.value) && token.value.length > 0;
|
|
18410
|
+
return typeof token.value === "string" && token.value !== "" && token.value !== "Any";
|
|
18411
|
+
}
|
|
18412
|
+
if (field.kind === "multi-select") {
|
|
18413
|
+
return Array.isArray(token.value) && token.value.length > 0;
|
|
18414
|
+
}
|
|
18415
|
+
return false;
|
|
18416
|
+
}
|
|
18417
|
+
|
|
18418
|
+
const NoLogsInfo = () => /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx(
|
|
18419
|
+
EmptyState,
|
|
18420
|
+
{
|
|
18421
|
+
iconSlot: /* @__PURE__ */ jsx(CircleSlashIcon, {}),
|
|
18422
|
+
titleSlot: "No logs yet",
|
|
18423
|
+
descriptionSlot: "Logs will appear here once agents, workflows, or tools are executed."
|
|
18424
|
+
}
|
|
18425
|
+
) });
|
|
18426
|
+
|
|
18427
|
+
const LOGS_PER_PAGE = 20;
|
|
18428
|
+
function getNextPageParam(lastPage, _allPages, lastPageParam) {
|
|
18429
|
+
if (lastPage?.pagination?.hasMore) {
|
|
18430
|
+
return lastPageParam + 1;
|
|
18431
|
+
}
|
|
18432
|
+
return void 0;
|
|
18433
|
+
}
|
|
18434
|
+
function selectLogs(data) {
|
|
18435
|
+
return data.pages.flatMap((page) => page.logs ?? []);
|
|
18436
|
+
}
|
|
18437
|
+
const useLogs = ({ filters } = {}) => {
|
|
18438
|
+
const client = useMastraClient();
|
|
18439
|
+
const { inView: isEndOfListInView, setRef: setEndOfListElement } = useInView();
|
|
18440
|
+
const query = useInfiniteQuery({
|
|
18441
|
+
queryKey: ["logs", filters],
|
|
18442
|
+
queryFn: ({ pageParam }) => client.listLogsVNext({
|
|
18443
|
+
pagination: { page: pageParam, perPage: LOGS_PER_PAGE },
|
|
18444
|
+
filters,
|
|
18445
|
+
orderBy: { field: "timestamp", direction: "DESC" }
|
|
18446
|
+
}),
|
|
18447
|
+
initialPageParam: 0,
|
|
18448
|
+
getNextPageParam,
|
|
18449
|
+
select: selectLogs,
|
|
18450
|
+
retry: false,
|
|
18451
|
+
refetchInterval: 3e3
|
|
18452
|
+
});
|
|
18453
|
+
const { hasNextPage, isFetchingNextPage, fetchNextPage } = query;
|
|
18454
|
+
useEffect(() => {
|
|
18455
|
+
if (isEndOfListInView && hasNextPage && !isFetchingNextPage) {
|
|
18456
|
+
void fetchNextPage();
|
|
18457
|
+
}
|
|
18458
|
+
}, [isEndOfListInView, hasNextPage, isFetchingNextPage, fetchNextPage]);
|
|
18459
|
+
return { ...query, data: query.data, setEndOfListElement };
|
|
18460
|
+
};
|
|
18461
|
+
|
|
18462
|
+
const LOGS_ROOT_ENTITY_TYPES = {
|
|
18463
|
+
AGENT: EntityType.AGENT,
|
|
18464
|
+
WORKFLOW: EntityType.WORKFLOW_RUN,
|
|
18465
|
+
SCORER: EntityType.SCORER,
|
|
18466
|
+
INGEST: EntityType.RAG_INGESTION
|
|
18467
|
+
};
|
|
18468
|
+
const LOGS_ROOT_ENTITY_TYPE_OPTIONS = [
|
|
18469
|
+
{ label: "Agent", entityType: LOGS_ROOT_ENTITY_TYPES.AGENT },
|
|
18470
|
+
{ label: "Workflow", entityType: LOGS_ROOT_ENTITY_TYPES.WORKFLOW },
|
|
18471
|
+
{ label: "Scorer", entityType: LOGS_ROOT_ENTITY_TYPES.SCORER },
|
|
18472
|
+
{ label: "Ingest", entityType: LOGS_ROOT_ENTITY_TYPES.INGEST }
|
|
18473
|
+
];
|
|
18474
|
+
const LOG_LEVEL_VALUES = ["debug", "info", "warn", "error", "fatal"];
|
|
18475
|
+
const LOG_LEVEL_OPTIONS = [
|
|
18476
|
+
{ label: "Debug", value: "debug" },
|
|
18477
|
+
{ label: "Info", value: "info" },
|
|
18478
|
+
{ label: "Warn", value: "warn" },
|
|
18479
|
+
{ label: "Error", value: "error" },
|
|
18480
|
+
{ label: "Fatal", value: "fatal" }
|
|
18481
|
+
];
|
|
18482
|
+
const LOGS_ROOT_ENTITY_TYPE_PARAM = "rootEntityType";
|
|
18483
|
+
const LOGS_DATE_PRESET_PARAM = "datePreset";
|
|
18484
|
+
const LOGS_DATE_FROM_PARAM = "dateFrom";
|
|
18485
|
+
const LOGS_DATE_TO_PARAM = "dateTo";
|
|
18486
|
+
const LOGS_DATE_PRESET_VALUES = /* @__PURE__ */ new Set([
|
|
18487
|
+
"all",
|
|
18488
|
+
"last-24h",
|
|
18489
|
+
"last-3d",
|
|
18490
|
+
"last-7d",
|
|
18491
|
+
"last-14d",
|
|
18492
|
+
"last-30d",
|
|
18493
|
+
"custom"
|
|
18494
|
+
]);
|
|
18495
|
+
const LOGS_PROPERTY_FILTER_PARAM_BY_FIELD = {
|
|
18496
|
+
level: "filterLevel",
|
|
18497
|
+
tags: "filterTags",
|
|
18498
|
+
entityName: "filterEntityName",
|
|
18499
|
+
traceId: "filterTraceId",
|
|
18500
|
+
spanId: "filterSpanId",
|
|
18501
|
+
runId: "filterRunId",
|
|
18502
|
+
threadId: "filterThreadId",
|
|
18503
|
+
sessionId: "filterSessionId",
|
|
18504
|
+
requestId: "filterRequestId",
|
|
18505
|
+
resourceId: "filterResourceId",
|
|
18506
|
+
userId: "filterUserId",
|
|
18507
|
+
organizationId: "filterOrganizationId",
|
|
18508
|
+
serviceName: "filterServiceName",
|
|
18509
|
+
environment: "filterEnvironment",
|
|
18510
|
+
experimentId: "filterExperimentId"
|
|
18511
|
+
};
|
|
18512
|
+
const LOGS_PROPERTY_FILTER_FIELD_IDS = Object.keys(LOGS_PROPERTY_FILTER_PARAM_BY_FIELD);
|
|
18513
|
+
const LOGS_ARRAY_FIELD_IDS = /* @__PURE__ */ new Set(["tags"]);
|
|
18514
|
+
const DEFAULT_LOGS_FILTERS_STORAGE_KEY = "mastra:logs:saved-filters";
|
|
18515
|
+
function saveLogsFiltersToStorage(params, storageKey = DEFAULT_LOGS_FILTERS_STORAGE_KEY) {
|
|
18516
|
+
const serialized = getPreservedLogsFilterParams(params);
|
|
18517
|
+
const preset = params.get(LOGS_DATE_PRESET_PARAM);
|
|
18518
|
+
if (preset) serialized.set(LOGS_DATE_PRESET_PARAM, preset);
|
|
18519
|
+
const from = params.get(LOGS_DATE_FROM_PARAM);
|
|
18520
|
+
if (from) serialized.set(LOGS_DATE_FROM_PARAM, from);
|
|
18521
|
+
const to = params.get(LOGS_DATE_TO_PARAM);
|
|
18522
|
+
if (to) serialized.set(LOGS_DATE_TO_PARAM, to);
|
|
18523
|
+
try {
|
|
18524
|
+
localStorage.setItem(storageKey, serialized.toString());
|
|
18525
|
+
} catch {
|
|
18526
|
+
}
|
|
18527
|
+
}
|
|
18528
|
+
function clearSavedLogsFilters(storageKey = DEFAULT_LOGS_FILTERS_STORAGE_KEY) {
|
|
18529
|
+
try {
|
|
18530
|
+
localStorage.removeItem(storageKey);
|
|
18531
|
+
} catch {
|
|
18532
|
+
}
|
|
18533
|
+
}
|
|
18534
|
+
function loadLogsFiltersFromStorage(storageKey = DEFAULT_LOGS_FILTERS_STORAGE_KEY) {
|
|
18535
|
+
try {
|
|
18536
|
+
const raw = localStorage.getItem(storageKey);
|
|
18537
|
+
if (!raw) return null;
|
|
18538
|
+
const parsed = new URLSearchParams(raw);
|
|
18539
|
+
return parsed.toString() ? parsed : null;
|
|
18540
|
+
} catch {
|
|
18541
|
+
return null;
|
|
18542
|
+
}
|
|
18543
|
+
}
|
|
18544
|
+
function hasAnyLogsFilterParams(params) {
|
|
18545
|
+
if (params.has(LOGS_DATE_PRESET_PARAM)) return true;
|
|
18546
|
+
if (params.has(LOGS_DATE_FROM_PARAM)) return true;
|
|
18547
|
+
if (params.has(LOGS_DATE_TO_PARAM)) return true;
|
|
18548
|
+
if (params.has(LOGS_ROOT_ENTITY_TYPE_PARAM)) return true;
|
|
18549
|
+
for (const fieldId of LOGS_PROPERTY_FILTER_FIELD_IDS) {
|
|
18550
|
+
if (params.has(LOGS_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId])) return true;
|
|
18551
|
+
}
|
|
18552
|
+
return false;
|
|
18553
|
+
}
|
|
18554
|
+
function createLogsPropertyFilterFields({
|
|
18555
|
+
availableTags,
|
|
18556
|
+
availableRootEntityNames,
|
|
18557
|
+
availableServiceNames,
|
|
18558
|
+
availableEnvironments,
|
|
18559
|
+
loading
|
|
18560
|
+
}) {
|
|
18561
|
+
const fields = [
|
|
18562
|
+
{
|
|
18563
|
+
id: "rootEntityType",
|
|
18564
|
+
label: "Primitive Type",
|
|
18565
|
+
kind: "pick-multi",
|
|
18566
|
+
searchable: false,
|
|
18567
|
+
options: LOGS_ROOT_ENTITY_TYPE_OPTIONS.map((o) => ({ label: o.label, value: o.entityType })),
|
|
18568
|
+
placeholder: "Choose entity type",
|
|
18569
|
+
emptyText: "No entity types."
|
|
18570
|
+
},
|
|
18571
|
+
{
|
|
18572
|
+
id: "entityName",
|
|
18573
|
+
label: "Primitive Name",
|
|
18574
|
+
kind: "pick-multi",
|
|
18575
|
+
options: availableRootEntityNames.map((name) => ({ label: name, value: name })),
|
|
18576
|
+
placeholder: "Choose entity names",
|
|
18577
|
+
emptyText: "No entity names found.",
|
|
18578
|
+
isLoading: loading?.entityNames
|
|
18579
|
+
},
|
|
18580
|
+
{
|
|
18581
|
+
id: "level",
|
|
18582
|
+
label: "Level",
|
|
18583
|
+
kind: "pick-multi",
|
|
18584
|
+
searchable: false,
|
|
18585
|
+
options: LOG_LEVEL_OPTIONS.map((o) => ({ label: o.label, value: o.value })),
|
|
18586
|
+
placeholder: "Choose level",
|
|
18587
|
+
emptyText: "No levels."
|
|
18588
|
+
},
|
|
18589
|
+
{
|
|
18590
|
+
id: "tags",
|
|
18591
|
+
label: "Tags",
|
|
18592
|
+
kind: "pick-multi",
|
|
18593
|
+
multi: true,
|
|
18594
|
+
options: availableTags.map((tag) => ({ label: tag, value: tag })),
|
|
18595
|
+
placeholder: "Choose tags",
|
|
18596
|
+
emptyText: "No tags found.",
|
|
18597
|
+
isLoading: loading?.tags
|
|
18598
|
+
},
|
|
18599
|
+
{
|
|
18600
|
+
id: "serviceName",
|
|
18601
|
+
label: "Service Name",
|
|
18602
|
+
kind: "pick-multi",
|
|
18603
|
+
options: availableServiceNames.map((name) => ({ label: name, value: name })),
|
|
18604
|
+
placeholder: "Choose service names",
|
|
18605
|
+
emptyText: "No service names found.",
|
|
18606
|
+
isLoading: loading?.serviceNames
|
|
18607
|
+
},
|
|
18608
|
+
{
|
|
18609
|
+
id: "environment",
|
|
18610
|
+
label: "Environment",
|
|
18611
|
+
kind: "pick-multi",
|
|
18612
|
+
options: availableEnvironments.map((env) => ({ label: env, value: env })),
|
|
18613
|
+
placeholder: "Choose environments",
|
|
18614
|
+
emptyText: "No environments found.",
|
|
18615
|
+
isLoading: loading?.environments
|
|
18616
|
+
},
|
|
18617
|
+
{ id: "traceId", label: "Trace ID", kind: "text" },
|
|
18618
|
+
{ id: "spanId", label: "Span ID", kind: "text" },
|
|
18619
|
+
{ id: "runId", label: "Run ID", kind: "text" },
|
|
18620
|
+
{ id: "threadId", label: "Thread ID", kind: "text" },
|
|
18621
|
+
{ id: "sessionId", label: "Session ID", kind: "text" },
|
|
18622
|
+
{ id: "requestId", label: "Request ID", kind: "text" },
|
|
18623
|
+
{ id: "resourceId", label: "Resource ID", kind: "text" },
|
|
18624
|
+
{ id: "userId", label: "User ID", kind: "text" },
|
|
18625
|
+
{ id: "organizationId", label: "Organization ID", kind: "text" },
|
|
18626
|
+
{ id: "experimentId", label: "Experiment ID", kind: "text" }
|
|
18627
|
+
];
|
|
18628
|
+
const byLabel = (a, b) => a.label.localeCompare(b.label);
|
|
18629
|
+
const pickMulti = fields.filter((f) => f.kind === "pick-multi").sort(byLabel);
|
|
18630
|
+
const text = fields.filter((f) => f.kind === "text").sort(byLabel);
|
|
18631
|
+
return [...pickMulti, ...text];
|
|
18632
|
+
}
|
|
18633
|
+
function getLogsPropertyFilterTokens(searchParams) {
|
|
18634
|
+
const tokens = [];
|
|
18635
|
+
const paramToFieldId = /* @__PURE__ */ new Map([[LOGS_ROOT_ENTITY_TYPE_PARAM, "rootEntityType"]]);
|
|
18636
|
+
for (const fieldId of LOGS_PROPERTY_FILTER_FIELD_IDS) {
|
|
18637
|
+
paramToFieldId.set(LOGS_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId], fieldId);
|
|
18638
|
+
}
|
|
18639
|
+
const seen = /* @__PURE__ */ new Set();
|
|
18640
|
+
for (const [paramName] of searchParams.entries()) {
|
|
18641
|
+
const fieldId = paramToFieldId.get(paramName);
|
|
18642
|
+
if (!fieldId || seen.has(fieldId)) continue;
|
|
18643
|
+
seen.add(fieldId);
|
|
18644
|
+
if (LOGS_ARRAY_FIELD_IDS.has(fieldId)) {
|
|
18645
|
+
const raw = searchParams.getAll(paramName);
|
|
18646
|
+
if (raw.length === 0) continue;
|
|
18647
|
+
tokens.push({ fieldId, value: raw.filter(Boolean) });
|
|
18648
|
+
continue;
|
|
18649
|
+
}
|
|
18650
|
+
const value = searchParams.get(paramName);
|
|
18651
|
+
if (value !== null) tokens.push({ fieldId, value });
|
|
18652
|
+
}
|
|
18653
|
+
return tokens;
|
|
18654
|
+
}
|
|
18655
|
+
function getPreservedLogsFilterParams(searchParams) {
|
|
18656
|
+
const next = new URLSearchParams();
|
|
18657
|
+
const rootEntityType = searchParams.get(LOGS_ROOT_ENTITY_TYPE_PARAM);
|
|
18658
|
+
if (rootEntityType) next.set(LOGS_ROOT_ENTITY_TYPE_PARAM, rootEntityType);
|
|
18659
|
+
for (const fieldId of LOGS_PROPERTY_FILTER_FIELD_IDS) {
|
|
18660
|
+
const param = LOGS_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId];
|
|
18661
|
+
if (LOGS_ARRAY_FIELD_IDS.has(fieldId)) {
|
|
18662
|
+
for (const value2 of searchParams.getAll(param)) {
|
|
18663
|
+
next.append(param, value2);
|
|
18664
|
+
}
|
|
18665
|
+
continue;
|
|
18666
|
+
}
|
|
18667
|
+
const value = searchParams.get(param);
|
|
18668
|
+
if (value) next.set(param, value);
|
|
18669
|
+
}
|
|
18670
|
+
return next;
|
|
18671
|
+
}
|
|
18672
|
+
function applyLogsPropertyFilterTokens(params, tokens) {
|
|
18673
|
+
params.delete(LOGS_ROOT_ENTITY_TYPE_PARAM);
|
|
18674
|
+
for (const fieldId of LOGS_PROPERTY_FILTER_FIELD_IDS) {
|
|
18675
|
+
params.delete(LOGS_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId]);
|
|
18676
|
+
}
|
|
18677
|
+
for (const token of tokens) {
|
|
18678
|
+
if (token.fieldId === "rootEntityType" && typeof token.value === "string") {
|
|
18679
|
+
params.set(LOGS_ROOT_ENTITY_TYPE_PARAM, token.value);
|
|
18680
|
+
continue;
|
|
18681
|
+
}
|
|
18682
|
+
const param = LOGS_PROPERTY_FILTER_PARAM_BY_FIELD[token.fieldId];
|
|
18683
|
+
if (!param) continue;
|
|
18684
|
+
if (LOGS_ARRAY_FIELD_IDS.has(token.fieldId) && Array.isArray(token.value)) {
|
|
18685
|
+
if (token.value.length === 0) {
|
|
18686
|
+
params.append(param, "");
|
|
18687
|
+
} else {
|
|
18688
|
+
for (const value of token.value) {
|
|
18689
|
+
params.append(param, value);
|
|
18690
|
+
}
|
|
18691
|
+
}
|
|
18692
|
+
continue;
|
|
18693
|
+
}
|
|
18694
|
+
if (typeof token.value === "string") {
|
|
18695
|
+
params.set(param, token.value.trim());
|
|
18696
|
+
}
|
|
18697
|
+
}
|
|
18698
|
+
}
|
|
18699
|
+
function buildLogsListFilters({
|
|
18700
|
+
rootEntityType,
|
|
18701
|
+
dateFrom,
|
|
18702
|
+
dateTo,
|
|
18703
|
+
tokens
|
|
18704
|
+
}) {
|
|
18705
|
+
const filters = {};
|
|
18706
|
+
if (rootEntityType) {
|
|
18707
|
+
filters.rootEntityType = rootEntityType;
|
|
18708
|
+
}
|
|
18709
|
+
if (dateFrom || dateTo) {
|
|
18710
|
+
filters.timestamp = {
|
|
18711
|
+
...dateFrom ? { start: dateFrom } : {},
|
|
18712
|
+
...dateTo ? { end: dateTo } : {}
|
|
18713
|
+
};
|
|
18714
|
+
}
|
|
18715
|
+
for (const token of tokens) {
|
|
18716
|
+
if (token.fieldId === "tags") {
|
|
18717
|
+
if (Array.isArray(token.value) && token.value.length > 0) {
|
|
18718
|
+
filters.tags = token.value;
|
|
18719
|
+
} else if (typeof token.value === "string" && token.value.trim()) {
|
|
18720
|
+
filters.tags = [token.value.trim()];
|
|
18721
|
+
}
|
|
18722
|
+
continue;
|
|
18723
|
+
}
|
|
18724
|
+
if (token.fieldId === "level") {
|
|
18725
|
+
if (typeof token.value === "string" && token.value.trim() && token.value !== "Any") {
|
|
18726
|
+
filters.level = token.value;
|
|
18727
|
+
}
|
|
18728
|
+
continue;
|
|
18729
|
+
}
|
|
18730
|
+
if (typeof token.value !== "string") continue;
|
|
18731
|
+
if (!token.value.trim()) continue;
|
|
18732
|
+
if (token.value === "Any") continue;
|
|
18733
|
+
switch (token.fieldId) {
|
|
18734
|
+
case "entityName":
|
|
18735
|
+
filters.rootEntityName = token.value;
|
|
18736
|
+
break;
|
|
18737
|
+
case "traceId":
|
|
18738
|
+
filters.traceId = token.value;
|
|
18739
|
+
break;
|
|
18740
|
+
case "spanId":
|
|
18741
|
+
filters.spanId = token.value;
|
|
18742
|
+
break;
|
|
18743
|
+
case "runId":
|
|
18744
|
+
filters.runId = token.value;
|
|
18745
|
+
break;
|
|
18746
|
+
case "threadId":
|
|
18747
|
+
filters.threadId = token.value;
|
|
18748
|
+
break;
|
|
18749
|
+
case "sessionId":
|
|
18750
|
+
filters.sessionId = token.value;
|
|
18751
|
+
break;
|
|
18752
|
+
case "requestId":
|
|
18753
|
+
filters.requestId = token.value;
|
|
18754
|
+
break;
|
|
18755
|
+
case "resourceId":
|
|
18756
|
+
filters.resourceId = token.value;
|
|
18757
|
+
break;
|
|
18758
|
+
case "userId":
|
|
18759
|
+
filters.userId = token.value;
|
|
18760
|
+
break;
|
|
18761
|
+
case "organizationId":
|
|
18762
|
+
filters.organizationId = token.value;
|
|
18763
|
+
break;
|
|
18764
|
+
case "serviceName":
|
|
18765
|
+
filters.serviceName = token.value;
|
|
18766
|
+
break;
|
|
18767
|
+
case "environment":
|
|
18768
|
+
filters.environment = token.value;
|
|
18769
|
+
break;
|
|
18770
|
+
case "experimentId":
|
|
18771
|
+
filters.experimentId = token.value;
|
|
18772
|
+
break;
|
|
18773
|
+
}
|
|
18774
|
+
}
|
|
18775
|
+
return filters;
|
|
18776
|
+
}
|
|
18777
|
+
function neutralizeLogsFilterTokens(filterFields, filterTokens) {
|
|
18778
|
+
return filterTokens.map((token) => {
|
|
18779
|
+
const field = filterFields.find((f) => f.id === token.fieldId);
|
|
18780
|
+
if (!field) return token;
|
|
18781
|
+
if (field.kind === "text") return { fieldId: token.fieldId, value: "" };
|
|
18782
|
+
if (field.kind === "pick-multi") {
|
|
18783
|
+
return field.multi ? { fieldId: token.fieldId, value: [] } : { fieldId: token.fieldId, value: "Any" };
|
|
18784
|
+
}
|
|
18785
|
+
return token;
|
|
18786
|
+
});
|
|
18787
|
+
}
|
|
18788
|
+
|
|
18789
|
+
const LOG_PARAM = "logId";
|
|
18790
|
+
const TRACE_PARAM = "traceId";
|
|
18791
|
+
const SPAN_PARAM = "spanId";
|
|
18792
|
+
const DAY_MS = 24 * 60 * 60 * 1e3;
|
|
18793
|
+
const PRESET_MS = {
|
|
18794
|
+
"last-24h": DAY_MS,
|
|
18795
|
+
"last-3d": 3 * DAY_MS,
|
|
18796
|
+
"last-7d": 7 * DAY_MS,
|
|
18797
|
+
"last-14d": 14 * DAY_MS,
|
|
18798
|
+
"last-30d": 30 * DAY_MS
|
|
18799
|
+
};
|
|
18800
|
+
function clearSelectionParams(params) {
|
|
18801
|
+
params.delete(LOG_PARAM);
|
|
18802
|
+
params.delete(TRACE_PARAM);
|
|
18803
|
+
params.delete(SPAN_PARAM);
|
|
18804
|
+
}
|
|
18805
|
+
function useLogsUrlState(searchParams, setSearchParams, options) {
|
|
18806
|
+
const { onRemoveAll } = options ?? {};
|
|
18807
|
+
const datePreset = useMemo(() => {
|
|
18808
|
+
const value = searchParams.get(LOGS_DATE_PRESET_PARAM);
|
|
18809
|
+
return value && LOGS_DATE_PRESET_VALUES.has(value) ? value : "last-24h";
|
|
18810
|
+
}, [searchParams]);
|
|
18811
|
+
const dateFromParamRaw = searchParams.get(LOGS_DATE_FROM_PARAM);
|
|
18812
|
+
const dateToParamRaw = searchParams.get(LOGS_DATE_TO_PARAM);
|
|
18813
|
+
const selectedDateFrom = useMemo(() => {
|
|
18814
|
+
if (datePreset === "custom") {
|
|
18815
|
+
if (!dateFromParamRaw) return void 0;
|
|
18816
|
+
const parsed = new Date(dateFromParamRaw);
|
|
18817
|
+
return Number.isNaN(parsed.getTime()) ? void 0 : parsed;
|
|
18818
|
+
}
|
|
18819
|
+
if (datePreset === "all") return void 0;
|
|
18820
|
+
const ms = PRESET_MS[datePreset];
|
|
18821
|
+
return ms ? new Date(Date.now() - ms) : void 0;
|
|
18822
|
+
}, [datePreset, dateFromParamRaw]);
|
|
18823
|
+
const selectedDateTo = useMemo(() => {
|
|
18824
|
+
if (datePreset !== "custom" || !dateToParamRaw) return void 0;
|
|
18825
|
+
const parsed = new Date(dateToParamRaw);
|
|
18826
|
+
return Number.isNaN(parsed.getTime()) ? void 0 : parsed;
|
|
18827
|
+
}, [datePreset, dateToParamRaw]);
|
|
18828
|
+
const datePresetRef = useRef(datePreset);
|
|
18829
|
+
datePresetRef.current = datePreset;
|
|
18830
|
+
const featuredLogId = searchParams.get(LOG_PARAM);
|
|
18831
|
+
const featuredTraceId = searchParams.get(TRACE_PARAM);
|
|
18832
|
+
const featuredSpanId = searchParams.get(SPAN_PARAM);
|
|
18833
|
+
const selectedEntityOption = useMemo(
|
|
18834
|
+
() => LOGS_ROOT_ENTITY_TYPE_OPTIONS.find((option) => option.entityType === searchParams.get(LOGS_ROOT_ENTITY_TYPE_PARAM)),
|
|
18835
|
+
[searchParams]
|
|
18836
|
+
);
|
|
18837
|
+
const filterTokens = useMemo(() => getLogsPropertyFilterTokens(searchParams), [searchParams]);
|
|
18838
|
+
const handleFeaturedChange = useCallback(
|
|
18839
|
+
(ids) => {
|
|
18840
|
+
setSearchParams(
|
|
18841
|
+
(prev) => {
|
|
18842
|
+
const next = new URLSearchParams(prev);
|
|
18843
|
+
for (const [field, value] of Object.entries(ids)) {
|
|
18844
|
+
const param = field === "logId" ? LOG_PARAM : field === "traceId" ? TRACE_PARAM : SPAN_PARAM;
|
|
18845
|
+
if (value) {
|
|
18846
|
+
next.set(param, value);
|
|
18847
|
+
} else {
|
|
18848
|
+
next.delete(param);
|
|
18849
|
+
}
|
|
18850
|
+
}
|
|
18851
|
+
return next;
|
|
18852
|
+
},
|
|
18853
|
+
{ replace: true }
|
|
18854
|
+
);
|
|
18855
|
+
},
|
|
18856
|
+
[setSearchParams]
|
|
18857
|
+
);
|
|
18858
|
+
const applyFilterTokens = useCallback(
|
|
18859
|
+
(tokens) => {
|
|
18860
|
+
setSearchParams(
|
|
18861
|
+
(prev) => {
|
|
18862
|
+
const next = new URLSearchParams(prev);
|
|
18863
|
+
applyLogsPropertyFilterTokens(next, tokens);
|
|
18864
|
+
clearSelectionParams(next);
|
|
18865
|
+
return next;
|
|
18866
|
+
},
|
|
18867
|
+
{ replace: true }
|
|
18868
|
+
);
|
|
18869
|
+
},
|
|
18870
|
+
[setSearchParams]
|
|
18871
|
+
);
|
|
18872
|
+
const handleFilterTokensChange = applyFilterTokens;
|
|
18873
|
+
const handleDateChange = useCallback(
|
|
18874
|
+
(value, type) => {
|
|
18875
|
+
if (datePresetRef.current !== "custom") return;
|
|
18876
|
+
const param = type === "from" ? LOGS_DATE_FROM_PARAM : LOGS_DATE_TO_PARAM;
|
|
18877
|
+
setSearchParams(
|
|
18878
|
+
(prev) => {
|
|
18879
|
+
const next = new URLSearchParams(prev);
|
|
18880
|
+
if (value) {
|
|
18881
|
+
next.set(param, value.toISOString());
|
|
18882
|
+
} else {
|
|
18883
|
+
next.delete(param);
|
|
18884
|
+
}
|
|
18885
|
+
clearSelectionParams(next);
|
|
18886
|
+
return next;
|
|
18887
|
+
},
|
|
18888
|
+
{ replace: true }
|
|
18889
|
+
);
|
|
18890
|
+
},
|
|
18891
|
+
[setSearchParams]
|
|
18892
|
+
);
|
|
18893
|
+
const handleDatePresetChange = useCallback(
|
|
18894
|
+
(preset) => {
|
|
18895
|
+
datePresetRef.current = preset;
|
|
18896
|
+
setSearchParams(
|
|
18897
|
+
(prev) => {
|
|
18898
|
+
const next = new URLSearchParams(prev);
|
|
18899
|
+
if (preset === "last-24h") {
|
|
18900
|
+
next.delete(LOGS_DATE_PRESET_PARAM);
|
|
18901
|
+
next.delete(LOGS_DATE_FROM_PARAM);
|
|
18902
|
+
next.delete(LOGS_DATE_TO_PARAM);
|
|
18903
|
+
} else if (preset === "custom") {
|
|
18904
|
+
next.set(LOGS_DATE_PRESET_PARAM, "custom");
|
|
18905
|
+
} else {
|
|
18906
|
+
next.set(LOGS_DATE_PRESET_PARAM, preset);
|
|
18907
|
+
next.delete(LOGS_DATE_FROM_PARAM);
|
|
18908
|
+
next.delete(LOGS_DATE_TO_PARAM);
|
|
18909
|
+
}
|
|
18910
|
+
clearSelectionParams(next);
|
|
18911
|
+
return next;
|
|
18912
|
+
},
|
|
18913
|
+
{ replace: true }
|
|
18914
|
+
);
|
|
18915
|
+
},
|
|
18916
|
+
[setSearchParams]
|
|
18917
|
+
);
|
|
18918
|
+
const handleRemoveAll = useCallback(() => {
|
|
18919
|
+
setSearchParams(
|
|
18920
|
+
(prev) => {
|
|
18921
|
+
const next = new URLSearchParams(prev);
|
|
18922
|
+
next.delete(LOGS_ROOT_ENTITY_TYPE_PARAM);
|
|
18923
|
+
for (const fieldId of LOGS_PROPERTY_FILTER_FIELD_IDS) {
|
|
18924
|
+
next.delete(LOGS_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId]);
|
|
18925
|
+
}
|
|
18926
|
+
next.delete(LOGS_DATE_PRESET_PARAM);
|
|
18927
|
+
next.delete(LOGS_DATE_FROM_PARAM);
|
|
18928
|
+
next.delete(LOGS_DATE_TO_PARAM);
|
|
18929
|
+
clearSelectionParams(next);
|
|
18930
|
+
return next;
|
|
18931
|
+
},
|
|
18932
|
+
{ replace: true }
|
|
18933
|
+
);
|
|
18934
|
+
onRemoveAll?.();
|
|
18935
|
+
}, [setSearchParams, onRemoveAll]);
|
|
18936
|
+
return useMemo(
|
|
18937
|
+
() => ({
|
|
18938
|
+
searchParams,
|
|
18939
|
+
setSearchParams,
|
|
18940
|
+
datePreset,
|
|
18941
|
+
selectedDateFrom,
|
|
18942
|
+
selectedDateTo,
|
|
18943
|
+
datePresetRef,
|
|
18944
|
+
featuredLogId,
|
|
18945
|
+
featuredTraceId,
|
|
18946
|
+
featuredSpanId,
|
|
18947
|
+
selectedEntityOption,
|
|
18948
|
+
filterTokens,
|
|
18949
|
+
handleFeaturedChange,
|
|
18950
|
+
handleFilterTokensChange,
|
|
18951
|
+
handleDateChange,
|
|
18952
|
+
handleDatePresetChange,
|
|
18953
|
+
handleRemoveAll,
|
|
18954
|
+
applyFilterTokens
|
|
18955
|
+
}),
|
|
18956
|
+
[
|
|
18957
|
+
searchParams,
|
|
18958
|
+
setSearchParams,
|
|
18959
|
+
datePreset,
|
|
18960
|
+
selectedDateFrom,
|
|
18961
|
+
selectedDateTo,
|
|
18962
|
+
datePresetRef,
|
|
18963
|
+
featuredLogId,
|
|
18964
|
+
featuredTraceId,
|
|
18965
|
+
featuredSpanId,
|
|
18966
|
+
selectedEntityOption,
|
|
18967
|
+
filterTokens,
|
|
18968
|
+
handleFeaturedChange,
|
|
18969
|
+
handleFilterTokensChange,
|
|
18970
|
+
handleDateChange,
|
|
18971
|
+
handleDatePresetChange,
|
|
18972
|
+
handleRemoveAll,
|
|
18973
|
+
applyFilterTokens
|
|
18974
|
+
]
|
|
18975
|
+
);
|
|
18976
|
+
}
|
|
18977
|
+
|
|
18978
|
+
const DEFAULT_SAVED_MESSAGE = "Filters setting for Logs saved";
|
|
18979
|
+
const DEFAULT_CLEARED_MESSAGE = "Filters setting for Logs cleared up";
|
|
18980
|
+
function useLogsFilterPersistence(searchParams, setSearchParams, options) {
|
|
18981
|
+
const { storageKey, messages, skipHydration } = options ?? {};
|
|
18982
|
+
const [hasSavedFilters, setHasSavedFilters] = useState(() => loadLogsFiltersFromStorage(storageKey) !== null);
|
|
18983
|
+
const handleSave = useCallback(() => {
|
|
18984
|
+
saveLogsFiltersToStorage(searchParams, storageKey);
|
|
18985
|
+
setHasSavedFilters(true);
|
|
18986
|
+
const text = messages?.saved ?? DEFAULT_SAVED_MESSAGE;
|
|
18987
|
+
if (text !== false) toast.success(text);
|
|
18988
|
+
}, [searchParams, storageKey, messages?.saved]);
|
|
18989
|
+
const handleRemoveSaved = useCallback(() => {
|
|
18990
|
+
clearSavedLogsFilters(storageKey);
|
|
18991
|
+
setHasSavedFilters(false);
|
|
18992
|
+
const text = messages?.cleared ?? DEFAULT_CLEARED_MESSAGE;
|
|
18993
|
+
if (text !== false) toast.success(text);
|
|
18994
|
+
}, [storageKey, messages?.cleared]);
|
|
18995
|
+
const hydratedRef = useRef(false);
|
|
18996
|
+
useEffect(() => {
|
|
18997
|
+
if (skipHydration) return;
|
|
18998
|
+
if (hydratedRef.current) return;
|
|
18999
|
+
hydratedRef.current = true;
|
|
19000
|
+
if (hasAnyLogsFilterParams(searchParams)) return;
|
|
19001
|
+
const saved = loadLogsFiltersFromStorage(storageKey);
|
|
19002
|
+
if (!saved) return;
|
|
19003
|
+
setSearchParams(
|
|
19004
|
+
(prev) => {
|
|
19005
|
+
const next = new URLSearchParams(prev);
|
|
19006
|
+
for (const [key, value] of saved) {
|
|
19007
|
+
next.append(key, value);
|
|
19008
|
+
}
|
|
19009
|
+
return next;
|
|
19010
|
+
},
|
|
19011
|
+
{ replace: true }
|
|
19012
|
+
);
|
|
19013
|
+
}, []);
|
|
19014
|
+
return { hasSavedFilters, handleSave, handleRemoveSaved };
|
|
19015
|
+
}
|
|
19016
|
+
|
|
19017
|
+
function hashCode(str) {
|
|
19018
|
+
let hash = 0;
|
|
19019
|
+
for (let i = 0; i < str.length; i++) {
|
|
19020
|
+
hash = (hash << 5) - hash + str.charCodeAt(i) | 0;
|
|
19021
|
+
}
|
|
19022
|
+
return (hash >>> 0).toString(36);
|
|
19023
|
+
}
|
|
19024
|
+
function buildLogIds(logs) {
|
|
19025
|
+
const ids = /* @__PURE__ */ new Map();
|
|
19026
|
+
for (const log of logs) {
|
|
19027
|
+
if (log.logId) {
|
|
19028
|
+
ids.set(log, log.logId);
|
|
19029
|
+
continue;
|
|
19030
|
+
}
|
|
19031
|
+
const ts = log.timestamp instanceof Date ? log.timestamp.toISOString() : log.timestamp;
|
|
19032
|
+
ids.set(log, hashCode(`${ts}${log.message ?? ""}${log.data ? JSON.stringify(log.data) : ""}`));
|
|
19033
|
+
}
|
|
19034
|
+
return ids;
|
|
19035
|
+
}
|
|
19036
|
+
function useLogsListNavigation(logs, featuredLogId, onFeaturedChange, featuredTraceId) {
|
|
19037
|
+
const logIdMap = useMemo(() => buildLogIds(logs), [logs]);
|
|
19038
|
+
const idToLog = useMemo(() => {
|
|
19039
|
+
const m = /* @__PURE__ */ new Map();
|
|
19040
|
+
for (let i = 0; i < logs.length; i++) {
|
|
19041
|
+
const id = logIdMap.get(logs[i]);
|
|
19042
|
+
if (id) m.set(id, { log: logs[i], idx: i });
|
|
19043
|
+
}
|
|
19044
|
+
return m;
|
|
19045
|
+
}, [logs, logIdMap]);
|
|
19046
|
+
const entry = featuredLogId ? idToLog.get(featuredLogId) : void 0;
|
|
19047
|
+
const featuredLogIdx = entry?.idx ?? -1;
|
|
19048
|
+
const featuredLog = featuredLogIdx >= 0 ? logs[featuredLogIdx] : null;
|
|
19049
|
+
const getLogId = useCallback((log) => logIdMap.get(log), [logIdMap]);
|
|
19050
|
+
const handleLogClick = useCallback(
|
|
19051
|
+
(log) => {
|
|
19052
|
+
const id = logIdMap.get(log);
|
|
19053
|
+
if (!id) return;
|
|
19054
|
+
if (featuredLogId === id) {
|
|
19055
|
+
onFeaturedChange({ logId: null });
|
|
19056
|
+
return;
|
|
19057
|
+
}
|
|
19058
|
+
if (featuredTraceId) {
|
|
19059
|
+
onFeaturedChange({ logId: id, traceId: log.traceId ?? null, spanId: null });
|
|
19060
|
+
} else {
|
|
19061
|
+
onFeaturedChange({ logId: id });
|
|
19062
|
+
}
|
|
19063
|
+
},
|
|
19064
|
+
[logIdMap, featuredLogId, featuredTraceId, onFeaturedChange]
|
|
19065
|
+
);
|
|
19066
|
+
const handlePreviousLog = featuredLogIdx > 0 ? () => {
|
|
19067
|
+
const prevLog = logs[featuredLogIdx - 1];
|
|
19068
|
+
const id = logIdMap.get(prevLog);
|
|
19069
|
+
if (featuredTraceId) {
|
|
19070
|
+
onFeaturedChange({ logId: id, traceId: prevLog.traceId ?? null, spanId: null });
|
|
19071
|
+
} else {
|
|
19072
|
+
onFeaturedChange({ logId: id });
|
|
19073
|
+
}
|
|
19074
|
+
} : void 0;
|
|
19075
|
+
const handleNextLog = featuredLogIdx >= 0 && featuredLogIdx < logs.length - 1 ? () => {
|
|
19076
|
+
const nextLog = logs[featuredLogIdx + 1];
|
|
19077
|
+
const id = logIdMap.get(nextLog);
|
|
19078
|
+
if (featuredTraceId) {
|
|
19079
|
+
onFeaturedChange({ logId: id, traceId: nextLog.traceId ?? null, spanId: null });
|
|
19080
|
+
} else {
|
|
19081
|
+
onFeaturedChange({ logId: id });
|
|
19082
|
+
}
|
|
19083
|
+
} : void 0;
|
|
19084
|
+
return {
|
|
19085
|
+
logIdMap,
|
|
19086
|
+
getLogId,
|
|
19087
|
+
featuredLog,
|
|
19088
|
+
handleLogClick,
|
|
19089
|
+
handlePreviousLog,
|
|
19090
|
+
handleNextLog
|
|
19091
|
+
};
|
|
19092
|
+
}
|
|
19093
|
+
|
|
19094
|
+
export { AddField, AgentCoinIcon, AgentIcon, AgentNetworkCoinIcon, AiIcon, Alert, AlertDescription, AlertDialog, AlertTitle, AmazonIcon, AnthropicChatIcon, AnthropicMessagesIcon, ApiIcon, Avatar, AzureIcon, Badge, BarListContent, BorderColors, BorderRadius, BranchIcon, BrandLoader, Breadcrumb, Button, ButtonWithTooltip, ButtonsGroup, CHART_COLORS, CONTEXT_FIELD_IDS, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Cell, CheckIcon, Checkbox, ChevronIcon, Chip, ChipsGroup, CodeDiff, CodeEditor, CohereIcon, Collapsible, CollapsibleContent, CollapsiblePanel, CollapsibleTrigger, Colors, Column, Columns, CombinedButtons, Combobox, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, CommitIcon, ContentBlock, ContentBlocks, CopyButton, CrossIcon, Crumb, DATE_PRESETS, DEFAULT_LOGS_FILTERS_STORAGE_KEY, DEFAULT_TRACE_FILTERS_STORAGE_KEY, DashboardCard, DataCodeSection, DataDetailsPanel, DataKeysAndValues, DataList, DataListSkeleton, DataPanel, DatePicker, DateRangeSelector, DateTimeCell, DateTimePicker, DateTimePickerContent, DateTimeRangePicker, DbIcon, DebugIcon, DefaultTrigger, DeploymentIcon, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DividerIcon, DocsIcon, DropdownMenu, EXTENSION_TO_MIME, ElementSelect, EmptyState, Entity, EntityContent, EntityDescription, EntityHeader, EntityIcon, EntityList, EntityListPageLayout, EntityListSkeleton, EntityName, Entry, EntryCell, EntryList, EntryListSkeleton, EnvIcon, ErrorBoundary, ErrorState, Field, FieldBlock, FieldBlocksLayout, FieldDescription, FieldList, FieldName, FieldNullable, FieldOptional, FieldRemove, FieldType, FiltersIcon, FolderIcon, FontSizes, GithubCoinIcon, GithubIcon, Glows, GoogleIcon, GroqIcon, Header$1 as Header, HeaderAction, HeaderGroup, HeaderTitle, HomeIcon, HorizontalBars, HoverPopover, Icon, IconButton, InfoIcon, Input, ItemList, ItemListSkeleton, JSONSchemaForm, JudgeIcon, Kbd, KeyValueList, KpiCardView, LOGS_DATE_FROM_PARAM, LOGS_DATE_PRESET_PARAM, LOGS_DATE_PRESET_VALUES, LOGS_DATE_TO_PARAM, LOGS_PROPERTY_FILTER_FIELD_IDS, LOGS_PROPERTY_FILTER_PARAM_BY_FIELD, LOGS_ROOT_ENTITY_TYPES, LOGS_ROOT_ENTITY_TYPE_OPTIONS, LOGS_ROOT_ENTITY_TYPE_PARAM, LOG_LEVEL_OPTIONS, LOG_LEVEL_VALUES, Label, LatencyCardView, LatencyIcon, LineHeights, ListSearch, LogDetailsView, Logo, LogoWithoutText, LogsDataList, DataListSkeleton as LogsDataListSkeleton, LogsErrorContent, LogsIcon, LogsLayout, LogsListView, LogsToolbar, MainContentContent, MainContentLayout, MainHeader, MainSidebar, MainSidebarProvider, MainSidebarTrigger, MarkdownRenderer, MastraIcon, McpCoinIcon, McpServerIcon, MemoryIcon, MetricsCard, MetricsDataTable, MetricsFlexGrid, MetricsKpiCard, MetricsLineChart, MetricsLineChartTooltip, MetricsProvider, MistralIcon, ModelUsageCostCardView, MultiColumn, MultiCombobox, NestedFields, NetlifyIcon, NoDataPageLayout, NoLogsInfo, Notice, Notification, OPERATORS, OPERATOR_LABELS, OpenAIIcon, OpenaiChatIcon, PageHeader, PageLayout, PanelSeparator, PermissionDenied, PickMultiPanel, Popover, PopoverContent, PopoverTrigger, PrevNextNav, ProcessStepList, ProcessStepListItem, ProcessStepProgressBar, ProcessorIcon, PromptIcon, PropertyFilterActions, PropertyFilterApplied, PropertyFilterCreator, ROOT_ENTITY_TYPES, ROOT_ENTITY_TYPE_OPTIONS, RadioGroup, RadioGroupItem, RepoIcon, Root$1 as Root, Row, RuleBuilder, RuleFieldSelect, RuleOperatorSelect, RuleRow, RuleValueInput, ScoresCardView, ScoresDataList, ScrollArea, ScrollBar, ScrollableContainer, SearchFieldBlock, Searchbar, SearchbarWrapper, Section, SectionRoot, Sections, Select, SelectContent, SelectDataFilter, SelectField, SelectFieldBlock, SelectGroup, SelectItem, SelectTrigger, SelectValue, SessionExpired, SettingsIcon, Shadows, SideDialog, Sizes, Skeleton, SkillIcon, SlashIcon, Slider, Spacings, SpanDataPanelView, SpanDetailsView, SpanTokenUsage, Spinner, StackedRunsBars, StatusBadge, SubSectionRoot, Switch, TRACE_DATE_FROM_PARAM, TRACE_DATE_PRESET_PARAM, TRACE_DATE_PRESET_VALUES, TRACE_DATE_TO_PARAM, TRACE_PROPERTY_FILTER_FIELD_IDS, TRACE_PROPERTY_FILTER_PARAM_BY_FIELD, TRACE_ROOT_ENTITY_TYPE_PARAM, TRACE_STATUS_OPTIONS, TRACE_STATUS_PARAM, TRACE_STATUS_VALUES, TRACE_SYNTHETIC_FILTER_FIELD_IDS, Tab, TabContent, TabList, Table, Tabs, Tbody, TextAndIcon, TextFieldBlock, Textarea, Th, Thead, ThreadDeleteButton, ThreadItem, ThreadLink, ThreadList, Threads, TimePicker, TimelineExpandCol, TimelineNameCol, TimelineStructureSign, TimelineTimingCol, TokenUsageByAgentCardView, ToolCoinIcon, ToolsIcon, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TraceDataPanelView, TraceDetailsView, TraceIcon, TraceKeysAndValues, TraceTimeline, TraceTimelineSpan, TracesDataList, TracesErrorContent, TracesLayout, TracesListView, TracesToolbar, TracesVolumeCardView, Tree, Truncate, TsIcon, Txt, TxtCell, VARIABLE_PATTERN, VariablesIcon, WorkflowCoinIcon, WorkflowIcon, XGroqIcon, applyLogsPropertyFilterTokens, applyTracePropertyFilterTokens, buildLogsListFilters, buildTraceListFilters, buttonVariants, clearSavedLogsFilters, clearSavedTraceFilters, cn, comboboxStyles, countLeafRules, createDefaultRule, createDefaultRuleGroup, createField, createLogsPropertyFilterFields, createTracePropertyFilterFields, createVariableAutocomplete, fieldsToJSONSchema, fileToBase64, flattenSchemaToVariables, focusRing, formElementFocus, formElementFocusWithin, formElementRadius, formElementSizes, formElementTransition, formatCompact, formatCost, formatHierarchicalSpans, formatJSON, generateDefaultValues, getAllSpanIds, getChildFieldOptions, getColumnTemplate, getFieldOptionAtPath, getFieldOptionsFromSchema, getFileContentType, getInputPreview, getItemListColumnTemplate, getLogsPropertyFilterTokens, getMainContentContentClassName, getPreservedLogsFilterParams, getPreservedTraceFilterParams, getShortId$1 as getShortId, getSpanDescendantIds, getSpanTypeUi, getStatusIcon, getToNextEntryFn, getToNextItemFn, getToPreviousEntryFn, getToPreviousItemFn, getTokenLimitMessage, getTracePropertyFilterTokens, groupTracesByThread, hasAnyLogsFilterParams, hasAnyTraceFilterParams, highlight, hoverEffects, inputVariants, is401UnauthorizedError, is403ForbiddenError, isNonRetryableError, isObjectEmpty, isRule, isRuleGroup, isTokenLimitExceeded, isValidJson, isValidPreset, jsonSchemaToFields, loadLogsFiltersFromStorage, loadTraceFiltersFromStorage, lodashTitleCase, neutralizeFilterTokens, neutralizeLogsFilterTokens, parseError, parseFieldPath, saveLogsFiltersToStorage, saveTraceFiltersToStorage, sharedFormElementDisabledStyle, sharedFormElementFocusStyle, sharedFormElementStyle, shouldRetryQuery, spanTypePrefixes, stringToColor, textareaVariants, toSigFigs, toast, transitions, truncateString, useAgentRunsKpiMetrics, useAutoscroll, useAvgScoreKpiMetrics, useCodemirrorTheme$3 as useCodemirrorTheme, useCopyToClipboard, useEntityNames, useEnvironments, useInView, useIsDarkMode, useJSONSchemaForm, useJSONSchemaFormField, useJSONSchemaFormNestedContext, useLatencyMetrics, useLogs, useLogsFilterPersistence, useLogsListNavigation, useLogsUrlState, useMainSidebar, useMaybeSidebar, useMetrics, useMetricsFilters, useModelCostKpiMetrics, useModelUsageCostMetrics, usePlaygroundStore, useScoresMetrics, useServiceNames, useSpanDetail, useTableKeyboardNavigation, useTags, useTokenUsageByAgentMetrics, useTotalTokensKpiMetrics, useTraceFilterPersistence, useTraceLightSpans, useTraceListNavigation, useTraceSpanNavigation, useTraceSpans, useTraceUrlState, useTraceVolumeMetrics, useTraces, variableHighlight };
|
|
14974
19095
|
//# sourceMappingURL=index.es.js.map
|