@mastra/playground-ui 69.0.0-alpha.2 → 69.0.0-alpha.3

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.
@@ -44,8 +44,9 @@ function useObservabilityListFilters(url, { sortFields, defaultDatePreset = requ
44
44
  const fromMs = dateFrom?.getTime();
45
45
  const toMs = dateTo?.getTime();
46
46
  const timeRange = (0, react.useMemo)(() => {
47
- const window = require_domains_traces_components_traces_explorer_traces_explorer_actions.resolveTracesDateWindow(datePreset, fromMs === void 0 ? void 0 : new Date(fromMs), toMs === void 0 ? void 0 : new Date(toMs));
48
- return require_trace_filters.resolveTraceQueryTimeRange(window.dateFrom, window.dateTo, /* @__PURE__ */ new Date());
47
+ const now = /* @__PURE__ */ new Date();
48
+ const window = require_domains_traces_components_traces_explorer_traces_explorer_actions.resolveTracesDateWindow(datePreset, fromMs === void 0 ? void 0 : new Date(fromMs), toMs === void 0 ? void 0 : new Date(toMs), now);
49
+ return require_trace_filters.resolveTraceQueryTimeRange(window.dateFrom, window.dateTo, now);
49
50
  }, [
50
51
  datePreset,
51
52
  fromMs,
@@ -1 +1 @@
1
- {"version":3,"file":"use-observability-list-filters.cjs.js","names":["recoveryRefetchInterval","useState","OBSERVABILITY_LIST_DEFAULT_DATE_PRESET","readObservabilityListDates","readObservabilityListFilters","useMemo","readObservabilityListSort","OBSERVABILITY_LIST_SORT_FIELDS","resolveTracesDateWindow","resolveTraceQueryTimeRange","useRef","writeObservabilityListDates","rememberZoom","rangeBeforeZoom","writeObservabilityListFilters","writeObservabilityListSort"],"sources":["../../../../src/domains/observability/hooks/use-observability-list-filters.ts"],"sourcesContent":["import { useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { rangeBeforeZoom, rememberZoom } from '../lib/zoom-memory';\nimport type { ZoomMemory } from '../lib/zoom-memory';\nimport {\n OBSERVABILITY_LIST_DEFAULT_DATE_PRESET,\n OBSERVABILITY_LIST_SORT_FIELDS,\n readObservabilityListDates,\n readObservabilityListFilters,\n readObservabilityListSort,\n writeObservabilityListDates,\n writeObservabilityListFilters,\n writeObservabilityListSort,\n} from '../observability-list-url-state';\nimport type { ObservabilityListDates, ObservabilityListSort } from '../observability-list-url-state';\nimport { recoveryRefetchInterval } from '@/domains/observability/list-polling';\nimport { resolveTracesDateWindow } from '@/domains/traces/components/traces-explorer/traces-explorer-actions';\nimport { resolveTraceQueryTimeRange } from '@/domains/traces/trace-query-filters';\nimport type { TraceFilterGroup, TraceFilterToken } from '@/domains/traces/trace-query-filters';\nimport type { TraceDatePreset } from '@/domains/traces/types';\nimport type { SetURLSearchParamsLike } from '@/lib/sort/use-url-sort';\n\n/**\n * Like the traces list with delta polling: a timer or a window focus would reload every loaded page\n * and reset the cursor chain, so an observability list only reloads to recover from a transient failure.\n */\nexport const observabilityListQueryOptions = {\n refetchInterval: ({ state }: { state: { error: unknown } }) => recoveryRefetchInterval(state.error),\n refetchOnWindowFocus: false,\n};\n\nexport type ObservabilityListUrlState = {\n searchParams: URLSearchParams;\n setSearchParams: SetURLSearchParamsLike;\n};\n\n/** The search params of `url`, or of an in-memory store when the host keeps no URL state. */\nfunction useListSearchParams(url: ObservabilityListUrlState | undefined): ObservabilityListUrlState {\n const [localParams, setLocalParams] = useState(() => new URLSearchParams());\n if (url) return url;\n return {\n searchParams: localParams,\n setSearchParams: next => setLocalParams(prev => (typeof next === 'function' ? next(prev) : next)),\n };\n}\n\n/**\n * The time range, filter and sort state of a spans or threads list, kept in the host's URL (same\n * date, sort and group params as /traces) so it survives a reload and can be shared. Without `url`\n * the state lives in memory. A sort on a field outside `sortFields` reads as start time, newest first.\n * `defaultDatePreset` is the range shown when the URL names none (last 7 days unless the host differs);\n * it is left out of the URL like any default.\n */\nexport function useObservabilityListFilters<F extends string = 'startedAt'>(\n url?: ObservabilityListUrlState,\n {\n sortFields,\n defaultDatePreset = OBSERVABILITY_LIST_DEFAULT_DATE_PRESET,\n }: { sortFields?: readonly F[]; defaultDatePreset?: TraceDatePreset } = {},\n) {\n const { searchParams, setSearchParams } = useListSearchParams(url);\n\n // Decoded values keep their identity while unrelated params (e.g. the open row) change.\n const datesKey = JSON.stringify(readObservabilityListDates(searchParams, defaultDatePreset));\n const filtersKey = JSON.stringify(readObservabilityListFilters(searchParams));\n const { datePreset, dateFrom, dateTo } = useMemo(\n () => readObservabilityListDates(searchParams, defaultDatePreset),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only re-read when the date params change\n [datesKey],\n );\n const { tokens, groups } = useMemo(\n () => readObservabilityListFilters(searchParams),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only re-read when the filter params change\n [filtersKey],\n );\n const urlSort = readObservabilityListSort<F | 'startedAt'>(\n searchParams,\n sortFields ?? OBSERVABILITY_LIST_SORT_FIELDS,\n );\n const sort = useMemo<ObservabilityListSort<F | 'startedAt'>>(\n () => ({ field: urlSort.field, direction: urlSort.direction }),\n [urlSort.field, urlSort.direction],\n );\n\n const fromMs = dateFrom?.getTime();\n const toMs = dateTo?.getTime();\n // Rolling presets are resolved against \"now\" only when the range changes, so the query key\n // (and the cursors issued for it) stays stable while the list scrolls.\n const timeRange = useMemo(() => {\n const window = resolveTracesDateWindow(\n datePreset,\n fromMs === undefined ? undefined : new Date(fromMs),\n toMs === undefined ? undefined : new Date(toMs),\n );\n return resolveTraceQueryTimeRange(window.dateFrom, window.dateTo, new Date());\n }, [datePreset, fromMs, toMs]);\n\n // react-router resolves even a functional update against the params of the last render, so writes\n // made in the same tick (zoom sets `custom` then the range; the picker reports the range after a\n // preset change) build on the pending params instead, like `useState` updaters would.\n const pending = useRef<URLSearchParams | null>(null);\n useLayoutEffect(() => {\n pending.current = null;\n }, [searchParams]);\n const update = (write: (next: URLSearchParams) => void) => {\n const base = pending.current ?? searchParams;\n const next = new URLSearchParams(base);\n write(next);\n if (next.toString() === base.toString()) return;\n pending.current = next;\n setSearchParams(next, { replace: true });\n };\n const updateDates = (change: (current: ObservabilityListDates) => ObservabilityListDates) =>\n update(next =>\n writeObservabilityListDates(next, change(readObservabilityListDates(next, defaultDatePreset)), defaultDatePreset),\n );\n\n // Not URL state: a shared or reloaded link has no zoom to undo.\n const zoomMemory = useRef<ZoomMemory | undefined>(undefined);\n // A range picked by hand drops the zoom memory, even one that matches the zoomed bounds.\n const pickDates = (change: (current: ObservabilityListDates) => ObservabilityListDates) => {\n zoomMemory.current = undefined;\n updateDates(change);\n };\n\n // Switching to `custom` keeps the current dates so the picker opens on them; any other preset drops them.\n const onDatePresetChange = (preset: TraceDatePreset) =>\n pickDates(current => (preset === 'custom' ? { ...current, datePreset: preset } : { datePreset: preset }));\n // The picker can report a date right after switching away from `custom`; those are ignored.\n const onDateChange = (date: Date | undefined, end: 'from' | 'to') =>\n pickDates(current => {\n if (current.datePreset !== 'custom') return current;\n return end === 'from' ? { ...current, dateFrom: date } : { ...current, dateTo: date };\n });\n const onDateRangeChange = (from: Date | undefined, to: Date | undefined) =>\n pickDates(current => (current.datePreset === 'custom' ? { ...current, dateFrom: from, dateTo: to } : current));\n /** Narrows the range to a histogram selection, remembering the range to return to on reset. */\n const onZoom = (from: Date, to: Date) =>\n updateDates(current => {\n zoomMemory.current = rememberZoom(zoomMemory.current, current, from, to);\n return { datePreset: 'custom', dateFrom: from, dateTo: to };\n });\n /** Undoes the last histogram zoom, or switches to `defaultPreset` when there is none to undo. */\n const onDateReset = (defaultPreset: TraceDatePreset) =>\n updateDates(current => {\n const before = rangeBeforeZoom(zoomMemory.current, current);\n zoomMemory.current = undefined;\n return before ?? { datePreset: defaultPreset };\n });\n const onFiltersChange = (nextTokens: TraceFilterToken[], nextGroups: TraceFilterGroup[]) =>\n update(next => writeObservabilityListFilters(next, { tokens: nextTokens, groups: nextGroups }));\n const setSort = (next: ObservabilityListSort<F | 'startedAt'>) =>\n update(params => writeObservabilityListSort(params, next));\n\n const contentFiltersApplied = tokens.length > 0 || groups.length > 0;\n const filtersApplied = contentFiltersApplied || datePreset !== defaultDatePreset;\n\n return {\n datePreset,\n dateFrom,\n dateTo,\n timeRange,\n /** The window ends at \"now\", so new rows can still land in it. */\n rolling: dateTo === undefined,\n tokens,\n groups,\n sort,\n setSort,\n onDatePresetChange,\n onDateChange,\n onDateRangeChange,\n onZoom,\n onDateReset,\n onFiltersChange,\n contentFiltersApplied,\n filtersApplied,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-observability-list-filters.cjs.js","names":["recoveryRefetchInterval","useState","OBSERVABILITY_LIST_DEFAULT_DATE_PRESET","readObservabilityListDates","readObservabilityListFilters","useMemo","readObservabilityListSort","OBSERVABILITY_LIST_SORT_FIELDS","resolveTracesDateWindow","resolveTraceQueryTimeRange","useRef","writeObservabilityListDates","rememberZoom","rangeBeforeZoom","writeObservabilityListFilters","writeObservabilityListSort"],"sources":["../../../../src/domains/observability/hooks/use-observability-list-filters.ts"],"sourcesContent":["import { useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { rangeBeforeZoom, rememberZoom } from '../lib/zoom-memory';\nimport type { ZoomMemory } from '../lib/zoom-memory';\nimport {\n OBSERVABILITY_LIST_DEFAULT_DATE_PRESET,\n OBSERVABILITY_LIST_SORT_FIELDS,\n readObservabilityListDates,\n readObservabilityListFilters,\n readObservabilityListSort,\n writeObservabilityListDates,\n writeObservabilityListFilters,\n writeObservabilityListSort,\n} from '../observability-list-url-state';\nimport type { ObservabilityListDates, ObservabilityListSort } from '../observability-list-url-state';\nimport { recoveryRefetchInterval } from '@/domains/observability/list-polling';\nimport { resolveTracesDateWindow } from '@/domains/traces/components/traces-explorer/traces-explorer-actions';\nimport { resolveTraceQueryTimeRange } from '@/domains/traces/trace-query-filters';\nimport type { TraceFilterGroup, TraceFilterToken } from '@/domains/traces/trace-query-filters';\nimport type { TraceDatePreset } from '@/domains/traces/types';\nimport type { SetURLSearchParamsLike } from '@/lib/sort/use-url-sort';\n\n/**\n * Like the traces list with delta polling: a timer or a window focus would reload every loaded page\n * and reset the cursor chain, so an observability list only reloads to recover from a transient failure.\n */\nexport const observabilityListQueryOptions = {\n refetchInterval: ({ state }: { state: { error: unknown } }) => recoveryRefetchInterval(state.error),\n refetchOnWindowFocus: false,\n};\n\nexport type ObservabilityListUrlState = {\n searchParams: URLSearchParams;\n setSearchParams: SetURLSearchParamsLike;\n};\n\n/** The search params of `url`, or of an in-memory store when the host keeps no URL state. */\nfunction useListSearchParams(url: ObservabilityListUrlState | undefined): ObservabilityListUrlState {\n const [localParams, setLocalParams] = useState(() => new URLSearchParams());\n if (url) return url;\n return {\n searchParams: localParams,\n setSearchParams: next => setLocalParams(prev => (typeof next === 'function' ? next(prev) : next)),\n };\n}\n\n/**\n * The time range, filter and sort state of a spans or threads list, kept in the host's URL (same\n * date, sort and group params as /traces) so it survives a reload and can be shared. Without `url`\n * the state lives in memory. A sort on a field outside `sortFields` reads as start time, newest first.\n * `defaultDatePreset` is the range shown when the URL names none (last 7 days unless the host differs);\n * it is left out of the URL like any default.\n */\nexport function useObservabilityListFilters<F extends string = 'startedAt'>(\n url?: ObservabilityListUrlState,\n {\n sortFields,\n defaultDatePreset = OBSERVABILITY_LIST_DEFAULT_DATE_PRESET,\n }: { sortFields?: readonly F[]; defaultDatePreset?: TraceDatePreset } = {},\n) {\n const { searchParams, setSearchParams } = useListSearchParams(url);\n\n // Decoded values keep their identity while unrelated params (e.g. the open row) change.\n const datesKey = JSON.stringify(readObservabilityListDates(searchParams, defaultDatePreset));\n const filtersKey = JSON.stringify(readObservabilityListFilters(searchParams));\n const { datePreset, dateFrom, dateTo } = useMemo(\n () => readObservabilityListDates(searchParams, defaultDatePreset),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only re-read when the date params change\n [datesKey],\n );\n const { tokens, groups } = useMemo(\n () => readObservabilityListFilters(searchParams),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only re-read when the filter params change\n [filtersKey],\n );\n const urlSort = readObservabilityListSort<F | 'startedAt'>(\n searchParams,\n sortFields ?? OBSERVABILITY_LIST_SORT_FIELDS,\n );\n const sort = useMemo<ObservabilityListSort<F | 'startedAt'>>(\n () => ({ field: urlSort.field, direction: urlSort.direction }),\n [urlSort.field, urlSort.direction],\n );\n\n const fromMs = dateFrom?.getTime();\n const toMs = dateTo?.getTime();\n // Rolling presets are resolved against \"now\" only when the range changes, so the query key\n // (and the cursors issued for it) stays stable while the list scrolls. Both ends share one `now`\n // so a rolling preset spans exactly its length.\n const timeRange = useMemo(() => {\n const now = new Date();\n const window = resolveTracesDateWindow(\n datePreset,\n fromMs === undefined ? undefined : new Date(fromMs),\n toMs === undefined ? undefined : new Date(toMs),\n now,\n );\n return resolveTraceQueryTimeRange(window.dateFrom, window.dateTo, now);\n }, [datePreset, fromMs, toMs]);\n\n // react-router resolves even a functional update against the params of the last render, so writes\n // made in the same tick (zoom sets `custom` then the range; the picker reports the range after a\n // preset change) build on the pending params instead, like `useState` updaters would.\n const pending = useRef<URLSearchParams | null>(null);\n useLayoutEffect(() => {\n pending.current = null;\n }, [searchParams]);\n const update = (write: (next: URLSearchParams) => void) => {\n const base = pending.current ?? searchParams;\n const next = new URLSearchParams(base);\n write(next);\n if (next.toString() === base.toString()) return;\n pending.current = next;\n setSearchParams(next, { replace: true });\n };\n const updateDates = (change: (current: ObservabilityListDates) => ObservabilityListDates) =>\n update(next =>\n writeObservabilityListDates(next, change(readObservabilityListDates(next, defaultDatePreset)), defaultDatePreset),\n );\n\n // Not URL state: a shared or reloaded link has no zoom to undo.\n const zoomMemory = useRef<ZoomMemory | undefined>(undefined);\n // A range picked by hand drops the zoom memory, even one that matches the zoomed bounds.\n const pickDates = (change: (current: ObservabilityListDates) => ObservabilityListDates) => {\n zoomMemory.current = undefined;\n updateDates(change);\n };\n\n // Switching to `custom` keeps the current dates so the picker opens on them; any other preset drops them.\n const onDatePresetChange = (preset: TraceDatePreset) =>\n pickDates(current => (preset === 'custom' ? { ...current, datePreset: preset } : { datePreset: preset }));\n // The picker can report a date right after switching away from `custom`; those are ignored.\n const onDateChange = (date: Date | undefined, end: 'from' | 'to') =>\n pickDates(current => {\n if (current.datePreset !== 'custom') return current;\n return end === 'from' ? { ...current, dateFrom: date } : { ...current, dateTo: date };\n });\n const onDateRangeChange = (from: Date | undefined, to: Date | undefined) =>\n pickDates(current => (current.datePreset === 'custom' ? { ...current, dateFrom: from, dateTo: to } : current));\n /** Narrows the range to a histogram selection, remembering the range to return to on reset. */\n const onZoom = (from: Date, to: Date) =>\n updateDates(current => {\n zoomMemory.current = rememberZoom(zoomMemory.current, current, from, to);\n return { datePreset: 'custom', dateFrom: from, dateTo: to };\n });\n /** Undoes the last histogram zoom, or switches to `defaultPreset` when there is none to undo. */\n const onDateReset = (defaultPreset: TraceDatePreset) =>\n updateDates(current => {\n const before = rangeBeforeZoom(zoomMemory.current, current);\n zoomMemory.current = undefined;\n return before ?? { datePreset: defaultPreset };\n });\n const onFiltersChange = (nextTokens: TraceFilterToken[], nextGroups: TraceFilterGroup[]) =>\n update(next => writeObservabilityListFilters(next, { tokens: nextTokens, groups: nextGroups }));\n const setSort = (next: ObservabilityListSort<F | 'startedAt'>) =>\n update(params => writeObservabilityListSort(params, next));\n\n const contentFiltersApplied = tokens.length > 0 || groups.length > 0;\n const filtersApplied = contentFiltersApplied || datePreset !== defaultDatePreset;\n\n return {\n datePreset,\n dateFrom,\n dateTo,\n timeRange,\n /** The window ends at \"now\", so new rows can still land in it. */\n rolling: dateTo === undefined,\n tokens,\n groups,\n sort,\n setSort,\n onDatePresetChange,\n onDateChange,\n onDateRangeChange,\n onZoom,\n onDateReset,\n onFiltersChange,\n contentFiltersApplied,\n filtersApplied,\n };\n}\n"],"mappings":"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"}
@@ -43,8 +43,9 @@ function useObservabilityListFilters(url, { sortFields, defaultDatePreset = OBSE
43
43
  const fromMs = dateFrom?.getTime();
44
44
  const toMs = dateTo?.getTime();
45
45
  const timeRange = useMemo(() => {
46
- const window = resolveTracesDateWindow(datePreset, fromMs === void 0 ? void 0 : new Date(fromMs), toMs === void 0 ? void 0 : new Date(toMs));
47
- return resolveTraceQueryTimeRange(window.dateFrom, window.dateTo, /* @__PURE__ */ new Date());
46
+ const now = /* @__PURE__ */ new Date();
47
+ const window = resolveTracesDateWindow(datePreset, fromMs === void 0 ? void 0 : new Date(fromMs), toMs === void 0 ? void 0 : new Date(toMs), now);
48
+ return resolveTraceQueryTimeRange(window.dateFrom, window.dateTo, now);
48
49
  }, [
49
50
  datePreset,
50
51
  fromMs,
@@ -1 +1 @@
1
- {"version":3,"file":"use-observability-list-filters.es.js","names":[],"sources":["../../../../src/domains/observability/hooks/use-observability-list-filters.ts"],"sourcesContent":["import { useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { rangeBeforeZoom, rememberZoom } from '../lib/zoom-memory';\nimport type { ZoomMemory } from '../lib/zoom-memory';\nimport {\n OBSERVABILITY_LIST_DEFAULT_DATE_PRESET,\n OBSERVABILITY_LIST_SORT_FIELDS,\n readObservabilityListDates,\n readObservabilityListFilters,\n readObservabilityListSort,\n writeObservabilityListDates,\n writeObservabilityListFilters,\n writeObservabilityListSort,\n} from '../observability-list-url-state';\nimport type { ObservabilityListDates, ObservabilityListSort } from '../observability-list-url-state';\nimport { recoveryRefetchInterval } from '@/domains/observability/list-polling';\nimport { resolveTracesDateWindow } from '@/domains/traces/components/traces-explorer/traces-explorer-actions';\nimport { resolveTraceQueryTimeRange } from '@/domains/traces/trace-query-filters';\nimport type { TraceFilterGroup, TraceFilterToken } from '@/domains/traces/trace-query-filters';\nimport type { TraceDatePreset } from '@/domains/traces/types';\nimport type { SetURLSearchParamsLike } from '@/lib/sort/use-url-sort';\n\n/**\n * Like the traces list with delta polling: a timer or a window focus would reload every loaded page\n * and reset the cursor chain, so an observability list only reloads to recover from a transient failure.\n */\nexport const observabilityListQueryOptions = {\n refetchInterval: ({ state }: { state: { error: unknown } }) => recoveryRefetchInterval(state.error),\n refetchOnWindowFocus: false,\n};\n\nexport type ObservabilityListUrlState = {\n searchParams: URLSearchParams;\n setSearchParams: SetURLSearchParamsLike;\n};\n\n/** The search params of `url`, or of an in-memory store when the host keeps no URL state. */\nfunction useListSearchParams(url: ObservabilityListUrlState | undefined): ObservabilityListUrlState {\n const [localParams, setLocalParams] = useState(() => new URLSearchParams());\n if (url) return url;\n return {\n searchParams: localParams,\n setSearchParams: next => setLocalParams(prev => (typeof next === 'function' ? next(prev) : next)),\n };\n}\n\n/**\n * The time range, filter and sort state of a spans or threads list, kept in the host's URL (same\n * date, sort and group params as /traces) so it survives a reload and can be shared. Without `url`\n * the state lives in memory. A sort on a field outside `sortFields` reads as start time, newest first.\n * `defaultDatePreset` is the range shown when the URL names none (last 7 days unless the host differs);\n * it is left out of the URL like any default.\n */\nexport function useObservabilityListFilters<F extends string = 'startedAt'>(\n url?: ObservabilityListUrlState,\n {\n sortFields,\n defaultDatePreset = OBSERVABILITY_LIST_DEFAULT_DATE_PRESET,\n }: { sortFields?: readonly F[]; defaultDatePreset?: TraceDatePreset } = {},\n) {\n const { searchParams, setSearchParams } = useListSearchParams(url);\n\n // Decoded values keep their identity while unrelated params (e.g. the open row) change.\n const datesKey = JSON.stringify(readObservabilityListDates(searchParams, defaultDatePreset));\n const filtersKey = JSON.stringify(readObservabilityListFilters(searchParams));\n const { datePreset, dateFrom, dateTo } = useMemo(\n () => readObservabilityListDates(searchParams, defaultDatePreset),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only re-read when the date params change\n [datesKey],\n );\n const { tokens, groups } = useMemo(\n () => readObservabilityListFilters(searchParams),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only re-read when the filter params change\n [filtersKey],\n );\n const urlSort = readObservabilityListSort<F | 'startedAt'>(\n searchParams,\n sortFields ?? OBSERVABILITY_LIST_SORT_FIELDS,\n );\n const sort = useMemo<ObservabilityListSort<F | 'startedAt'>>(\n () => ({ field: urlSort.field, direction: urlSort.direction }),\n [urlSort.field, urlSort.direction],\n );\n\n const fromMs = dateFrom?.getTime();\n const toMs = dateTo?.getTime();\n // Rolling presets are resolved against \"now\" only when the range changes, so the query key\n // (and the cursors issued for it) stays stable while the list scrolls.\n const timeRange = useMemo(() => {\n const window = resolveTracesDateWindow(\n datePreset,\n fromMs === undefined ? undefined : new Date(fromMs),\n toMs === undefined ? undefined : new Date(toMs),\n );\n return resolveTraceQueryTimeRange(window.dateFrom, window.dateTo, new Date());\n }, [datePreset, fromMs, toMs]);\n\n // react-router resolves even a functional update against the params of the last render, so writes\n // made in the same tick (zoom sets `custom` then the range; the picker reports the range after a\n // preset change) build on the pending params instead, like `useState` updaters would.\n const pending = useRef<URLSearchParams | null>(null);\n useLayoutEffect(() => {\n pending.current = null;\n }, [searchParams]);\n const update = (write: (next: URLSearchParams) => void) => {\n const base = pending.current ?? searchParams;\n const next = new URLSearchParams(base);\n write(next);\n if (next.toString() === base.toString()) return;\n pending.current = next;\n setSearchParams(next, { replace: true });\n };\n const updateDates = (change: (current: ObservabilityListDates) => ObservabilityListDates) =>\n update(next =>\n writeObservabilityListDates(next, change(readObservabilityListDates(next, defaultDatePreset)), defaultDatePreset),\n );\n\n // Not URL state: a shared or reloaded link has no zoom to undo.\n const zoomMemory = useRef<ZoomMemory | undefined>(undefined);\n // A range picked by hand drops the zoom memory, even one that matches the zoomed bounds.\n const pickDates = (change: (current: ObservabilityListDates) => ObservabilityListDates) => {\n zoomMemory.current = undefined;\n updateDates(change);\n };\n\n // Switching to `custom` keeps the current dates so the picker opens on them; any other preset drops them.\n const onDatePresetChange = (preset: TraceDatePreset) =>\n pickDates(current => (preset === 'custom' ? { ...current, datePreset: preset } : { datePreset: preset }));\n // The picker can report a date right after switching away from `custom`; those are ignored.\n const onDateChange = (date: Date | undefined, end: 'from' | 'to') =>\n pickDates(current => {\n if (current.datePreset !== 'custom') return current;\n return end === 'from' ? { ...current, dateFrom: date } : { ...current, dateTo: date };\n });\n const onDateRangeChange = (from: Date | undefined, to: Date | undefined) =>\n pickDates(current => (current.datePreset === 'custom' ? { ...current, dateFrom: from, dateTo: to } : current));\n /** Narrows the range to a histogram selection, remembering the range to return to on reset. */\n const onZoom = (from: Date, to: Date) =>\n updateDates(current => {\n zoomMemory.current = rememberZoom(zoomMemory.current, current, from, to);\n return { datePreset: 'custom', dateFrom: from, dateTo: to };\n });\n /** Undoes the last histogram zoom, or switches to `defaultPreset` when there is none to undo. */\n const onDateReset = (defaultPreset: TraceDatePreset) =>\n updateDates(current => {\n const before = rangeBeforeZoom(zoomMemory.current, current);\n zoomMemory.current = undefined;\n return before ?? { datePreset: defaultPreset };\n });\n const onFiltersChange = (nextTokens: TraceFilterToken[], nextGroups: TraceFilterGroup[]) =>\n update(next => writeObservabilityListFilters(next, { tokens: nextTokens, groups: nextGroups }));\n const setSort = (next: ObservabilityListSort<F | 'startedAt'>) =>\n update(params => writeObservabilityListSort(params, next));\n\n const contentFiltersApplied = tokens.length > 0 || groups.length > 0;\n const filtersApplied = contentFiltersApplied || datePreset !== defaultDatePreset;\n\n return {\n datePreset,\n dateFrom,\n dateTo,\n timeRange,\n /** The window ends at \"now\", so new rows can still land in it. */\n rolling: dateTo === undefined,\n tokens,\n groups,\n sort,\n setSort,\n onDatePresetChange,\n onDateChange,\n onDateRangeChange,\n onZoom,\n onDateReset,\n onFiltersChange,\n contentFiltersApplied,\n filtersApplied,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-observability-list-filters.es.js","names":[],"sources":["../../../../src/domains/observability/hooks/use-observability-list-filters.ts"],"sourcesContent":["import { useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { rangeBeforeZoom, rememberZoom } from '../lib/zoom-memory';\nimport type { ZoomMemory } from '../lib/zoom-memory';\nimport {\n OBSERVABILITY_LIST_DEFAULT_DATE_PRESET,\n OBSERVABILITY_LIST_SORT_FIELDS,\n readObservabilityListDates,\n readObservabilityListFilters,\n readObservabilityListSort,\n writeObservabilityListDates,\n writeObservabilityListFilters,\n writeObservabilityListSort,\n} from '../observability-list-url-state';\nimport type { ObservabilityListDates, ObservabilityListSort } from '../observability-list-url-state';\nimport { recoveryRefetchInterval } from '@/domains/observability/list-polling';\nimport { resolveTracesDateWindow } from '@/domains/traces/components/traces-explorer/traces-explorer-actions';\nimport { resolveTraceQueryTimeRange } from '@/domains/traces/trace-query-filters';\nimport type { TraceFilterGroup, TraceFilterToken } from '@/domains/traces/trace-query-filters';\nimport type { TraceDatePreset } from '@/domains/traces/types';\nimport type { SetURLSearchParamsLike } from '@/lib/sort/use-url-sort';\n\n/**\n * Like the traces list with delta polling: a timer or a window focus would reload every loaded page\n * and reset the cursor chain, so an observability list only reloads to recover from a transient failure.\n */\nexport const observabilityListQueryOptions = {\n refetchInterval: ({ state }: { state: { error: unknown } }) => recoveryRefetchInterval(state.error),\n refetchOnWindowFocus: false,\n};\n\nexport type ObservabilityListUrlState = {\n searchParams: URLSearchParams;\n setSearchParams: SetURLSearchParamsLike;\n};\n\n/** The search params of `url`, or of an in-memory store when the host keeps no URL state. */\nfunction useListSearchParams(url: ObservabilityListUrlState | undefined): ObservabilityListUrlState {\n const [localParams, setLocalParams] = useState(() => new URLSearchParams());\n if (url) return url;\n return {\n searchParams: localParams,\n setSearchParams: next => setLocalParams(prev => (typeof next === 'function' ? next(prev) : next)),\n };\n}\n\n/**\n * The time range, filter and sort state of a spans or threads list, kept in the host's URL (same\n * date, sort and group params as /traces) so it survives a reload and can be shared. Without `url`\n * the state lives in memory. A sort on a field outside `sortFields` reads as start time, newest first.\n * `defaultDatePreset` is the range shown when the URL names none (last 7 days unless the host differs);\n * it is left out of the URL like any default.\n */\nexport function useObservabilityListFilters<F extends string = 'startedAt'>(\n url?: ObservabilityListUrlState,\n {\n sortFields,\n defaultDatePreset = OBSERVABILITY_LIST_DEFAULT_DATE_PRESET,\n }: { sortFields?: readonly F[]; defaultDatePreset?: TraceDatePreset } = {},\n) {\n const { searchParams, setSearchParams } = useListSearchParams(url);\n\n // Decoded values keep their identity while unrelated params (e.g. the open row) change.\n const datesKey = JSON.stringify(readObservabilityListDates(searchParams, defaultDatePreset));\n const filtersKey = JSON.stringify(readObservabilityListFilters(searchParams));\n const { datePreset, dateFrom, dateTo } = useMemo(\n () => readObservabilityListDates(searchParams, defaultDatePreset),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only re-read when the date params change\n [datesKey],\n );\n const { tokens, groups } = useMemo(\n () => readObservabilityListFilters(searchParams),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only re-read when the filter params change\n [filtersKey],\n );\n const urlSort = readObservabilityListSort<F | 'startedAt'>(\n searchParams,\n sortFields ?? OBSERVABILITY_LIST_SORT_FIELDS,\n );\n const sort = useMemo<ObservabilityListSort<F | 'startedAt'>>(\n () => ({ field: urlSort.field, direction: urlSort.direction }),\n [urlSort.field, urlSort.direction],\n );\n\n const fromMs = dateFrom?.getTime();\n const toMs = dateTo?.getTime();\n // Rolling presets are resolved against \"now\" only when the range changes, so the query key\n // (and the cursors issued for it) stays stable while the list scrolls. Both ends share one `now`\n // so a rolling preset spans exactly its length.\n const timeRange = useMemo(() => {\n const now = new Date();\n const window = resolveTracesDateWindow(\n datePreset,\n fromMs === undefined ? undefined : new Date(fromMs),\n toMs === undefined ? undefined : new Date(toMs),\n now,\n );\n return resolveTraceQueryTimeRange(window.dateFrom, window.dateTo, now);\n }, [datePreset, fromMs, toMs]);\n\n // react-router resolves even a functional update against the params of the last render, so writes\n // made in the same tick (zoom sets `custom` then the range; the picker reports the range after a\n // preset change) build on the pending params instead, like `useState` updaters would.\n const pending = useRef<URLSearchParams | null>(null);\n useLayoutEffect(() => {\n pending.current = null;\n }, [searchParams]);\n const update = (write: (next: URLSearchParams) => void) => {\n const base = pending.current ?? searchParams;\n const next = new URLSearchParams(base);\n write(next);\n if (next.toString() === base.toString()) return;\n pending.current = next;\n setSearchParams(next, { replace: true });\n };\n const updateDates = (change: (current: ObservabilityListDates) => ObservabilityListDates) =>\n update(next =>\n writeObservabilityListDates(next, change(readObservabilityListDates(next, defaultDatePreset)), defaultDatePreset),\n );\n\n // Not URL state: a shared or reloaded link has no zoom to undo.\n const zoomMemory = useRef<ZoomMemory | undefined>(undefined);\n // A range picked by hand drops the zoom memory, even one that matches the zoomed bounds.\n const pickDates = (change: (current: ObservabilityListDates) => ObservabilityListDates) => {\n zoomMemory.current = undefined;\n updateDates(change);\n };\n\n // Switching to `custom` keeps the current dates so the picker opens on them; any other preset drops them.\n const onDatePresetChange = (preset: TraceDatePreset) =>\n pickDates(current => (preset === 'custom' ? { ...current, datePreset: preset } : { datePreset: preset }));\n // The picker can report a date right after switching away from `custom`; those are ignored.\n const onDateChange = (date: Date | undefined, end: 'from' | 'to') =>\n pickDates(current => {\n if (current.datePreset !== 'custom') return current;\n return end === 'from' ? { ...current, dateFrom: date } : { ...current, dateTo: date };\n });\n const onDateRangeChange = (from: Date | undefined, to: Date | undefined) =>\n pickDates(current => (current.datePreset === 'custom' ? { ...current, dateFrom: from, dateTo: to } : current));\n /** Narrows the range to a histogram selection, remembering the range to return to on reset. */\n const onZoom = (from: Date, to: Date) =>\n updateDates(current => {\n zoomMemory.current = rememberZoom(zoomMemory.current, current, from, to);\n return { datePreset: 'custom', dateFrom: from, dateTo: to };\n });\n /** Undoes the last histogram zoom, or switches to `defaultPreset` when there is none to undo. */\n const onDateReset = (defaultPreset: TraceDatePreset) =>\n updateDates(current => {\n const before = rangeBeforeZoom(zoomMemory.current, current);\n zoomMemory.current = undefined;\n return before ?? { datePreset: defaultPreset };\n });\n const onFiltersChange = (nextTokens: TraceFilterToken[], nextGroups: TraceFilterGroup[]) =>\n update(next => writeObservabilityListFilters(next, { tokens: nextTokens, groups: nextGroups }));\n const setSort = (next: ObservabilityListSort<F | 'startedAt'>) =>\n update(params => writeObservabilityListSort(params, next));\n\n const contentFiltersApplied = tokens.length > 0 || groups.length > 0;\n const filtersApplied = contentFiltersApplied || datePreset !== defaultDatePreset;\n\n return {\n datePreset,\n dateFrom,\n dateTo,\n timeRange,\n /** The window ends at \"now\", so new rows can still land in it. */\n rolling: dateTo === undefined,\n tokens,\n groups,\n sort,\n setSort,\n onDatePresetChange,\n onDateChange,\n onDateRangeChange,\n onZoom,\n onDateReset,\n onFiltersChange,\n contentFiltersApplied,\n filtersApplied,\n };\n}\n"],"mappings":"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"}
@@ -159,14 +159,14 @@ var buildTracesLegacyFilters = ({ filters, dateFrom, dateTo }) => require_trace_
159
159
  tokens: filters.tokens
160
160
  });
161
161
  /** Rolling presets start `PRESET_MS` before now and stay open-ended; `all` is open on both ends. */
162
- var resolveTracesDateWindow = (datePreset, dateFrom, dateTo) => {
162
+ var resolveTracesDateWindow = (datePreset, dateFrom, dateTo, now = /* @__PURE__ */ new Date()) => {
163
163
  if (datePreset === "custom") return {
164
164
  dateFrom,
165
165
  dateTo
166
166
  };
167
167
  const ms = PRESET_MS[datePreset];
168
168
  return {
169
- dateFrom: ms ? new Date(Date.now() - ms) : void 0,
169
+ dateFrom: ms ? new Date(now.getTime() - ms) : void 0,
170
170
  dateTo: void 0
171
171
  };
172
172
  };
@@ -1 +1 @@
1
- {"version":3,"file":"traces-explorer-actions.cjs.js","names":["TRACE_QUERY_UNSUPPORTED_FILTER_FIELDS","traceQueryUnqueryableFieldIds","ROOT_ENTITY_TYPE_OPTIONS","TRACE_STATUS_VALUES","buildTraceQueryRequest","buildTraceListFilters"],"sources":["../../../../../src/domains/traces/components/traces-explorer/traces-explorer-actions.ts"],"sourcesContent":["import {\n buildTraceListFilters,\n ROOT_ENTITY_TYPE_OPTIONS,\n TRACE_STATUS_VALUES,\n traceQueryUnqueryableFieldIds,\n} from '../../trace-filters';\nimport type {\n EntityOptions,\n TraceFilterGroup,\n TraceFilterToken,\n TraceQueryFieldSupport,\n TraceStatusFilter,\n} from '../../trace-filters';\nimport { buildTraceQueryRequest, TRACE_QUERY_UNSUPPORTED_FILTER_FIELDS } from '../../trace-query-filters';\nimport type { SpanTab, TraceDatePreset } from '../../types';\nimport type { TraceSpanView } from '../trace-data-panel-view';\n\nexport type TracesSelection = {\n traceId?: string;\n spanId?: string;\n spanTab?: SpanTab;\n spanView: TraceSpanView;\n scoreId?: string;\n highlightSpanIds: string[];\n};\n\n/** `rootEntityType` and `status` are tokens too (`fieldId: 'rootEntityType' | 'status'`), like every other filter. */\nexport type TracesFilters = {\n datePreset: TraceDatePreset;\n /** Only read when `datePreset` is `custom`. */\n dateFrom?: Date;\n /** Only read when `datePreset` is `custom`. */\n dateTo?: Date;\n tokens: TraceFilterToken[];\n groups: TraceFilterGroup[];\n};\n\nexport type TracesSortDirection = 'asc' | 'desc';\n\n/** Fields the traces list can be sorted by, named like the trace query's `orderBy` fields. */\nexport const TRACES_SORT_FIELDS = ['startedAt', 'timeToFirstChunkMs', 'timeToFirstTokenMs'] as const;\nexport type TracesSortField = (typeof TRACES_SORT_FIELDS)[number];\n\nexport type TracesSort = { field: TracesSortField; direction: TracesSortDirection };\n\nexport const DEFAULT_TRACES_SORT: TracesSort = { field: 'startedAt', direction: 'desc' };\n\n/** What the explorer emits on every change: filters and selection move together (a filter edit clears the selection). */\nexport type TracesExplorerState = { selection: TracesSelection; filters: TracesFilters };\n\nexport const EMPTY_TRACES_SELECTION: TracesSelection = { spanView: 'tree', highlightSpanIds: [] };\n\nexport const DEFAULT_TRACES_FILTERS: TracesFilters = { datePreset: 'last-7d', tokens: [], groups: [] };\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\nconst PRESET_MS: Partial<Record<TraceDatePreset, number>> = {\n 'last-24h': DAY_MS,\n 'last-3d': 3 * DAY_MS,\n 'last-7d': 7 * DAY_MS,\n 'last-14d': 14 * DAY_MS,\n 'last-30d': 30 * DAY_MS,\n};\n\nexport const isSelectionEmpty = (selection: TracesSelection) =>\n !selection.traceId &&\n !selection.spanId &&\n !selection.spanTab &&\n !selection.scoreId &&\n selection.highlightSpanIds.length === 0;\n\n/** Keeps the span view: it is a display preference, not part of what is selected. */\nexport const clearSelection = (selection: TracesSelection): TracesSelection => ({\n spanView: selection.spanView,\n highlightSpanIds: [],\n});\n\nexport const selectTrace = (selection: TracesSelection, traceId: string | null): TracesSelection =>\n traceId ? { traceId, spanView: selection.spanView, highlightSpanIds: [] } : clearSelection(selection);\n\n/**\n * The open tab stays, so stepping through spans compares the same tab; the score belongs to the\n * previous span and is dropped with it.\n */\nexport const selectSpan = (selection: TracesSelection, spanId: string | null): TracesSelection => {\n if ((spanId ?? undefined) === selection.spanId) return selection;\n return { ...selection, spanId: spanId ?? undefined, scoreId: undefined };\n};\n\nexport const setSpanTab = (selection: TracesSelection, tab: SpanTab): TracesSelection => {\n if (tab === selection.spanTab) return selection;\n return { ...selection, spanTab: tab === 'details' ? undefined : tab, scoreId: undefined };\n};\n\nexport const setSpanView = (selection: TracesSelection, spanView: TraceSpanView): TracesSelection =>\n spanView === selection.spanView ? selection : { ...selection, spanView };\n\nexport const selectScore = (selection: TracesSelection, scoreId: string | null): TracesSelection =>\n (scoreId ?? undefined) === selection.scoreId ? selection : { ...selection, scoreId: scoreId ?? undefined };\n\nexport const highlightSpans = (selection: TracesSelection, spanIds: string[]): TracesSelection => {\n const unchanged =\n spanIds.length === selection.highlightSpanIds.length &&\n spanIds.every((id, index) => id === selection.highlightSpanIds[index]);\n return unchanged ? selection : { ...selection, highlightSpanIds: spanIds };\n};\n\nexport const applyFilterTokens = (\n filters: TracesFilters,\n tokens: TraceFilterToken[],\n groups: TraceFilterGroup[],\n): TracesFilters => ({ ...filters, tokens, groups });\n\n/** Switching to `custom` keeps the current dates so the picker opens on them; any other preset drops them. */\nexport const applyDatePreset = (filters: TracesFilters, datePreset: TraceDatePreset): TracesFilters =>\n datePreset === 'custom' ? { ...filters, datePreset } : { datePreset, tokens: filters.tokens, groups: filters.groups };\n\n// The picker can report a date right after switching away from `custom`; those are ignored.\nexport const applyDate = (filters: TracesFilters, date: Date | undefined, end: 'from' | 'to'): TracesFilters => {\n if (filters.datePreset !== 'custom') return filters;\n return end === 'from' ? { ...filters, dateFrom: date } : { ...filters, dateTo: date };\n};\n\nexport const applyDateRange = (\n filters: TracesFilters,\n dateFrom: Date | undefined,\n dateTo: Date | undefined,\n): TracesFilters => (filters.datePreset === 'custom' ? { ...filters, dateFrom, dateTo } : filters);\n\nconst isQueryableToken = (token: TraceFilterToken, unqueryableFieldIds: ReadonlySet<string>) => {\n if (token.fieldId === 'status' && token.value === 'running') return false;\n if (TRACE_QUERY_UNSUPPORTED_FILTER_FIELDS.has(token.fieldId)) return false;\n return !unqueryableFieldIds.has(token.fieldId);\n};\n\n/**\n * Drops the top-level tokens the trace query can't run, so no chip advertises a filter with no effect.\n * Groups pass through and stay visible in the bar: `buildTracesQueryRequest` leaves their unqueryable\n * conditions out of the query. Returns the same object when nothing is dropped.\n */\nexport const sanitizeTracesFilters = (filters: TracesFilters, support: TraceQueryFieldSupport): TracesFilters => {\n const unqueryableFieldIds = traceQueryUnqueryableFieldIds(support);\n const tokens = filters.tokens.filter(token => isQueryableToken(token, unqueryableFieldIds));\n return tokens.length === filters.tokens.length ? filters : { ...filters, tokens };\n};\n\nconst selectsRunning = (node: TraceFilterGroup | TraceFilterToken): boolean => {\n if ('nodes' in node) return node.nodes.some(selectsRunning);\n if (node.fieldId !== 'status') return false;\n return Array.isArray(node.value) ? node.value.includes('running') : node.value === 'running';\n};\n\n/** Whether a status filter asks for `running`, which the trace query can't express and drops. */\nexport const selectsRunningStatus = (filters: TracesFilters): boolean =>\n filters.tokens.some(selectsRunning) || filters.groups.some(selectsRunning);\n\nconst tokenValue = (tokens: TraceFilterToken[], fieldId: string) => {\n const value = tokens.find(token => token.fieldId === fieldId)?.value;\n return typeof value === 'string' ? value : undefined;\n};\n\nexport const getSelectedEntityOption = (tokens: TraceFilterToken[]): EntityOptions | undefined => {\n const value = tokenValue(tokens, 'rootEntityType');\n return ROOT_ENTITY_TYPE_OPTIONS.find(option => option.entityType === value);\n};\n\nexport const getSelectedStatus = (tokens: TraceFilterToken[]): TraceStatusFilter | undefined => {\n const value = tokenValue(tokens, 'status');\n return value && TRACE_STATUS_VALUES.has(value as TraceStatusFilter) ? (value as TraceStatusFilter) : undefined;\n};\n\ntype TracesQueryWindow = { filters: TracesFilters; dateFrom?: Date; dateTo?: Date };\n\n/** The trace query for the (sanitized) filters and the resolved date window. */\nexport const buildTracesQueryRequest = ({\n filters,\n dateFrom,\n dateTo,\n now,\n ...support\n}: TracesQueryWindow & TraceQueryFieldSupport & { now: Date }) =>\n buildTraceQueryRequest({\n rootEntityType: getSelectedEntityOption(filters.tokens)?.entityType,\n status: getSelectedStatus(filters.tokens),\n dateFrom,\n dateTo,\n tokens: filters.tokens,\n groups: filters.groups,\n excludedFieldIds: traceQueryUnqueryableFieldIds(support),\n now,\n });\n\n/** The `listTracesLight` filters for servers without the trace query API (no groups there). */\nexport const buildTracesLegacyFilters = ({ filters, dateFrom, dateTo }: TracesQueryWindow) =>\n buildTraceListFilters({\n rootEntityType: getSelectedEntityOption(filters.tokens)?.entityType,\n status: getSelectedStatus(filters.tokens),\n dateFrom,\n dateTo,\n tokens: filters.tokens,\n });\n\n/** Rolling presets start `PRESET_MS` before now and stay open-ended; `all` is open on both ends. */\nexport const resolveTracesDateWindow = (\n datePreset: TraceDatePreset,\n dateFrom: Date | undefined,\n dateTo: Date | undefined,\n): { dateFrom?: Date; dateTo?: Date } => {\n if (datePreset === 'custom') return { dateFrom, dateTo };\n const ms = PRESET_MS[datePreset];\n return { dateFrom: ms ? new Date(Date.now() - ms) : undefined, dateTo: undefined };\n};\n"],"mappings":";;;;AAwCA,IAAa,qBAAqB;CAAC;CAAa;CAAsB;AAAoB;AAK1F,IAAa,sBAAkC;CAAE,OAAO;CAAa,WAAW;AAAO;AAKvF,IAAa,yBAA0C;CAAE,UAAU;CAAQ,kBAAkB,CAAC;AAAE;AAEhG,IAAa,yBAAwC;CAAE,YAAY;CAAW,QAAQ,CAAC;CAAG,QAAQ,CAAC;AAAE;AAErG,IAAM,SAAS;AACf,IAAM,YAAsD;CAC1D,YAAY;CACZ,WAAW,IAAI;CACf,WAAW,IAAI;CACf,YAAY,KAAK;CACjB,YAAY,KAAK;AACnB;AAEA,IAAa,oBAAoB,cAC/B,CAAC,UAAU,WACX,CAAC,UAAU,UACX,CAAC,UAAU,WACX,CAAC,UAAU,WACX,UAAU,iBAAiB,WAAW;;AAGxC,IAAa,kBAAkB,eAAiD;CAC9E,UAAU,UAAU;CACpB,kBAAkB,CAAC;AACrB;AAEA,IAAa,eAAe,WAA4B,YACtD,UAAU;CAAE;CAAS,UAAU,UAAU;CAAU,kBAAkB,CAAC;AAAE,IAAI,eAAe,SAAS;;;;;AAMtG,IAAa,cAAc,WAA4B,WAA2C;CAChG,KAAK,UAAU,KAAA,OAAe,UAAU,QAAQ,OAAO;CACvD,OAAO;EAAE,GAAG;EAAW,QAAQ,UAAU,KAAA;EAAW,SAAS,KAAA;CAAU;AACzE;AAEA,IAAa,cAAc,WAA4B,QAAkC;CACvF,IAAI,QAAQ,UAAU,SAAS,OAAO;CACtC,OAAO;EAAE,GAAG;EAAW,SAAS,QAAQ,YAAY,KAAA,IAAY;EAAK,SAAS,KAAA;CAAU;AAC1F;AAEA,IAAa,eAAe,WAA4B,aACtD,aAAa,UAAU,WAAW,YAAY;CAAE,GAAG;CAAW;AAAS;AAEzE,IAAa,eAAe,WAA4B,aACrD,WAAW,KAAA,OAAe,UAAU,UAAU,YAAY;CAAE,GAAG;CAAW,SAAS,WAAW,KAAA;AAAU;AAE3G,IAAa,kBAAkB,WAA4B,YAAuC;CAIhG,OAFE,QAAQ,WAAW,UAAU,iBAAiB,UAC9C,QAAQ,OAAO,IAAI,UAAU,OAAO,UAAU,iBAAiB,MAAM,IACpD,YAAY;EAAE,GAAG;EAAW,kBAAkB;CAAQ;AAC3E;AAEA,IAAa,qBACX,SACA,QACA,YACmB;CAAE,GAAG;CAAS;CAAQ;AAAO;;AAGlD,IAAa,mBAAmB,SAAwB,eACtD,eAAe,WAAW;CAAE,GAAG;CAAS;AAAW,IAAI;CAAE;CAAY,QAAQ,QAAQ;CAAQ,QAAQ,QAAQ;AAAO;AAGtH,IAAa,aAAa,SAAwB,MAAwB,QAAsC;CAC9G,IAAI,QAAQ,eAAe,UAAU,OAAO;CAC5C,OAAO,QAAQ,SAAS;EAAE,GAAG;EAAS,UAAU;CAAK,IAAI;EAAE,GAAG;EAAS,QAAQ;CAAK;AACtF;AAEA,IAAa,kBACX,SACA,UACA,WACmB,QAAQ,eAAe,WAAW;CAAE,GAAG;CAAS;CAAU;AAAO,IAAI;AAE1F,IAAM,oBAAoB,OAAyB,wBAA6C;CAC9F,IAAI,MAAM,YAAY,YAAY,MAAM,UAAU,WAAW,OAAO;CACpE,IAAIA,sBAAAA,sCAAsC,IAAI,MAAM,OAAO,GAAG,OAAO;CACrE,OAAO,CAAC,oBAAoB,IAAI,MAAM,OAAO;AAC/C;;;;;;AAOA,IAAa,yBAAyB,SAAwB,YAAmD;CAC/G,MAAM,sBAAsBC,sBAAAA,8BAA8B,OAAO;CACjE,MAAM,SAAS,QAAQ,OAAO,QAAO,UAAS,iBAAiB,OAAO,mBAAmB,CAAC;CAC1F,OAAO,OAAO,WAAW,QAAQ,OAAO,SAAS,UAAU;EAAE,GAAG;EAAS;CAAO;AAClF;AAEA,IAAM,kBAAkB,SAAuD;CAC7E,IAAI,WAAW,MAAM,OAAO,KAAK,MAAM,KAAK,cAAc;CAC1D,IAAI,KAAK,YAAY,UAAU,OAAO;CACtC,OAAO,MAAM,QAAQ,KAAK,KAAK,IAAI,KAAK,MAAM,SAAS,SAAS,IAAI,KAAK,UAAU;AACrF;;AAGA,IAAa,wBAAwB,YACnC,QAAQ,OAAO,KAAK,cAAc,KAAK,QAAQ,OAAO,KAAK,cAAc;AAE3E,IAAM,cAAc,QAA4B,YAAoB;CAClE,MAAM,QAAQ,OAAO,MAAK,UAAS,MAAM,YAAY,OAAO,CAAC,EAAE;CAC/D,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;AAC7C;AAEA,IAAa,2BAA2B,WAA0D;CAChG,MAAM,QAAQ,WAAW,QAAQ,gBAAgB;CACjD,OAAOC,sBAAAA,yBAAyB,MAAK,WAAU,OAAO,eAAe,KAAK;AAC5E;AAEA,IAAa,qBAAqB,WAA8D;CAC9F,MAAM,QAAQ,WAAW,QAAQ,QAAQ;CACzC,OAAO,SAASC,sBAAAA,oBAAoB,IAAI,KAA0B,IAAK,QAA8B,KAAA;AACvG;;AAKA,IAAa,2BAA2B,EACtC,SACA,UACA,QACA,KACA,GAAG,cAEHC,sBAAAA,uBAAuB;CACrB,gBAAgB,wBAAwB,QAAQ,MAAM,CAAC,EAAE;CACzD,QAAQ,kBAAkB,QAAQ,MAAM;CACxC;CACA;CACA,QAAQ,QAAQ;CAChB,QAAQ,QAAQ;CAChB,kBAAkBH,sBAAAA,8BAA8B,OAAO;CACvD;AACF,CAAC;;AAGH,IAAa,4BAA4B,EAAE,SAAS,UAAU,aAC5DI,sBAAAA,sBAAsB;CACpB,gBAAgB,wBAAwB,QAAQ,MAAM,CAAC,EAAE;CACzD,QAAQ,kBAAkB,QAAQ,MAAM;CACxC;CACA;CACA,QAAQ,QAAQ;AAClB,CAAC;;AAGH,IAAa,2BACX,YACA,UACA,WACuC;CACvC,IAAI,eAAe,UAAU,OAAO;EAAE;EAAU;CAAO;CACvD,MAAM,KAAK,UAAU;CACrB,OAAO;EAAE,UAAU,KAAK,IAAI,KAAK,KAAK,IAAI,IAAI,EAAE,IAAI,KAAA;EAAW,QAAQ,KAAA;CAAU;AACnF"}
1
+ {"version":3,"file":"traces-explorer-actions.cjs.js","names":["TRACE_QUERY_UNSUPPORTED_FILTER_FIELDS","traceQueryUnqueryableFieldIds","ROOT_ENTITY_TYPE_OPTIONS","TRACE_STATUS_VALUES","buildTraceQueryRequest","buildTraceListFilters"],"sources":["../../../../../src/domains/traces/components/traces-explorer/traces-explorer-actions.ts"],"sourcesContent":["import {\n buildTraceListFilters,\n ROOT_ENTITY_TYPE_OPTIONS,\n TRACE_STATUS_VALUES,\n traceQueryUnqueryableFieldIds,\n} from '../../trace-filters';\nimport type {\n EntityOptions,\n TraceFilterGroup,\n TraceFilterToken,\n TraceQueryFieldSupport,\n TraceStatusFilter,\n} from '../../trace-filters';\nimport { buildTraceQueryRequest, TRACE_QUERY_UNSUPPORTED_FILTER_FIELDS } from '../../trace-query-filters';\nimport type { SpanTab, TraceDatePreset } from '../../types';\nimport type { TraceSpanView } from '../trace-data-panel-view';\n\nexport type TracesSelection = {\n traceId?: string;\n spanId?: string;\n spanTab?: SpanTab;\n spanView: TraceSpanView;\n scoreId?: string;\n highlightSpanIds: string[];\n};\n\n/** `rootEntityType` and `status` are tokens too (`fieldId: 'rootEntityType' | 'status'`), like every other filter. */\nexport type TracesFilters = {\n datePreset: TraceDatePreset;\n /** Only read when `datePreset` is `custom`. */\n dateFrom?: Date;\n /** Only read when `datePreset` is `custom`. */\n dateTo?: Date;\n tokens: TraceFilterToken[];\n groups: TraceFilterGroup[];\n};\n\nexport type TracesSortDirection = 'asc' | 'desc';\n\n/** Fields the traces list can be sorted by, named like the trace query's `orderBy` fields. */\nexport const TRACES_SORT_FIELDS = ['startedAt', 'timeToFirstChunkMs', 'timeToFirstTokenMs'] as const;\nexport type TracesSortField = (typeof TRACES_SORT_FIELDS)[number];\n\nexport type TracesSort = { field: TracesSortField; direction: TracesSortDirection };\n\nexport const DEFAULT_TRACES_SORT: TracesSort = { field: 'startedAt', direction: 'desc' };\n\n/** What the explorer emits on every change: filters and selection move together (a filter edit clears the selection). */\nexport type TracesExplorerState = { selection: TracesSelection; filters: TracesFilters };\n\nexport const EMPTY_TRACES_SELECTION: TracesSelection = { spanView: 'tree', highlightSpanIds: [] };\n\nexport const DEFAULT_TRACES_FILTERS: TracesFilters = { datePreset: 'last-7d', tokens: [], groups: [] };\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\nconst PRESET_MS: Partial<Record<TraceDatePreset, number>> = {\n 'last-24h': DAY_MS,\n 'last-3d': 3 * DAY_MS,\n 'last-7d': 7 * DAY_MS,\n 'last-14d': 14 * DAY_MS,\n 'last-30d': 30 * DAY_MS,\n};\n\nexport const isSelectionEmpty = (selection: TracesSelection) =>\n !selection.traceId &&\n !selection.spanId &&\n !selection.spanTab &&\n !selection.scoreId &&\n selection.highlightSpanIds.length === 0;\n\n/** Keeps the span view: it is a display preference, not part of what is selected. */\nexport const clearSelection = (selection: TracesSelection): TracesSelection => ({\n spanView: selection.spanView,\n highlightSpanIds: [],\n});\n\nexport const selectTrace = (selection: TracesSelection, traceId: string | null): TracesSelection =>\n traceId ? { traceId, spanView: selection.spanView, highlightSpanIds: [] } : clearSelection(selection);\n\n/**\n * The open tab stays, so stepping through spans compares the same tab; the score belongs to the\n * previous span and is dropped with it.\n */\nexport const selectSpan = (selection: TracesSelection, spanId: string | null): TracesSelection => {\n if ((spanId ?? undefined) === selection.spanId) return selection;\n return { ...selection, spanId: spanId ?? undefined, scoreId: undefined };\n};\n\nexport const setSpanTab = (selection: TracesSelection, tab: SpanTab): TracesSelection => {\n if (tab === selection.spanTab) return selection;\n return { ...selection, spanTab: tab === 'details' ? undefined : tab, scoreId: undefined };\n};\n\nexport const setSpanView = (selection: TracesSelection, spanView: TraceSpanView): TracesSelection =>\n spanView === selection.spanView ? selection : { ...selection, spanView };\n\nexport const selectScore = (selection: TracesSelection, scoreId: string | null): TracesSelection =>\n (scoreId ?? undefined) === selection.scoreId ? selection : { ...selection, scoreId: scoreId ?? undefined };\n\nexport const highlightSpans = (selection: TracesSelection, spanIds: string[]): TracesSelection => {\n const unchanged =\n spanIds.length === selection.highlightSpanIds.length &&\n spanIds.every((id, index) => id === selection.highlightSpanIds[index]);\n return unchanged ? selection : { ...selection, highlightSpanIds: spanIds };\n};\n\nexport const applyFilterTokens = (\n filters: TracesFilters,\n tokens: TraceFilterToken[],\n groups: TraceFilterGroup[],\n): TracesFilters => ({ ...filters, tokens, groups });\n\n/** Switching to `custom` keeps the current dates so the picker opens on them; any other preset drops them. */\nexport const applyDatePreset = (filters: TracesFilters, datePreset: TraceDatePreset): TracesFilters =>\n datePreset === 'custom' ? { ...filters, datePreset } : { datePreset, tokens: filters.tokens, groups: filters.groups };\n\n// The picker can report a date right after switching away from `custom`; those are ignored.\nexport const applyDate = (filters: TracesFilters, date: Date | undefined, end: 'from' | 'to'): TracesFilters => {\n if (filters.datePreset !== 'custom') return filters;\n return end === 'from' ? { ...filters, dateFrom: date } : { ...filters, dateTo: date };\n};\n\nexport const applyDateRange = (\n filters: TracesFilters,\n dateFrom: Date | undefined,\n dateTo: Date | undefined,\n): TracesFilters => (filters.datePreset === 'custom' ? { ...filters, dateFrom, dateTo } : filters);\n\nconst isQueryableToken = (token: TraceFilterToken, unqueryableFieldIds: ReadonlySet<string>) => {\n if (token.fieldId === 'status' && token.value === 'running') return false;\n if (TRACE_QUERY_UNSUPPORTED_FILTER_FIELDS.has(token.fieldId)) return false;\n return !unqueryableFieldIds.has(token.fieldId);\n};\n\n/**\n * Drops the top-level tokens the trace query can't run, so no chip advertises a filter with no effect.\n * Groups pass through and stay visible in the bar: `buildTracesQueryRequest` leaves their unqueryable\n * conditions out of the query. Returns the same object when nothing is dropped.\n */\nexport const sanitizeTracesFilters = (filters: TracesFilters, support: TraceQueryFieldSupport): TracesFilters => {\n const unqueryableFieldIds = traceQueryUnqueryableFieldIds(support);\n const tokens = filters.tokens.filter(token => isQueryableToken(token, unqueryableFieldIds));\n return tokens.length === filters.tokens.length ? filters : { ...filters, tokens };\n};\n\nconst selectsRunning = (node: TraceFilterGroup | TraceFilterToken): boolean => {\n if ('nodes' in node) return node.nodes.some(selectsRunning);\n if (node.fieldId !== 'status') return false;\n return Array.isArray(node.value) ? node.value.includes('running') : node.value === 'running';\n};\n\n/** Whether a status filter asks for `running`, which the trace query can't express and drops. */\nexport const selectsRunningStatus = (filters: TracesFilters): boolean =>\n filters.tokens.some(selectsRunning) || filters.groups.some(selectsRunning);\n\nconst tokenValue = (tokens: TraceFilterToken[], fieldId: string) => {\n const value = tokens.find(token => token.fieldId === fieldId)?.value;\n return typeof value === 'string' ? value : undefined;\n};\n\nexport const getSelectedEntityOption = (tokens: TraceFilterToken[]): EntityOptions | undefined => {\n const value = tokenValue(tokens, 'rootEntityType');\n return ROOT_ENTITY_TYPE_OPTIONS.find(option => option.entityType === value);\n};\n\nexport const getSelectedStatus = (tokens: TraceFilterToken[]): TraceStatusFilter | undefined => {\n const value = tokenValue(tokens, 'status');\n return value && TRACE_STATUS_VALUES.has(value as TraceStatusFilter) ? (value as TraceStatusFilter) : undefined;\n};\n\ntype TracesQueryWindow = { filters: TracesFilters; dateFrom?: Date; dateTo?: Date };\n\n/** The trace query for the (sanitized) filters and the resolved date window. */\nexport const buildTracesQueryRequest = ({\n filters,\n dateFrom,\n dateTo,\n now,\n ...support\n}: TracesQueryWindow & TraceQueryFieldSupport & { now: Date }) =>\n buildTraceQueryRequest({\n rootEntityType: getSelectedEntityOption(filters.tokens)?.entityType,\n status: getSelectedStatus(filters.tokens),\n dateFrom,\n dateTo,\n tokens: filters.tokens,\n groups: filters.groups,\n excludedFieldIds: traceQueryUnqueryableFieldIds(support),\n now,\n });\n\n/** The `listTracesLight` filters for servers without the trace query API (no groups there). */\nexport const buildTracesLegacyFilters = ({ filters, dateFrom, dateTo }: TracesQueryWindow) =>\n buildTraceListFilters({\n rootEntityType: getSelectedEntityOption(filters.tokens)?.entityType,\n status: getSelectedStatus(filters.tokens),\n dateFrom,\n dateTo,\n tokens: filters.tokens,\n });\n\n/** Rolling presets start `PRESET_MS` before now and stay open-ended; `all` is open on both ends. */\nexport const resolveTracesDateWindow = (\n datePreset: TraceDatePreset,\n dateFrom: Date | undefined,\n dateTo: Date | undefined,\n now: Date = new Date(),\n): { dateFrom?: Date; dateTo?: Date } => {\n if (datePreset === 'custom') return { dateFrom, dateTo };\n const ms = PRESET_MS[datePreset];\n return { dateFrom: ms ? new Date(now.getTime() - ms) : undefined, dateTo: undefined };\n};\n"],"mappings":"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"}
@@ -158,14 +158,14 @@ var buildTracesLegacyFilters = ({ filters, dateFrom, dateTo }) => buildTraceList
158
158
  tokens: filters.tokens
159
159
  });
160
160
  /** Rolling presets start `PRESET_MS` before now and stay open-ended; `all` is open on both ends. */
161
- var resolveTracesDateWindow = (datePreset, dateFrom, dateTo) => {
161
+ var resolveTracesDateWindow = (datePreset, dateFrom, dateTo, now = /* @__PURE__ */ new Date()) => {
162
162
  if (datePreset === "custom") return {
163
163
  dateFrom,
164
164
  dateTo
165
165
  };
166
166
  const ms = PRESET_MS[datePreset];
167
167
  return {
168
- dateFrom: ms ? new Date(Date.now() - ms) : void 0,
168
+ dateFrom: ms ? new Date(now.getTime() - ms) : void 0,
169
169
  dateTo: void 0
170
170
  };
171
171
  };
@@ -1 +1 @@
1
- {"version":3,"file":"traces-explorer-actions.es.js","names":[],"sources":["../../../../../src/domains/traces/components/traces-explorer/traces-explorer-actions.ts"],"sourcesContent":["import {\n buildTraceListFilters,\n ROOT_ENTITY_TYPE_OPTIONS,\n TRACE_STATUS_VALUES,\n traceQueryUnqueryableFieldIds,\n} from '../../trace-filters';\nimport type {\n EntityOptions,\n TraceFilterGroup,\n TraceFilterToken,\n TraceQueryFieldSupport,\n TraceStatusFilter,\n} from '../../trace-filters';\nimport { buildTraceQueryRequest, TRACE_QUERY_UNSUPPORTED_FILTER_FIELDS } from '../../trace-query-filters';\nimport type { SpanTab, TraceDatePreset } from '../../types';\nimport type { TraceSpanView } from '../trace-data-panel-view';\n\nexport type TracesSelection = {\n traceId?: string;\n spanId?: string;\n spanTab?: SpanTab;\n spanView: TraceSpanView;\n scoreId?: string;\n highlightSpanIds: string[];\n};\n\n/** `rootEntityType` and `status` are tokens too (`fieldId: 'rootEntityType' | 'status'`), like every other filter. */\nexport type TracesFilters = {\n datePreset: TraceDatePreset;\n /** Only read when `datePreset` is `custom`. */\n dateFrom?: Date;\n /** Only read when `datePreset` is `custom`. */\n dateTo?: Date;\n tokens: TraceFilterToken[];\n groups: TraceFilterGroup[];\n};\n\nexport type TracesSortDirection = 'asc' | 'desc';\n\n/** Fields the traces list can be sorted by, named like the trace query's `orderBy` fields. */\nexport const TRACES_SORT_FIELDS = ['startedAt', 'timeToFirstChunkMs', 'timeToFirstTokenMs'] as const;\nexport type TracesSortField = (typeof TRACES_SORT_FIELDS)[number];\n\nexport type TracesSort = { field: TracesSortField; direction: TracesSortDirection };\n\nexport const DEFAULT_TRACES_SORT: TracesSort = { field: 'startedAt', direction: 'desc' };\n\n/** What the explorer emits on every change: filters and selection move together (a filter edit clears the selection). */\nexport type TracesExplorerState = { selection: TracesSelection; filters: TracesFilters };\n\nexport const EMPTY_TRACES_SELECTION: TracesSelection = { spanView: 'tree', highlightSpanIds: [] };\n\nexport const DEFAULT_TRACES_FILTERS: TracesFilters = { datePreset: 'last-7d', tokens: [], groups: [] };\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\nconst PRESET_MS: Partial<Record<TraceDatePreset, number>> = {\n 'last-24h': DAY_MS,\n 'last-3d': 3 * DAY_MS,\n 'last-7d': 7 * DAY_MS,\n 'last-14d': 14 * DAY_MS,\n 'last-30d': 30 * DAY_MS,\n};\n\nexport const isSelectionEmpty = (selection: TracesSelection) =>\n !selection.traceId &&\n !selection.spanId &&\n !selection.spanTab &&\n !selection.scoreId &&\n selection.highlightSpanIds.length === 0;\n\n/** Keeps the span view: it is a display preference, not part of what is selected. */\nexport const clearSelection = (selection: TracesSelection): TracesSelection => ({\n spanView: selection.spanView,\n highlightSpanIds: [],\n});\n\nexport const selectTrace = (selection: TracesSelection, traceId: string | null): TracesSelection =>\n traceId ? { traceId, spanView: selection.spanView, highlightSpanIds: [] } : clearSelection(selection);\n\n/**\n * The open tab stays, so stepping through spans compares the same tab; the score belongs to the\n * previous span and is dropped with it.\n */\nexport const selectSpan = (selection: TracesSelection, spanId: string | null): TracesSelection => {\n if ((spanId ?? undefined) === selection.spanId) return selection;\n return { ...selection, spanId: spanId ?? undefined, scoreId: undefined };\n};\n\nexport const setSpanTab = (selection: TracesSelection, tab: SpanTab): TracesSelection => {\n if (tab === selection.spanTab) return selection;\n return { ...selection, spanTab: tab === 'details' ? undefined : tab, scoreId: undefined };\n};\n\nexport const setSpanView = (selection: TracesSelection, spanView: TraceSpanView): TracesSelection =>\n spanView === selection.spanView ? selection : { ...selection, spanView };\n\nexport const selectScore = (selection: TracesSelection, scoreId: string | null): TracesSelection =>\n (scoreId ?? undefined) === selection.scoreId ? selection : { ...selection, scoreId: scoreId ?? undefined };\n\nexport const highlightSpans = (selection: TracesSelection, spanIds: string[]): TracesSelection => {\n const unchanged =\n spanIds.length === selection.highlightSpanIds.length &&\n spanIds.every((id, index) => id === selection.highlightSpanIds[index]);\n return unchanged ? selection : { ...selection, highlightSpanIds: spanIds };\n};\n\nexport const applyFilterTokens = (\n filters: TracesFilters,\n tokens: TraceFilterToken[],\n groups: TraceFilterGroup[],\n): TracesFilters => ({ ...filters, tokens, groups });\n\n/** Switching to `custom` keeps the current dates so the picker opens on them; any other preset drops them. */\nexport const applyDatePreset = (filters: TracesFilters, datePreset: TraceDatePreset): TracesFilters =>\n datePreset === 'custom' ? { ...filters, datePreset } : { datePreset, tokens: filters.tokens, groups: filters.groups };\n\n// The picker can report a date right after switching away from `custom`; those are ignored.\nexport const applyDate = (filters: TracesFilters, date: Date | undefined, end: 'from' | 'to'): TracesFilters => {\n if (filters.datePreset !== 'custom') return filters;\n return end === 'from' ? { ...filters, dateFrom: date } : { ...filters, dateTo: date };\n};\n\nexport const applyDateRange = (\n filters: TracesFilters,\n dateFrom: Date | undefined,\n dateTo: Date | undefined,\n): TracesFilters => (filters.datePreset === 'custom' ? { ...filters, dateFrom, dateTo } : filters);\n\nconst isQueryableToken = (token: TraceFilterToken, unqueryableFieldIds: ReadonlySet<string>) => {\n if (token.fieldId === 'status' && token.value === 'running') return false;\n if (TRACE_QUERY_UNSUPPORTED_FILTER_FIELDS.has(token.fieldId)) return false;\n return !unqueryableFieldIds.has(token.fieldId);\n};\n\n/**\n * Drops the top-level tokens the trace query can't run, so no chip advertises a filter with no effect.\n * Groups pass through and stay visible in the bar: `buildTracesQueryRequest` leaves their unqueryable\n * conditions out of the query. Returns the same object when nothing is dropped.\n */\nexport const sanitizeTracesFilters = (filters: TracesFilters, support: TraceQueryFieldSupport): TracesFilters => {\n const unqueryableFieldIds = traceQueryUnqueryableFieldIds(support);\n const tokens = filters.tokens.filter(token => isQueryableToken(token, unqueryableFieldIds));\n return tokens.length === filters.tokens.length ? filters : { ...filters, tokens };\n};\n\nconst selectsRunning = (node: TraceFilterGroup | TraceFilterToken): boolean => {\n if ('nodes' in node) return node.nodes.some(selectsRunning);\n if (node.fieldId !== 'status') return false;\n return Array.isArray(node.value) ? node.value.includes('running') : node.value === 'running';\n};\n\n/** Whether a status filter asks for `running`, which the trace query can't express and drops. */\nexport const selectsRunningStatus = (filters: TracesFilters): boolean =>\n filters.tokens.some(selectsRunning) || filters.groups.some(selectsRunning);\n\nconst tokenValue = (tokens: TraceFilterToken[], fieldId: string) => {\n const value = tokens.find(token => token.fieldId === fieldId)?.value;\n return typeof value === 'string' ? value : undefined;\n};\n\nexport const getSelectedEntityOption = (tokens: TraceFilterToken[]): EntityOptions | undefined => {\n const value = tokenValue(tokens, 'rootEntityType');\n return ROOT_ENTITY_TYPE_OPTIONS.find(option => option.entityType === value);\n};\n\nexport const getSelectedStatus = (tokens: TraceFilterToken[]): TraceStatusFilter | undefined => {\n const value = tokenValue(tokens, 'status');\n return value && TRACE_STATUS_VALUES.has(value as TraceStatusFilter) ? (value as TraceStatusFilter) : undefined;\n};\n\ntype TracesQueryWindow = { filters: TracesFilters; dateFrom?: Date; dateTo?: Date };\n\n/** The trace query for the (sanitized) filters and the resolved date window. */\nexport const buildTracesQueryRequest = ({\n filters,\n dateFrom,\n dateTo,\n now,\n ...support\n}: TracesQueryWindow & TraceQueryFieldSupport & { now: Date }) =>\n buildTraceQueryRequest({\n rootEntityType: getSelectedEntityOption(filters.tokens)?.entityType,\n status: getSelectedStatus(filters.tokens),\n dateFrom,\n dateTo,\n tokens: filters.tokens,\n groups: filters.groups,\n excludedFieldIds: traceQueryUnqueryableFieldIds(support),\n now,\n });\n\n/** The `listTracesLight` filters for servers without the trace query API (no groups there). */\nexport const buildTracesLegacyFilters = ({ filters, dateFrom, dateTo }: TracesQueryWindow) =>\n buildTraceListFilters({\n rootEntityType: getSelectedEntityOption(filters.tokens)?.entityType,\n status: getSelectedStatus(filters.tokens),\n dateFrom,\n dateTo,\n tokens: filters.tokens,\n });\n\n/** Rolling presets start `PRESET_MS` before now and stay open-ended; `all` is open on both ends. */\nexport const resolveTracesDateWindow = (\n datePreset: TraceDatePreset,\n dateFrom: Date | undefined,\n dateTo: Date | undefined,\n): { dateFrom?: Date; dateTo?: Date } => {\n if (datePreset === 'custom') return { dateFrom, dateTo };\n const ms = PRESET_MS[datePreset];\n return { dateFrom: ms ? new Date(Date.now() - ms) : undefined, dateTo: undefined };\n};\n"],"mappings":";;;AAwCA,IAAa,qBAAqB;CAAC;CAAa;CAAsB;AAAoB;AAK1F,IAAa,sBAAkC;CAAE,OAAO;CAAa,WAAW;AAAO;AAKvF,IAAa,yBAA0C;CAAE,UAAU;CAAQ,kBAAkB,CAAC;AAAE;AAEhG,IAAa,yBAAwC;CAAE,YAAY;CAAW,QAAQ,CAAC;CAAG,QAAQ,CAAC;AAAE;AAErG,IAAM,SAAS;AACf,IAAM,YAAsD;CAC1D,YAAY;CACZ,WAAW,IAAI;CACf,WAAW,IAAI;CACf,YAAY,KAAK;CACjB,YAAY,KAAK;AACnB;AAEA,IAAa,oBAAoB,cAC/B,CAAC,UAAU,WACX,CAAC,UAAU,UACX,CAAC,UAAU,WACX,CAAC,UAAU,WACX,UAAU,iBAAiB,WAAW;;AAGxC,IAAa,kBAAkB,eAAiD;CAC9E,UAAU,UAAU;CACpB,kBAAkB,CAAC;AACrB;AAEA,IAAa,eAAe,WAA4B,YACtD,UAAU;CAAE;CAAS,UAAU,UAAU;CAAU,kBAAkB,CAAC;AAAE,IAAI,eAAe,SAAS;;;;;AAMtG,IAAa,cAAc,WAA4B,WAA2C;CAChG,KAAK,UAAU,KAAA,OAAe,UAAU,QAAQ,OAAO;CACvD,OAAO;EAAE,GAAG;EAAW,QAAQ,UAAU,KAAA;EAAW,SAAS,KAAA;CAAU;AACzE;AAEA,IAAa,cAAc,WAA4B,QAAkC;CACvF,IAAI,QAAQ,UAAU,SAAS,OAAO;CACtC,OAAO;EAAE,GAAG;EAAW,SAAS,QAAQ,YAAY,KAAA,IAAY;EAAK,SAAS,KAAA;CAAU;AAC1F;AAEA,IAAa,eAAe,WAA4B,aACtD,aAAa,UAAU,WAAW,YAAY;CAAE,GAAG;CAAW;AAAS;AAEzE,IAAa,eAAe,WAA4B,aACrD,WAAW,KAAA,OAAe,UAAU,UAAU,YAAY;CAAE,GAAG;CAAW,SAAS,WAAW,KAAA;AAAU;AAE3G,IAAa,kBAAkB,WAA4B,YAAuC;CAIhG,OAFE,QAAQ,WAAW,UAAU,iBAAiB,UAC9C,QAAQ,OAAO,IAAI,UAAU,OAAO,UAAU,iBAAiB,MAAM,IACpD,YAAY;EAAE,GAAG;EAAW,kBAAkB;CAAQ;AAC3E;AAEA,IAAa,qBACX,SACA,QACA,YACmB;CAAE,GAAG;CAAS;CAAQ;AAAO;;AAGlD,IAAa,mBAAmB,SAAwB,eACtD,eAAe,WAAW;CAAE,GAAG;CAAS;AAAW,IAAI;CAAE;CAAY,QAAQ,QAAQ;CAAQ,QAAQ,QAAQ;AAAO;AAGtH,IAAa,aAAa,SAAwB,MAAwB,QAAsC;CAC9G,IAAI,QAAQ,eAAe,UAAU,OAAO;CAC5C,OAAO,QAAQ,SAAS;EAAE,GAAG;EAAS,UAAU;CAAK,IAAI;EAAE,GAAG;EAAS,QAAQ;CAAK;AACtF;AAEA,IAAa,kBACX,SACA,UACA,WACmB,QAAQ,eAAe,WAAW;CAAE,GAAG;CAAS;CAAU;AAAO,IAAI;AAE1F,IAAM,oBAAoB,OAAyB,wBAA6C;CAC9F,IAAI,MAAM,YAAY,YAAY,MAAM,UAAU,WAAW,OAAO;CACpE,IAAI,sCAAsC,IAAI,MAAM,OAAO,GAAG,OAAO;CACrE,OAAO,CAAC,oBAAoB,IAAI,MAAM,OAAO;AAC/C;;;;;;AAOA,IAAa,yBAAyB,SAAwB,YAAmD;CAC/G,MAAM,sBAAsB,8BAA8B,OAAO;CACjE,MAAM,SAAS,QAAQ,OAAO,QAAO,UAAS,iBAAiB,OAAO,mBAAmB,CAAC;CAC1F,OAAO,OAAO,WAAW,QAAQ,OAAO,SAAS,UAAU;EAAE,GAAG;EAAS;CAAO;AAClF;AAEA,IAAM,kBAAkB,SAAuD;CAC7E,IAAI,WAAW,MAAM,OAAO,KAAK,MAAM,KAAK,cAAc;CAC1D,IAAI,KAAK,YAAY,UAAU,OAAO;CACtC,OAAO,MAAM,QAAQ,KAAK,KAAK,IAAI,KAAK,MAAM,SAAS,SAAS,IAAI,KAAK,UAAU;AACrF;;AAGA,IAAa,wBAAwB,YACnC,QAAQ,OAAO,KAAK,cAAc,KAAK,QAAQ,OAAO,KAAK,cAAc;AAE3E,IAAM,cAAc,QAA4B,YAAoB;CAClE,MAAM,QAAQ,OAAO,MAAK,UAAS,MAAM,YAAY,OAAO,CAAC,EAAE;CAC/D,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;AAC7C;AAEA,IAAa,2BAA2B,WAA0D;CAChG,MAAM,QAAQ,WAAW,QAAQ,gBAAgB;CACjD,OAAO,yBAAyB,MAAK,WAAU,OAAO,eAAe,KAAK;AAC5E;AAEA,IAAa,qBAAqB,WAA8D;CAC9F,MAAM,QAAQ,WAAW,QAAQ,QAAQ;CACzC,OAAO,SAAS,oBAAoB,IAAI,KAA0B,IAAK,QAA8B,KAAA;AACvG;;AAKA,IAAa,2BAA2B,EACtC,SACA,UACA,QACA,KACA,GAAG,cAEH,uBAAuB;CACrB,gBAAgB,wBAAwB,QAAQ,MAAM,CAAC,EAAE;CACzD,QAAQ,kBAAkB,QAAQ,MAAM;CACxC;CACA;CACA,QAAQ,QAAQ;CAChB,QAAQ,QAAQ;CAChB,kBAAkB,8BAA8B,OAAO;CACvD;AACF,CAAC;;AAGH,IAAa,4BAA4B,EAAE,SAAS,UAAU,aAC5D,sBAAsB;CACpB,gBAAgB,wBAAwB,QAAQ,MAAM,CAAC,EAAE;CACzD,QAAQ,kBAAkB,QAAQ,MAAM;CACxC;CACA;CACA,QAAQ,QAAQ;AAClB,CAAC;;AAGH,IAAa,2BACX,YACA,UACA,WACuC;CACvC,IAAI,eAAe,UAAU,OAAO;EAAE;EAAU;CAAO;CACvD,MAAM,KAAK,UAAU;CACrB,OAAO;EAAE,UAAU,KAAK,IAAI,KAAK,KAAK,IAAI,IAAI,EAAE,IAAI,KAAA;EAAW,QAAQ,KAAA;CAAU;AACnF"}
1
+ {"version":3,"file":"traces-explorer-actions.es.js","names":[],"sources":["../../../../../src/domains/traces/components/traces-explorer/traces-explorer-actions.ts"],"sourcesContent":["import {\n buildTraceListFilters,\n ROOT_ENTITY_TYPE_OPTIONS,\n TRACE_STATUS_VALUES,\n traceQueryUnqueryableFieldIds,\n} from '../../trace-filters';\nimport type {\n EntityOptions,\n TraceFilterGroup,\n TraceFilterToken,\n TraceQueryFieldSupport,\n TraceStatusFilter,\n} from '../../trace-filters';\nimport { buildTraceQueryRequest, TRACE_QUERY_UNSUPPORTED_FILTER_FIELDS } from '../../trace-query-filters';\nimport type { SpanTab, TraceDatePreset } from '../../types';\nimport type { TraceSpanView } from '../trace-data-panel-view';\n\nexport type TracesSelection = {\n traceId?: string;\n spanId?: string;\n spanTab?: SpanTab;\n spanView: TraceSpanView;\n scoreId?: string;\n highlightSpanIds: string[];\n};\n\n/** `rootEntityType` and `status` are tokens too (`fieldId: 'rootEntityType' | 'status'`), like every other filter. */\nexport type TracesFilters = {\n datePreset: TraceDatePreset;\n /** Only read when `datePreset` is `custom`. */\n dateFrom?: Date;\n /** Only read when `datePreset` is `custom`. */\n dateTo?: Date;\n tokens: TraceFilterToken[];\n groups: TraceFilterGroup[];\n};\n\nexport type TracesSortDirection = 'asc' | 'desc';\n\n/** Fields the traces list can be sorted by, named like the trace query's `orderBy` fields. */\nexport const TRACES_SORT_FIELDS = ['startedAt', 'timeToFirstChunkMs', 'timeToFirstTokenMs'] as const;\nexport type TracesSortField = (typeof TRACES_SORT_FIELDS)[number];\n\nexport type TracesSort = { field: TracesSortField; direction: TracesSortDirection };\n\nexport const DEFAULT_TRACES_SORT: TracesSort = { field: 'startedAt', direction: 'desc' };\n\n/** What the explorer emits on every change: filters and selection move together (a filter edit clears the selection). */\nexport type TracesExplorerState = { selection: TracesSelection; filters: TracesFilters };\n\nexport const EMPTY_TRACES_SELECTION: TracesSelection = { spanView: 'tree', highlightSpanIds: [] };\n\nexport const DEFAULT_TRACES_FILTERS: TracesFilters = { datePreset: 'last-7d', tokens: [], groups: [] };\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\nconst PRESET_MS: Partial<Record<TraceDatePreset, number>> = {\n 'last-24h': DAY_MS,\n 'last-3d': 3 * DAY_MS,\n 'last-7d': 7 * DAY_MS,\n 'last-14d': 14 * DAY_MS,\n 'last-30d': 30 * DAY_MS,\n};\n\nexport const isSelectionEmpty = (selection: TracesSelection) =>\n !selection.traceId &&\n !selection.spanId &&\n !selection.spanTab &&\n !selection.scoreId &&\n selection.highlightSpanIds.length === 0;\n\n/** Keeps the span view: it is a display preference, not part of what is selected. */\nexport const clearSelection = (selection: TracesSelection): TracesSelection => ({\n spanView: selection.spanView,\n highlightSpanIds: [],\n});\n\nexport const selectTrace = (selection: TracesSelection, traceId: string | null): TracesSelection =>\n traceId ? { traceId, spanView: selection.spanView, highlightSpanIds: [] } : clearSelection(selection);\n\n/**\n * The open tab stays, so stepping through spans compares the same tab; the score belongs to the\n * previous span and is dropped with it.\n */\nexport const selectSpan = (selection: TracesSelection, spanId: string | null): TracesSelection => {\n if ((spanId ?? undefined) === selection.spanId) return selection;\n return { ...selection, spanId: spanId ?? undefined, scoreId: undefined };\n};\n\nexport const setSpanTab = (selection: TracesSelection, tab: SpanTab): TracesSelection => {\n if (tab === selection.spanTab) return selection;\n return { ...selection, spanTab: tab === 'details' ? undefined : tab, scoreId: undefined };\n};\n\nexport const setSpanView = (selection: TracesSelection, spanView: TraceSpanView): TracesSelection =>\n spanView === selection.spanView ? selection : { ...selection, spanView };\n\nexport const selectScore = (selection: TracesSelection, scoreId: string | null): TracesSelection =>\n (scoreId ?? undefined) === selection.scoreId ? selection : { ...selection, scoreId: scoreId ?? undefined };\n\nexport const highlightSpans = (selection: TracesSelection, spanIds: string[]): TracesSelection => {\n const unchanged =\n spanIds.length === selection.highlightSpanIds.length &&\n spanIds.every((id, index) => id === selection.highlightSpanIds[index]);\n return unchanged ? selection : { ...selection, highlightSpanIds: spanIds };\n};\n\nexport const applyFilterTokens = (\n filters: TracesFilters,\n tokens: TraceFilterToken[],\n groups: TraceFilterGroup[],\n): TracesFilters => ({ ...filters, tokens, groups });\n\n/** Switching to `custom` keeps the current dates so the picker opens on them; any other preset drops them. */\nexport const applyDatePreset = (filters: TracesFilters, datePreset: TraceDatePreset): TracesFilters =>\n datePreset === 'custom' ? { ...filters, datePreset } : { datePreset, tokens: filters.tokens, groups: filters.groups };\n\n// The picker can report a date right after switching away from `custom`; those are ignored.\nexport const applyDate = (filters: TracesFilters, date: Date | undefined, end: 'from' | 'to'): TracesFilters => {\n if (filters.datePreset !== 'custom') return filters;\n return end === 'from' ? { ...filters, dateFrom: date } : { ...filters, dateTo: date };\n};\n\nexport const applyDateRange = (\n filters: TracesFilters,\n dateFrom: Date | undefined,\n dateTo: Date | undefined,\n): TracesFilters => (filters.datePreset === 'custom' ? { ...filters, dateFrom, dateTo } : filters);\n\nconst isQueryableToken = (token: TraceFilterToken, unqueryableFieldIds: ReadonlySet<string>) => {\n if (token.fieldId === 'status' && token.value === 'running') return false;\n if (TRACE_QUERY_UNSUPPORTED_FILTER_FIELDS.has(token.fieldId)) return false;\n return !unqueryableFieldIds.has(token.fieldId);\n};\n\n/**\n * Drops the top-level tokens the trace query can't run, so no chip advertises a filter with no effect.\n * Groups pass through and stay visible in the bar: `buildTracesQueryRequest` leaves their unqueryable\n * conditions out of the query. Returns the same object when nothing is dropped.\n */\nexport const sanitizeTracesFilters = (filters: TracesFilters, support: TraceQueryFieldSupport): TracesFilters => {\n const unqueryableFieldIds = traceQueryUnqueryableFieldIds(support);\n const tokens = filters.tokens.filter(token => isQueryableToken(token, unqueryableFieldIds));\n return tokens.length === filters.tokens.length ? filters : { ...filters, tokens };\n};\n\nconst selectsRunning = (node: TraceFilterGroup | TraceFilterToken): boolean => {\n if ('nodes' in node) return node.nodes.some(selectsRunning);\n if (node.fieldId !== 'status') return false;\n return Array.isArray(node.value) ? node.value.includes('running') : node.value === 'running';\n};\n\n/** Whether a status filter asks for `running`, which the trace query can't express and drops. */\nexport const selectsRunningStatus = (filters: TracesFilters): boolean =>\n filters.tokens.some(selectsRunning) || filters.groups.some(selectsRunning);\n\nconst tokenValue = (tokens: TraceFilterToken[], fieldId: string) => {\n const value = tokens.find(token => token.fieldId === fieldId)?.value;\n return typeof value === 'string' ? value : undefined;\n};\n\nexport const getSelectedEntityOption = (tokens: TraceFilterToken[]): EntityOptions | undefined => {\n const value = tokenValue(tokens, 'rootEntityType');\n return ROOT_ENTITY_TYPE_OPTIONS.find(option => option.entityType === value);\n};\n\nexport const getSelectedStatus = (tokens: TraceFilterToken[]): TraceStatusFilter | undefined => {\n const value = tokenValue(tokens, 'status');\n return value && TRACE_STATUS_VALUES.has(value as TraceStatusFilter) ? (value as TraceStatusFilter) : undefined;\n};\n\ntype TracesQueryWindow = { filters: TracesFilters; dateFrom?: Date; dateTo?: Date };\n\n/** The trace query for the (sanitized) filters and the resolved date window. */\nexport const buildTracesQueryRequest = ({\n filters,\n dateFrom,\n dateTo,\n now,\n ...support\n}: TracesQueryWindow & TraceQueryFieldSupport & { now: Date }) =>\n buildTraceQueryRequest({\n rootEntityType: getSelectedEntityOption(filters.tokens)?.entityType,\n status: getSelectedStatus(filters.tokens),\n dateFrom,\n dateTo,\n tokens: filters.tokens,\n groups: filters.groups,\n excludedFieldIds: traceQueryUnqueryableFieldIds(support),\n now,\n });\n\n/** The `listTracesLight` filters for servers without the trace query API (no groups there). */\nexport const buildTracesLegacyFilters = ({ filters, dateFrom, dateTo }: TracesQueryWindow) =>\n buildTraceListFilters({\n rootEntityType: getSelectedEntityOption(filters.tokens)?.entityType,\n status: getSelectedStatus(filters.tokens),\n dateFrom,\n dateTo,\n tokens: filters.tokens,\n });\n\n/** Rolling presets start `PRESET_MS` before now and stay open-ended; `all` is open on both ends. */\nexport const resolveTracesDateWindow = (\n datePreset: TraceDatePreset,\n dateFrom: Date | undefined,\n dateTo: Date | undefined,\n now: Date = new Date(),\n): { dateFrom?: Date; dateTo?: Date } => {\n if (datePreset === 'custom') return { dateFrom, dateTo };\n const ms = PRESET_MS[datePreset];\n return { dateFrom: ms ? new Date(now.getTime() - ms) : undefined, dateTo: undefined };\n};\n"],"mappings":"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"}
@@ -118,7 +118,7 @@ export declare const buildTracesLegacyFilters: ({ filters, dateFrom, dateTo }: T
118
118
  hasChildError?: unknown;
119
119
  } | undefined;
120
120
  /** Rolling presets start `PRESET_MS` before now and stay open-ended; `all` is open on both ends. */
121
- export declare const resolveTracesDateWindow: (datePreset: TraceDatePreset, dateFrom: Date | undefined, dateTo: Date | undefined) => {
121
+ export declare const resolveTracesDateWindow: (datePreset: TraceDatePreset, dateFrom: Date | undefined, dateTo: Date | undefined, now?: Date) => {
122
122
  dateFrom?: Date;
123
123
  dateTo?: Date;
124
124
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mastra/playground-ui",
3
3
  "type": "module",
4
- "version": "69.0.0-alpha.2",
4
+ "version": "69.0.0-alpha.3",
5
5
  "description": "Mastra Playground components",
6
6
  "sideEffects": [
7
7
  "**/*.css"
@@ -221,8 +221,8 @@
221
221
  "react-dom": ">=19.0.0",
222
222
  "tailwindcss": "^4.0.0",
223
223
  "@mastra/ai-sdk": "^1.11.3",
224
- "@mastra/client-js": "^1.60.0-alpha.1",
225
- "@mastra/react": "1.15.0-alpha.1"
224
+ "@mastra/client-js": "^1.60.0-alpha.2",
225
+ "@mastra/react": "1.15.0-alpha.2"
226
226
  },
227
227
  "devDependencies": {
228
228
  "@modelcontextprotocol/client": "2.4.0",
@@ -266,13 +266,13 @@
266
266
  "vite-plugin-lib-inject-css": "^2.2.2",
267
267
  "vitest": "5.1.0",
268
268
  "@types/d3-force": "^3.0.10",
269
+ "@internal/lint": "0.0.148",
269
270
  "@mastra/ai-sdk": "1.11.3",
270
- "@mastra/client-js": "^1.60.0-alpha.1",
271
- "@mastra/core": "1.83.0-alpha.1",
271
+ "@mastra/client-js": "^1.60.0-alpha.2",
272
+ "@mastra/core": "1.83.0-alpha.2",
272
273
  "@mastra/memory": "1.41.1-alpha.0",
273
- "@mastra/react": "1.15.0-alpha.1",
274
- "@mastra/schema-compat": "1.3.17",
275
- "@internal/lint": "0.0.148"
274
+ "@mastra/react": "1.15.0-alpha.2",
275
+ "@mastra/schema-compat": "1.3.17"
276
276
  },
277
277
  "homepage": "https://mastra.ai",
278
278
  "repository": {