@mastra/playground-ui 51.3.0-alpha.0 → 51.3.0-alpha.2
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 +41 -0
- package/LICENSE.md +6 -4
- package/dist/components/Composer.cjs.js +1 -1
- package/dist/components/Composer.cjs.js.map +1 -1
- package/dist/components/Composer.es.js +1 -1
- package/dist/components/Composer.es.js.map +1 -1
- package/dist/components/DataCodeSection.cjs.js +1 -1
- package/dist/components/DataCodeSection.es.js +1 -1
- package/dist/components/DataPanel.cjs.js +1 -1
- package/dist/components/DataPanel.es.js +1 -1
- package/dist/components/FormFieldBlocks.cjs.js +1 -1
- package/dist/components/FormFieldBlocks.es.js +1 -1
- package/dist/components/ListSearch.cjs.js +13 -2
- package/dist/components/ListSearch.cjs.js.map +1 -1
- package/dist/components/ListSearch.es.js +14 -3
- package/dist/components/ListSearch.es.js.map +1 -1
- package/dist/{data-code-section-sK4cZuA-.cjs → data-code-section-C3ZRkULz.cjs} +2 -2
- package/dist/{data-code-section-sK4cZuA-.cjs.map → data-code-section-C3ZRkULz.cjs.map} +1 -1
- package/dist/{data-code-section-g1jBtzwR.js → data-code-section-CSt_ZuUP.js} +2 -2
- package/dist/{data-code-section-g1jBtzwR.js.map → data-code-section-CSt_ZuUP.js.map} +1 -1
- package/dist/{data-panel-B3AECYLW.cjs → data-panel-DHNc5Y4L.cjs} +2 -2
- package/dist/{data-panel-B3AECYLW.cjs.map → data-panel-DHNc5Y4L.cjs.map} +1 -1
- package/dist/{data-panel-B527Q_Zh.js → data-panel-DJpAfEsG.js} +2 -2
- package/dist/{data-panel-B527Q_Zh.js.map → data-panel-DJpAfEsG.js.map} +1 -1
- package/dist/domains/traces/components/span-data-panel-view.cjs.js +1 -1
- package/dist/domains/traces/components/span-data-panel-view.es.js +1 -1
- package/dist/domains/traces/components/timeline-name-col.cjs.js +1 -1
- package/dist/domains/traces/components/timeline-name-col.cjs.js.map +1 -1
- package/dist/domains/traces/components/timeline-name-col.es.js +1 -1
- package/dist/domains/traces/components/timeline-name-col.es.js.map +1 -1
- package/dist/domains/traces/components/trace-data-panel-view.cjs.js +44 -9
- package/dist/domains/traces/components/trace-data-panel-view.cjs.js.map +1 -1
- package/dist/domains/traces/components/trace-data-panel-view.es.js +45 -10
- package/dist/domains/traces/components/trace-data-panel-view.es.js.map +1 -1
- package/dist/domains/traces/components/trace-timeline.cjs.js +18 -14
- package/dist/domains/traces/components/trace-timeline.cjs.js.map +1 -1
- package/dist/domains/traces/components/trace-timeline.es.js +18 -14
- package/dist/domains/traces/components/trace-timeline.es.js.map +1 -1
- package/dist/domains/traces/hooks/use-branch.cjs.js +4 -0
- package/dist/domains/traces/hooks/use-branch.cjs.js.map +1 -1
- package/dist/domains/traces/hooks/use-branch.es.js +4 -0
- package/dist/domains/traces/hooks/use-branch.es.js.map +1 -1
- package/dist/domains/traces/hooks/use-trace-light-spans.cjs.js +4 -0
- package/dist/domains/traces/hooks/use-trace-light-spans.cjs.js.map +1 -1
- package/dist/domains/traces/hooks/use-trace-light-spans.es.js +4 -0
- package/dist/domains/traces/hooks/use-trace-light-spans.es.js.map +1 -1
- package/dist/domains/traces/hooks/use-trace-or-branch-spans.cjs.js +2 -2
- package/dist/domains/traces/hooks/use-trace-or-branch-spans.cjs.js.map +1 -1
- package/dist/domains/traces/hooks/use-trace-or-branch-spans.es.js +2 -2
- package/dist/domains/traces/hooks/use-trace-or-branch-spans.es.js.map +1 -1
- package/dist/domains/traces/hooks/use-trace-search.cjs.js +21 -0
- package/dist/domains/traces/hooks/use-trace-search.cjs.js.map +1 -0
- package/dist/domains/traces/hooks/use-trace-search.d.ts +2 -0
- package/dist/domains/traces/hooks/use-trace-search.es.js +17 -0
- package/dist/domains/traces/hooks/use-trace-search.es.js.map +1 -0
- package/dist/domains/traces/hooks/use-trace-spans.cjs.js +11 -1
- package/dist/domains/traces/hooks/use-trace-spans.cjs.js.map +1 -1
- package/dist/domains/traces/hooks/use-trace-spans.es.js +11 -1
- package/dist/domains/traces/hooks/use-trace-spans.es.js.map +1 -1
- package/dist/domains/traces/hooks.cjs.js +2 -0
- package/dist/domains/traces/hooks.cjs.js.map +1 -1
- package/dist/domains/traces/hooks.es.js +1 -0
- package/dist/domains/traces/hooks.es.js.map +1 -1
- package/dist/domains/traces/types.cjs.js.map +1 -1
- package/dist/domains/traces/types.es.js.map +1 -1
- package/dist/domains/traces/utils/filter-spans-keeping-ancestors.cjs.js +47 -0
- package/dist/domains/traces/utils/filter-spans-keeping-ancestors.cjs.js.map +1 -0
- package/dist/domains/traces/utils/filter-spans-keeping-ancestors.d.ts +2 -0
- package/dist/domains/traces/utils/filter-spans-keeping-ancestors.es.js +43 -0
- package/dist/domains/traces/utils/filter-spans-keeping-ancestors.es.js.map +1 -0
- package/dist/domains/traces/utils/flatten-to-search-text.cjs.js +78 -0
- package/dist/domains/traces/utils/flatten-to-search-text.cjs.js.map +1 -0
- package/dist/domains/traces/utils/flatten-to-search-text.d.ts +2 -0
- package/dist/domains/traces/utils/flatten-to-search-text.es.js +74 -0
- package/dist/domains/traces/utils/flatten-to-search-text.es.js.map +1 -0
- package/dist/domains/traces/utils/to-searchable-spans.cjs.js +22 -0
- package/dist/domains/traces/utils/to-searchable-spans.cjs.js.map +1 -0
- package/dist/domains/traces/utils/to-searchable-spans.d.ts +2 -0
- package/dist/domains/traces/utils/to-searchable-spans.es.js +17 -0
- package/dist/domains/traces/utils/to-searchable-spans.es.js.map +1 -0
- package/dist/domains/traces/utils.cjs.js +7 -0
- package/dist/domains/traces/utils.cjs.js.map +1 -1
- package/dist/domains/traces/utils.es.js +3 -0
- package/dist/domains/traces/utils.es.js.map +1 -1
- package/dist/domains/traces.cjs.js +9 -0
- package/dist/domains/traces.cjs.js.map +1 -1
- package/dist/domains/traces.es.js +4 -0
- package/dist/domains/traces.es.js.map +1 -1
- package/dist/ee/topics/components/topic-trace-details-panel.cjs.js +2 -2
- package/dist/ee/topics/components/topic-trace-details-panel.cjs.js.map +1 -1
- package/dist/ee/topics/components/topic-trace-details-panel.es.js +2 -2
- package/dist/ee/topics/components/topic-trace-details-panel.es.js.map +1 -1
- package/dist/hooks/use-text-highlight.cjs.js +68 -0
- package/dist/hooks/use-text-highlight.cjs.js.map +1 -0
- package/dist/hooks/use-text-highlight.d.ts +2 -0
- package/dist/hooks/use-text-highlight.es.js +64 -0
- package/dist/hooks/use-text-highlight.es.js.map +1 -0
- package/dist/{search-field-block-BqRM53jf.cjs → search-field-block-CjCIzUhN.cjs} +8 -3
- package/dist/search-field-block-CjCIzUhN.cjs.map +1 -0
- package/dist/{search-field-block-CgrC6f9t.js → search-field-block-DoNywsJC.js} +8 -3
- package/dist/search-field-block-DoNywsJC.js.map +1 -0
- package/dist/src/domains/traces/components/trace-data-panel-view.d.ts +2 -2
- package/dist/src/domains/traces/components/trace-timeline.d.ts +4 -2
- package/dist/src/domains/traces/hooks/index.d.ts +1 -0
- package/dist/src/domains/traces/hooks/use-branch.d.ts +2 -2
- package/dist/src/domains/traces/hooks/use-trace-light-spans.d.ts +2 -2
- package/dist/src/domains/traces/hooks/use-trace-or-branch-spans.d.ts +5 -2
- package/dist/src/domains/traces/hooks/use-trace-search.d.ts +27 -0
- package/dist/src/domains/traces/hooks/use-trace-spans.d.ts +11 -2
- package/dist/src/domains/traces/types.d.ts +16 -0
- package/dist/src/domains/traces/utils/filter-spans-keeping-ancestors.d.ts +19 -0
- package/dist/src/domains/traces/utils/flatten-to-search-text.d.ts +25 -0
- package/dist/src/domains/traces/utils/index.d.ts +3 -0
- package/dist/src/domains/traces/utils/to-searchable-spans.d.ts +41 -0
- package/dist/src/ds/components/FormFieldBlocks/fields/search-field-block.d.ts +4 -1
- package/dist/src/ds/components/ListSearch/list-search.d.ts +6 -1
- package/dist/src/hooks/use-text-highlight.d.ts +18 -0
- package/dist/src/test/highlight-api.d.ts +28 -0
- package/dist/style.css +0 -20
- package/dist/use-text-highlight.css +8 -0
- package/package.json +7 -7
- package/dist/search-field-block-BqRM53jf.cjs.map +0 -1
- package/dist/search-field-block-CgrC6f9t.js.map +0 -1
|
@@ -28,6 +28,7 @@ const domains_traces_hooks_useDownloadTraceJson = require('./traces/hooks/use-do
|
|
|
28
28
|
const domains_traces_hooks_useSpanDetail = require('./traces/hooks/use-span-detail.cjs.js');
|
|
29
29
|
const domains_traces_hooks_useTraceLightSpans = require('./traces/hooks/use-trace-light-spans.cjs.js');
|
|
30
30
|
const domains_traces_hooks_useTraceOrBranchSpans = require('./traces/hooks/use-trace-or-branch-spans.cjs.js');
|
|
31
|
+
const domains_traces_hooks_useTraceSearch = require('./traces/hooks/use-trace-search.cjs.js');
|
|
31
32
|
const domains_traces_hooks_useTraceSpans = require('./traces/hooks/use-trace-spans.cjs.js');
|
|
32
33
|
const domains_traces_hooks_useTraces = require('./traces/hooks/use-traces.cjs.js');
|
|
33
34
|
const domains_traces_hooks_useTags = require('./traces/hooks/use-tags.cjs.js');
|
|
@@ -38,6 +39,9 @@ const domains_traces_hooks_useTraceSpanNavigation = require('./traces/hooks/use-
|
|
|
38
39
|
const domains_traces_hooks_useTraceListNavigation = require('./traces/hooks/use-trace-list-navigation.cjs.js');
|
|
39
40
|
const domains_traces_hooks_useTraceUrlState = require('./traces/hooks/use-trace-url-state.cjs.js');
|
|
40
41
|
const domains_traces_hooks_useTraceFilterPersistence = require('./traces/hooks/use-trace-filter-persistence.cjs.js');
|
|
42
|
+
const domains_traces_utils_filterSpansKeepingAncestors = require('./traces/utils/filter-spans-keeping-ancestors.cjs.js');
|
|
43
|
+
const domains_traces_utils_flattenToSearchText = require('./traces/utils/flatten-to-search-text.cjs.js');
|
|
44
|
+
const domains_traces_utils_toSearchableSpans = require('./traces/utils/to-searchable-spans.cjs.js');
|
|
41
45
|
const domains_traces_utils_spanUtils = require('./traces/utils/span-utils.cjs.js');
|
|
42
46
|
const domains_traces_traceFilters = require('./traces/trace-filters.cjs.js');
|
|
43
47
|
const domains_traces_types = require('./traces/types.cjs.js');
|
|
@@ -72,6 +76,7 @@ exports.useDownloadTraceJson = domains_traces_hooks_useDownloadTraceJson.useDown
|
|
|
72
76
|
exports.useSpanDetail = domains_traces_hooks_useSpanDetail.useSpanDetail;
|
|
73
77
|
exports.useTraceLightSpans = domains_traces_hooks_useTraceLightSpans.useTraceLightSpans;
|
|
74
78
|
exports.useTraceOrBranchSpans = domains_traces_hooks_useTraceOrBranchSpans.useTraceOrBranchSpans;
|
|
79
|
+
exports.useTraceSearch = domains_traces_hooks_useTraceSearch.useTraceSearch;
|
|
75
80
|
exports.useTraceSpans = domains_traces_hooks_useTraceSpans.useTraceSpans;
|
|
76
81
|
exports.useTraces = domains_traces_hooks_useTraces.useTraces;
|
|
77
82
|
exports.useTags = domains_traces_hooks_useTags.useTags;
|
|
@@ -82,6 +87,10 @@ exports.useTraceSpanNavigation = domains_traces_hooks_useTraceSpanNavigation.use
|
|
|
82
87
|
exports.useTraceListNavigation = domains_traces_hooks_useTraceListNavigation.useTraceListNavigation;
|
|
83
88
|
exports.useTraceUrlState = domains_traces_hooks_useTraceUrlState.useTraceUrlState;
|
|
84
89
|
exports.useTraceFilterPersistence = domains_traces_hooks_useTraceFilterPersistence.useTraceFilterPersistence;
|
|
90
|
+
exports.filterSpansKeepingAncestors = domains_traces_utils_filterSpansKeepingAncestors.filterSpansKeepingAncestors;
|
|
91
|
+
exports.flattenToSearchText = domains_traces_utils_flattenToSearchText.flattenToSearchText;
|
|
92
|
+
exports.selectSearchableSpans = domains_traces_utils_toSearchableSpans.selectSearchableSpans;
|
|
93
|
+
exports.toSearchableSpans = domains_traces_utils_toSearchableSpans.toSearchableSpans;
|
|
85
94
|
exports.formatSpanDuration = domains_traces_utils_spanUtils.formatSpanDuration;
|
|
86
95
|
exports.getInputPreview = domains_traces_utils_spanUtils.getInputPreview;
|
|
87
96
|
exports.getTokenLimitMessage = domains_traces_utils_spanUtils.getTokenLimitMessage;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"traces.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"traces.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -24,6 +24,7 @@ export { useDownloadTraceJson } from './traces/hooks/use-download-trace-json.es.
|
|
|
24
24
|
export { useSpanDetail } from './traces/hooks/use-span-detail.es.js';
|
|
25
25
|
export { useTraceLightSpans } from './traces/hooks/use-trace-light-spans.es.js';
|
|
26
26
|
export { useTraceOrBranchSpans } from './traces/hooks/use-trace-or-branch-spans.es.js';
|
|
27
|
+
export { useTraceSearch } from './traces/hooks/use-trace-search.es.js';
|
|
27
28
|
export { useTraceSpans } from './traces/hooks/use-trace-spans.es.js';
|
|
28
29
|
export { useTraces } from './traces/hooks/use-traces.es.js';
|
|
29
30
|
export { useTags } from './traces/hooks/use-tags.es.js';
|
|
@@ -34,6 +35,9 @@ export { useTraceSpanNavigation } from './traces/hooks/use-trace-span-navigation
|
|
|
34
35
|
export { useTraceListNavigation } from './traces/hooks/use-trace-list-navigation.es.js';
|
|
35
36
|
export { useTraceUrlState } from './traces/hooks/use-trace-url-state.es.js';
|
|
36
37
|
export { useTraceFilterPersistence } from './traces/hooks/use-trace-filter-persistence.es.js';
|
|
38
|
+
export { filterSpansKeepingAncestors } from './traces/utils/filter-spans-keeping-ancestors.es.js';
|
|
39
|
+
export { flattenToSearchText } from './traces/utils/flatten-to-search-text.es.js';
|
|
40
|
+
export { selectSearchableSpans, toSearchableSpans } from './traces/utils/to-searchable-spans.es.js';
|
|
37
41
|
export { formatSpanDuration, getInputPreview, getTokenLimitMessage, isTokenLimitExceeded } from './traces/utils/span-utils.es.js';
|
|
38
42
|
export { DEFAULT_TRACE_FILTERS_STORAGE_KEY, ROOT_ENTITY_TYPES, ROOT_ENTITY_TYPE_OPTIONS, TRACE_ANCHOR_SPAN_ID_PARAM, TRACE_DATE_FROM_PARAM, TRACE_DATE_PRESET_PARAM, TRACE_DATE_PRESET_VALUES, TRACE_DATE_TO_PARAM, TRACE_LIST_MODE_OPTIONS, TRACE_LIST_MODE_PARAM, TRACE_LIST_MODE_VALUES, 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, applyTracePropertyFilterTokens, buildTraceListFilters, clearSavedTraceFilters, createTracePropertyFilterFields, getPreservedTraceFilterParams, getTracePropertyFilterTokens, hasAnyTraceFilterParams, loadTraceFiltersFromStorage, neutralizeFilterTokens, saveTraceFiltersToStorage } from './traces/trace-filters.es.js';
|
|
39
43
|
export { CONTEXT_FIELD_IDS } from './traces/types.es.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"traces.es.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"traces.es.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -6,8 +6,8 @@ const jsxRuntime = require('react/jsx-runtime');
|
|
|
6
6
|
const domains_traces_components_spanDataPanelView = require('../../../domains/traces/components/span-data-panel-view.cjs.js');
|
|
7
7
|
const domains_traces_components_traceDetailsView = require('../../../domains/traces/components/trace-details-view.cjs.js');
|
|
8
8
|
const domains_traces_hooks_useSpanDetail = require('../../../domains/traces/hooks/use-span-detail.cjs.js');
|
|
9
|
-
const domains_traces_hooks_useTraceLightSpans = require('../../../domains/traces/hooks/use-trace-light-spans.cjs.js');
|
|
10
9
|
const domains_traces_hooks_useTraceSpanNavigation = require('../../../domains/traces/hooks/use-trace-span-navigation.cjs.js');
|
|
10
|
+
const domains_traces_hooks_useTraceSpans = require('../../../domains/traces/hooks/use-trace-spans.cjs.js');
|
|
11
11
|
const utils_cn = require('../../../cn-vA5sWo9W.cjs');
|
|
12
12
|
|
|
13
13
|
function TopicTraceDetailsPanel({
|
|
@@ -16,7 +16,7 @@ function TopicTraceDetailsPanel({
|
|
|
16
16
|
onSpanSelect,
|
|
17
17
|
onClose
|
|
18
18
|
}) {
|
|
19
|
-
const traceSpans =
|
|
19
|
+
const traceSpans = domains_traces_hooks_useTraceSpans.useTraceSpans(traceId);
|
|
20
20
|
const spanDetail = domains_traces_hooks_useSpanDetail.useSpanDetail(traceId, selectedSpanId);
|
|
21
21
|
const { handlePreviousSpan, handleNextSpan } = domains_traces_hooks_useTraceSpanNavigation.useTraceSpanNavigation(
|
|
22
22
|
traceSpans.data?.spans,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topic-trace-details-panel.cjs.js","sources":["../../../../src/ee/topics/components/topic-trace-details-panel.tsx"],"sourcesContent":["import { SpanDataPanelView } from '@/domains/traces/components/span-data-panel-view';\nimport { TraceDetailsView } from '@/domains/traces/components/trace-details-view';\nimport { useSpanDetail } from '@/domains/traces/hooks/use-span-detail';\nimport {
|
|
1
|
+
{"version":3,"file":"topic-trace-details-panel.cjs.js","sources":["../../../../src/ee/topics/components/topic-trace-details-panel.tsx"],"sourcesContent":["import { SpanDataPanelView } from '@/domains/traces/components/span-data-panel-view';\nimport { TraceDetailsView } from '@/domains/traces/components/trace-details-view';\nimport { useSpanDetail } from '@/domains/traces/hooks/use-span-detail';\nimport { useTraceSpanNavigation } from '@/domains/traces/hooks/use-trace-span-navigation';\nimport { useTraceSpans } from '@/domains/traces/hooks/use-trace-spans';\nimport { cn } from '@/lib/utils';\n\nexport interface TopicTraceDetailsPanelProps {\n traceId: string | null;\n selectedSpanId?: string | null;\n onSpanSelect?: (spanId: string | undefined) => void;\n onClose: () => void;\n}\n\nexport function TopicTraceDetailsPanel({\n traceId,\n selectedSpanId,\n onSpanSelect,\n onClose,\n}: TopicTraceDetailsPanelProps) {\n const traceSpans = useTraceSpans(traceId);\n const spanDetail = useSpanDetail(traceId, selectedSpanId);\n const { handlePreviousSpan, handleNextSpan } = useTraceSpanNavigation(\n traceSpans.data?.spans,\n selectedSpanId,\n spanId => onSpanSelect?.(spanId),\n );\n\n if (!traceId) return null;\n\n return (\n <div\n className={cn(\n 'grid h-full min-h-0 overflow-auto',\n selectedSpanId ? 'grid-rows-[minmax(0,1fr)_minmax(0,1fr)] gap-4' : 'grid-rows-[minmax(0,1fr)]',\n )}\n >\n <TraceDetailsView\n traceId={traceId}\n spans={traceSpans.data?.spans}\n isLoading={traceSpans.isLoading}\n selectedSpanId={selectedSpanId}\n onSpanSelect={onSpanSelect}\n onClose={onClose}\n />\n {selectedSpanId ? (\n <SpanDataPanelView\n traceId={traceId}\n spanId={selectedSpanId}\n span={spanDetail.data?.span}\n isLoading={spanDetail.isLoading}\n onClose={() => onSpanSelect?.(undefined)}\n onPrevious={handlePreviousSpan}\n onNext={handleNextSpan}\n />\n ) : null}\n </div>\n );\n}\n"],"names":["useTraceSpans","useSpanDetail","useTraceSpanNavigation","jsxs","cn","jsx","TraceDetailsView","SpanDataPanelView"],"mappings":";;;;;;;;;;;;AAcO,SAAS,sBAAA,CAAuB;AAAA,EACrC,OAAA;AAAA,EACA,cAAA;AAAA,EACA,YAAA;AAAA,EACA;AACF,CAAA,EAAgC;AAC9B,EAAA,MAAM,UAAA,GAAaA,iDAAc,OAAO,CAAA;AACxC,EAAA,MAAM,UAAA,GAAaC,gDAAA,CAAc,OAAA,EAAS,cAAc,CAAA;AACxD,EAAA,MAAM,EAAE,kBAAA,EAAoB,cAAA,EAAe,GAAIC,kEAAA;AAAA,IAC7C,WAAW,IAAA,EAAM,KAAA;AAAA,IACjB,cAAA;AAAA,IACA,CAAA,MAAA,KAAU,eAAe,MAAM;AAAA,GACjC;AAEA,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAErB,EAAA,uBACEC,eAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAWC,WAAA;AAAA,QACT,mCAAA;AAAA,QACA,iBAAiB,+CAAA,GAAkD;AAAA,OACrE;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAAC,cAAA;AAAA,UAACC,2DAAA;AAAA,UAAA;AAAA,YACC,OAAA;AAAA,YACA,KAAA,EAAO,WAAW,IAAA,EAAM,KAAA;AAAA,YACxB,WAAW,UAAA,CAAW,SAAA;AAAA,YACtB,cAAA;AAAA,YACA,YAAA;AAAA,YACA;AAAA;AAAA,SACF;AAAA,QACC,cAAA,mBACCD,cAAA;AAAA,UAACE,6DAAA;AAAA,UAAA;AAAA,YACC,OAAA;AAAA,YACA,MAAA,EAAQ,cAAA;AAAA,YACR,IAAA,EAAM,WAAW,IAAA,EAAM,IAAA;AAAA,YACvB,WAAW,UAAA,CAAW,SAAA;AAAA,YACtB,OAAA,EAAS,MAAM,YAAA,GAAe,MAAS,CAAA;AAAA,YACvC,UAAA,EAAY,kBAAA;AAAA,YACZ,MAAA,EAAQ;AAAA;AAAA,SACV,GACE;AAAA;AAAA;AAAA,GACN;AAEJ;;;;"}
|
|
@@ -2,8 +2,8 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import { SpanDataPanelView } from '../../../domains/traces/components/span-data-panel-view.es.js';
|
|
3
3
|
import { TraceDetailsView } from '../../../domains/traces/components/trace-details-view.es.js';
|
|
4
4
|
import { useSpanDetail } from '../../../domains/traces/hooks/use-span-detail.es.js';
|
|
5
|
-
import { useTraceLightSpans } from '../../../domains/traces/hooks/use-trace-light-spans.es.js';
|
|
6
5
|
import { useTraceSpanNavigation } from '../../../domains/traces/hooks/use-trace-span-navigation.es.js';
|
|
6
|
+
import { useTraceSpans } from '../../../domains/traces/hooks/use-trace-spans.es.js';
|
|
7
7
|
import { c as cn } from '../../../cn-BakJzhuv.js';
|
|
8
8
|
|
|
9
9
|
function TopicTraceDetailsPanel({
|
|
@@ -12,7 +12,7 @@ function TopicTraceDetailsPanel({
|
|
|
12
12
|
onSpanSelect,
|
|
13
13
|
onClose
|
|
14
14
|
}) {
|
|
15
|
-
const traceSpans =
|
|
15
|
+
const traceSpans = useTraceSpans(traceId);
|
|
16
16
|
const spanDetail = useSpanDetail(traceId, selectedSpanId);
|
|
17
17
|
const { handlePreviousSpan, handleNextSpan } = useTraceSpanNavigation(
|
|
18
18
|
traceSpans.data?.spans,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topic-trace-details-panel.es.js","sources":["../../../../src/ee/topics/components/topic-trace-details-panel.tsx"],"sourcesContent":["import { SpanDataPanelView } from '@/domains/traces/components/span-data-panel-view';\nimport { TraceDetailsView } from '@/domains/traces/components/trace-details-view';\nimport { useSpanDetail } from '@/domains/traces/hooks/use-span-detail';\nimport {
|
|
1
|
+
{"version":3,"file":"topic-trace-details-panel.es.js","sources":["../../../../src/ee/topics/components/topic-trace-details-panel.tsx"],"sourcesContent":["import { SpanDataPanelView } from '@/domains/traces/components/span-data-panel-view';\nimport { TraceDetailsView } from '@/domains/traces/components/trace-details-view';\nimport { useSpanDetail } from '@/domains/traces/hooks/use-span-detail';\nimport { useTraceSpanNavigation } from '@/domains/traces/hooks/use-trace-span-navigation';\nimport { useTraceSpans } from '@/domains/traces/hooks/use-trace-spans';\nimport { cn } from '@/lib/utils';\n\nexport interface TopicTraceDetailsPanelProps {\n traceId: string | null;\n selectedSpanId?: string | null;\n onSpanSelect?: (spanId: string | undefined) => void;\n onClose: () => void;\n}\n\nexport function TopicTraceDetailsPanel({\n traceId,\n selectedSpanId,\n onSpanSelect,\n onClose,\n}: TopicTraceDetailsPanelProps) {\n const traceSpans = useTraceSpans(traceId);\n const spanDetail = useSpanDetail(traceId, selectedSpanId);\n const { handlePreviousSpan, handleNextSpan } = useTraceSpanNavigation(\n traceSpans.data?.spans,\n selectedSpanId,\n spanId => onSpanSelect?.(spanId),\n );\n\n if (!traceId) return null;\n\n return (\n <div\n className={cn(\n 'grid h-full min-h-0 overflow-auto',\n selectedSpanId ? 'grid-rows-[minmax(0,1fr)_minmax(0,1fr)] gap-4' : 'grid-rows-[minmax(0,1fr)]',\n )}\n >\n <TraceDetailsView\n traceId={traceId}\n spans={traceSpans.data?.spans}\n isLoading={traceSpans.isLoading}\n selectedSpanId={selectedSpanId}\n onSpanSelect={onSpanSelect}\n onClose={onClose}\n />\n {selectedSpanId ? (\n <SpanDataPanelView\n traceId={traceId}\n spanId={selectedSpanId}\n span={spanDetail.data?.span}\n isLoading={spanDetail.isLoading}\n onClose={() => onSpanSelect?.(undefined)}\n onPrevious={handlePreviousSpan}\n onNext={handleNextSpan}\n />\n ) : null}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AAcO,SAAS,sBAAA,CAAuB;AAAA,EACrC,OAAA;AAAA,EACA,cAAA;AAAA,EACA,YAAA;AAAA,EACA;AACF,CAAA,EAAgC;AAC9B,EAAA,MAAM,UAAA,GAAa,cAAc,OAAO,CAAA;AACxC,EAAA,MAAM,UAAA,GAAa,aAAA,CAAc,OAAA,EAAS,cAAc,CAAA;AACxD,EAAA,MAAM,EAAE,kBAAA,EAAoB,cAAA,EAAe,GAAI,sBAAA;AAAA,IAC7C,WAAW,IAAA,EAAM,KAAA;AAAA,IACjB,cAAA;AAAA,IACA,CAAA,MAAA,KAAU,eAAe,MAAM;AAAA,GACjC;AAEA,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAErB,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA;AAAA,QACT,mCAAA;AAAA,QACA,iBAAiB,+CAAA,GAAkD;AAAA,OACrE;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,gBAAA;AAAA,UAAA;AAAA,YACC,OAAA;AAAA,YACA,KAAA,EAAO,WAAW,IAAA,EAAM,KAAA;AAAA,YACxB,WAAW,UAAA,CAAW,SAAA;AAAA,YACtB,cAAA;AAAA,YACA,YAAA;AAAA,YACA;AAAA;AAAA,SACF;AAAA,QACC,cAAA,mBACC,GAAA;AAAA,UAAC,iBAAA;AAAA,UAAA;AAAA,YACC,OAAA;AAAA,YACA,MAAA,EAAQ,cAAA;AAAA,YACR,IAAA,EAAM,WAAW,IAAA,EAAM,IAAA;AAAA,YACvB,WAAW,UAAA,CAAW,SAAA;AAAA,YACtB,OAAA,EAAS,MAAM,YAAA,GAAe,MAAS,CAAA;AAAA,YACvC,UAAA,EAAY,kBAAA;AAAA,YACZ,MAAA,EAAQ;AAAA;AAAA,SACV,GACE;AAAA;AAAA;AAAA,GACN;AAEJ;;;;"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
+
|
|
5
|
+
require('../use-text-highlight.css');const React = require('react');
|
|
6
|
+
const hooks_useIsomorphicLayoutEffect = require('./use-isomorphic-layout-effect.cjs.js');
|
|
7
|
+
|
|
8
|
+
const HIGHLIGHT_NAME = "search-result";
|
|
9
|
+
const MIN_SEARCH_LENGTH = 2;
|
|
10
|
+
const INCLUDED_SELECTOR = "[data-highlight]";
|
|
11
|
+
function escapeRegExp(value) {
|
|
12
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
13
|
+
}
|
|
14
|
+
function useTextHighlight(search) {
|
|
15
|
+
const [root, setRoot] = React.useState(null);
|
|
16
|
+
hooks_useIsomorphicLayoutEffect.useIsomorphicLayoutEffect(() => {
|
|
17
|
+
if (!root || search.trim().length < MIN_SEARCH_LENGTH || typeof CSS === "undefined" || !("highlights" in CSS) || typeof StaticRange === "undefined") {
|
|
18
|
+
CSS?.highlights?.delete(HIGHLIGHT_NAME);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
let animationFrame = null;
|
|
22
|
+
const updateHighlight = () => {
|
|
23
|
+
const ranges = [];
|
|
24
|
+
const regex = new RegExp(escapeRegExp(search), "giu");
|
|
25
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
|
|
26
|
+
acceptNode(node) {
|
|
27
|
+
const parent = node.parentElement;
|
|
28
|
+
return parent.closest(INCLUDED_SELECTOR) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
while (walker.nextNode()) {
|
|
32
|
+
const textNode = walker.currentNode;
|
|
33
|
+
regex.lastIndex = 0;
|
|
34
|
+
let match;
|
|
35
|
+
while ((match = regex.exec(textNode.data)) !== null) {
|
|
36
|
+
ranges.push(
|
|
37
|
+
new StaticRange({
|
|
38
|
+
startContainer: textNode,
|
|
39
|
+
startOffset: match.index,
|
|
40
|
+
endContainer: textNode,
|
|
41
|
+
endOffset: match.index + match[0].length
|
|
42
|
+
})
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
CSS.highlights.set(HIGHLIGHT_NAME, new Highlight(...ranges));
|
|
47
|
+
};
|
|
48
|
+
const scheduleUpdate = () => {
|
|
49
|
+
if (animationFrame !== null) cancelAnimationFrame(animationFrame);
|
|
50
|
+
animationFrame = requestAnimationFrame(() => {
|
|
51
|
+
animationFrame = null;
|
|
52
|
+
updateHighlight();
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
updateHighlight();
|
|
56
|
+
const observer = new MutationObserver(scheduleUpdate);
|
|
57
|
+
observer.observe(root, { subtree: true, childList: true, characterData: true });
|
|
58
|
+
return () => {
|
|
59
|
+
observer.disconnect();
|
|
60
|
+
if (animationFrame !== null) cancelAnimationFrame(animationFrame);
|
|
61
|
+
CSS.highlights.delete(HIGHLIGHT_NAME);
|
|
62
|
+
};
|
|
63
|
+
}, [root, search]);
|
|
64
|
+
return { ref: setRoot };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
exports.useTextHighlight = useTextHighlight;
|
|
68
|
+
//# sourceMappingURL=use-text-highlight.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-text-highlight.cjs.js","sources":["../../src/hooks/use-text-highlight.ts"],"sourcesContent":["import { useState } from 'react';\nimport type { RefCallback } from 'react';\n\nimport { useIsomorphicLayoutEffect } from './use-isomorphic-layout-effect';\nimport './use-text-highlight.css';\n\n/** Single registry entry, so only one search surface can be highlighted at a time. */\nconst HIGHLIGHT_NAME = 'search-result';\n\n/**\n * A single character matches almost everywhere, which paints noise instead of results.\n * Highlighting only starts once the term is discriminating enough.\n */\nconst MIN_SEARCH_LENGTH = 2;\n\n/**\n * Opt-in marker: only text inside a `data-highlight` subtree can be painted. Highlighting\n * is a claim about which text is searchable, so surfaces state it explicitly rather than\n * having every piece of surrounding chrome remember to opt out.\n */\nconst INCLUDED_SELECTOR = '[data-highlight]';\n\nfunction escapeRegExp(value: string) {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport interface UseTextHighlightResult<TElement extends HTMLElement> {\n ref: RefCallback<TElement>;\n}\n\n/**\n * Paints every occurrence of `search` inside the referenced subtree using the CSS Custom\n * Highlight API. Only text under an element carrying `data-highlight` is painted, so a\n * surface names its searchable regions and everything else — headers, labels, metadata —\n * is left alone by default. The DOM is never mutated — no wrapper elements are injected — so text\n * selection, copy/paste and virtualised renderers are unaffected. Styling lives in\n * `use-text-highlight.css` (`::highlight(search-result)`).\n *\n * Terms shorter than two characters are ignored — they match too much to be useful.\n * Matching is case-insensitive and literal (the term is escaped, not a pattern). The\n * subtree is re-scanned on content changes, coalesced to one scan per frame. Browsers\n * without the API simply render nothing highlighted.\n */\nexport function useTextHighlight<TElement extends HTMLElement = HTMLElement>(\n search: string,\n): UseTextHighlightResult<TElement> {\n const [root, setRoot] = useState<TElement | null>(null);\n\n useIsomorphicLayoutEffect(() => {\n if (\n !root ||\n search.trim().length < MIN_SEARCH_LENGTH ||\n typeof CSS === 'undefined' ||\n !('highlights' in CSS) ||\n typeof StaticRange === 'undefined'\n ) {\n CSS?.highlights?.delete(HIGHLIGHT_NAME);\n return;\n }\n\n let animationFrame: number | null = null;\n\n const updateHighlight = () => {\n const ranges: StaticRange[] = [];\n const regex = new RegExp(escapeRegExp(search), 'giu');\n\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {\n acceptNode(node) {\n // Inside a rooted walker every text node has a parent element.\n const parent = node.parentElement as HTMLElement;\n return parent.closest(INCLUDED_SELECTOR) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;\n },\n });\n\n while (walker.nextNode()) {\n const textNode = walker.currentNode as Text;\n regex.lastIndex = 0;\n\n let match: RegExpExecArray | null;\n while ((match = regex.exec(textNode.data)) !== null) {\n ranges.push(\n new StaticRange({\n startContainer: textNode,\n startOffset: match.index,\n endContainer: textNode,\n endOffset: match.index + match[0].length,\n }),\n );\n }\n }\n\n CSS.highlights.set(HIGHLIGHT_NAME, new Highlight(...ranges));\n };\n\n const scheduleUpdate = () => {\n if (animationFrame !== null) cancelAnimationFrame(animationFrame);\n\n animationFrame = requestAnimationFrame(() => {\n animationFrame = null;\n updateHighlight();\n });\n };\n\n updateHighlight();\n\n const observer = new MutationObserver(scheduleUpdate);\n observer.observe(root, { subtree: true, childList: true, characterData: true });\n\n return () => {\n observer.disconnect();\n if (animationFrame !== null) cancelAnimationFrame(animationFrame);\n CSS.highlights.delete(HIGHLIGHT_NAME);\n };\n }, [root, search]);\n\n return { ref: setRoot };\n}\n"],"names":["useState","useIsomorphicLayoutEffect"],"mappings":";;;;;;;AAOA,MAAM,cAAA,GAAiB,eAAA;AAMvB,MAAM,iBAAA,GAAoB,CAAA;AAO1B,MAAM,iBAAA,GAAoB,kBAAA;AAE1B,SAAS,aAAa,KAAA,EAAe;AACnC,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,qBAAA,EAAuB,MAAM,CAAA;AACpD;AAmBO,SAAS,iBACd,MAAA,EACkC;AAClC,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIA,eAA0B,IAAI,CAAA;AAEtD,EAAAC,yDAAA,CAA0B,MAAM;AAC9B,IAAA,IACE,CAAC,IAAA,IACD,MAAA,CAAO,IAAA,GAAO,MAAA,GAAS,iBAAA,IACvB,OAAO,GAAA,KAAQ,eACf,EAAE,YAAA,IAAgB,GAAA,CAAA,IAClB,OAAO,gBAAgB,WAAA,EACvB;AACA,MAAA,GAAA,EAAK,UAAA,EAAY,OAAO,cAAc,CAAA;AACtC,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,cAAA,GAAgC,IAAA;AAEpC,IAAA,MAAM,kBAAkB,MAAM;AAC5B,MAAA,MAAM,SAAwB,EAAC;AAC/B,MAAA,MAAM,QAAQ,IAAI,MAAA,CAAO,YAAA,CAAa,MAAM,GAAG,KAAK,CAAA;AAEpD,MAAA,MAAM,MAAA,GAAS,QAAA,CAAS,gBAAA,CAAiB,IAAA,EAAM,WAAW,SAAA,EAAW;AAAA,QACnE,WAAW,IAAA,EAAM;AAEf,UAAA,MAAM,SAAS,IAAA,CAAK,aAAA;AACpB,UAAA,OAAO,OAAO,OAAA,CAAQ,iBAAiB,CAAA,GAAI,UAAA,CAAW,gBAAgB,UAAA,CAAW,aAAA;AAAA,QACnF;AAAA,OACD,CAAA;AAED,MAAA,OAAO,MAAA,CAAO,UAAS,EAAG;AACxB,QAAA,MAAM,WAAW,MAAA,CAAO,WAAA;AACxB,QAAA,KAAA,CAAM,SAAA,GAAY,CAAA;AAElB,QAAA,IAAI,KAAA;AACJ,QAAA,OAAA,CAAQ,QAAQ,KAAA,CAAM,IAAA,CAAK,QAAA,CAAS,IAAI,OAAO,IAAA,EAAM;AACnD,UAAA,MAAA,CAAO,IAAA;AAAA,YACL,IAAI,WAAA,CAAY;AAAA,cACd,cAAA,EAAgB,QAAA;AAAA,cAChB,aAAa,KAAA,CAAM,KAAA;AAAA,cACnB,YAAA,EAAc,QAAA;AAAA,cACd,SAAA,EAAW,KAAA,CAAM,KAAA,GAAQ,KAAA,CAAM,CAAC,CAAA,CAAE;AAAA,aACnC;AAAA,WACH;AAAA,QACF;AAAA,MACF;AAEA,MAAA,GAAA,CAAI,WAAW,GAAA,CAAI,cAAA,EAAgB,IAAI,SAAA,CAAU,GAAG,MAAM,CAAC,CAAA;AAAA,IAC7D,CAAA;AAEA,IAAA,MAAM,iBAAiB,MAAM;AAC3B,MAAA,IAAI,cAAA,KAAmB,IAAA,EAAM,oBAAA,CAAqB,cAAc,CAAA;AAEhE,MAAA,cAAA,GAAiB,sBAAsB,MAAM;AAC3C,QAAA,cAAA,GAAiB,IAAA;AACjB,QAAA,eAAA,EAAgB;AAAA,MAClB,CAAC,CAAA;AAAA,IACH,CAAA;AAEA,IAAA,eAAA,EAAgB;AAEhB,IAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,cAAc,CAAA;AACpD,IAAA,QAAA,CAAS,OAAA,CAAQ,MAAM,EAAE,OAAA,EAAS,MAAM,SAAA,EAAW,IAAA,EAAM,aAAA,EAAe,IAAA,EAAM,CAAA;AAE9E,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,UAAA,EAAW;AACpB,MAAA,IAAI,cAAA,KAAmB,IAAA,EAAM,oBAAA,CAAqB,cAAc,CAAA;AAChE,MAAA,GAAA,CAAI,UAAA,CAAW,OAAO,cAAc,CAAA;AAAA,IACtC,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAA,EAAM,MAAM,CAAC,CAAA;AAEjB,EAAA,OAAO,EAAE,KAAK,OAAA,EAAQ;AACxB;;;;"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { useIsomorphicLayoutEffect } from './use-isomorphic-layout-effect.es.js';
|
|
3
|
+
|
|
4
|
+
import '../use-text-highlight.css';const HIGHLIGHT_NAME = "search-result";
|
|
5
|
+
const MIN_SEARCH_LENGTH = 2;
|
|
6
|
+
const INCLUDED_SELECTOR = "[data-highlight]";
|
|
7
|
+
function escapeRegExp(value) {
|
|
8
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9
|
+
}
|
|
10
|
+
function useTextHighlight(search) {
|
|
11
|
+
const [root, setRoot] = useState(null);
|
|
12
|
+
useIsomorphicLayoutEffect(() => {
|
|
13
|
+
if (!root || search.trim().length < MIN_SEARCH_LENGTH || typeof CSS === "undefined" || !("highlights" in CSS) || typeof StaticRange === "undefined") {
|
|
14
|
+
CSS?.highlights?.delete(HIGHLIGHT_NAME);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
let animationFrame = null;
|
|
18
|
+
const updateHighlight = () => {
|
|
19
|
+
const ranges = [];
|
|
20
|
+
const regex = new RegExp(escapeRegExp(search), "giu");
|
|
21
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
|
|
22
|
+
acceptNode(node) {
|
|
23
|
+
const parent = node.parentElement;
|
|
24
|
+
return parent.closest(INCLUDED_SELECTOR) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
while (walker.nextNode()) {
|
|
28
|
+
const textNode = walker.currentNode;
|
|
29
|
+
regex.lastIndex = 0;
|
|
30
|
+
let match;
|
|
31
|
+
while ((match = regex.exec(textNode.data)) !== null) {
|
|
32
|
+
ranges.push(
|
|
33
|
+
new StaticRange({
|
|
34
|
+
startContainer: textNode,
|
|
35
|
+
startOffset: match.index,
|
|
36
|
+
endContainer: textNode,
|
|
37
|
+
endOffset: match.index + match[0].length
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
CSS.highlights.set(HIGHLIGHT_NAME, new Highlight(...ranges));
|
|
43
|
+
};
|
|
44
|
+
const scheduleUpdate = () => {
|
|
45
|
+
if (animationFrame !== null) cancelAnimationFrame(animationFrame);
|
|
46
|
+
animationFrame = requestAnimationFrame(() => {
|
|
47
|
+
animationFrame = null;
|
|
48
|
+
updateHighlight();
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
updateHighlight();
|
|
52
|
+
const observer = new MutationObserver(scheduleUpdate);
|
|
53
|
+
observer.observe(root, { subtree: true, childList: true, characterData: true });
|
|
54
|
+
return () => {
|
|
55
|
+
observer.disconnect();
|
|
56
|
+
if (animationFrame !== null) cancelAnimationFrame(animationFrame);
|
|
57
|
+
CSS.highlights.delete(HIGHLIGHT_NAME);
|
|
58
|
+
};
|
|
59
|
+
}, [root, search]);
|
|
60
|
+
return { ref: setRoot };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { useTextHighlight };
|
|
64
|
+
//# sourceMappingURL=use-text-highlight.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-text-highlight.es.js","sources":["../../src/hooks/use-text-highlight.ts"],"sourcesContent":["import { useState } from 'react';\nimport type { RefCallback } from 'react';\n\nimport { useIsomorphicLayoutEffect } from './use-isomorphic-layout-effect';\nimport './use-text-highlight.css';\n\n/** Single registry entry, so only one search surface can be highlighted at a time. */\nconst HIGHLIGHT_NAME = 'search-result';\n\n/**\n * A single character matches almost everywhere, which paints noise instead of results.\n * Highlighting only starts once the term is discriminating enough.\n */\nconst MIN_SEARCH_LENGTH = 2;\n\n/**\n * Opt-in marker: only text inside a `data-highlight` subtree can be painted. Highlighting\n * is a claim about which text is searchable, so surfaces state it explicitly rather than\n * having every piece of surrounding chrome remember to opt out.\n */\nconst INCLUDED_SELECTOR = '[data-highlight]';\n\nfunction escapeRegExp(value: string) {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport interface UseTextHighlightResult<TElement extends HTMLElement> {\n ref: RefCallback<TElement>;\n}\n\n/**\n * Paints every occurrence of `search` inside the referenced subtree using the CSS Custom\n * Highlight API. Only text under an element carrying `data-highlight` is painted, so a\n * surface names its searchable regions and everything else — headers, labels, metadata —\n * is left alone by default. The DOM is never mutated — no wrapper elements are injected — so text\n * selection, copy/paste and virtualised renderers are unaffected. Styling lives in\n * `use-text-highlight.css` (`::highlight(search-result)`).\n *\n * Terms shorter than two characters are ignored — they match too much to be useful.\n * Matching is case-insensitive and literal (the term is escaped, not a pattern). The\n * subtree is re-scanned on content changes, coalesced to one scan per frame. Browsers\n * without the API simply render nothing highlighted.\n */\nexport function useTextHighlight<TElement extends HTMLElement = HTMLElement>(\n search: string,\n): UseTextHighlightResult<TElement> {\n const [root, setRoot] = useState<TElement | null>(null);\n\n useIsomorphicLayoutEffect(() => {\n if (\n !root ||\n search.trim().length < MIN_SEARCH_LENGTH ||\n typeof CSS === 'undefined' ||\n !('highlights' in CSS) ||\n typeof StaticRange === 'undefined'\n ) {\n CSS?.highlights?.delete(HIGHLIGHT_NAME);\n return;\n }\n\n let animationFrame: number | null = null;\n\n const updateHighlight = () => {\n const ranges: StaticRange[] = [];\n const regex = new RegExp(escapeRegExp(search), 'giu');\n\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {\n acceptNode(node) {\n // Inside a rooted walker every text node has a parent element.\n const parent = node.parentElement as HTMLElement;\n return parent.closest(INCLUDED_SELECTOR) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;\n },\n });\n\n while (walker.nextNode()) {\n const textNode = walker.currentNode as Text;\n regex.lastIndex = 0;\n\n let match: RegExpExecArray | null;\n while ((match = regex.exec(textNode.data)) !== null) {\n ranges.push(\n new StaticRange({\n startContainer: textNode,\n startOffset: match.index,\n endContainer: textNode,\n endOffset: match.index + match[0].length,\n }),\n );\n }\n }\n\n CSS.highlights.set(HIGHLIGHT_NAME, new Highlight(...ranges));\n };\n\n const scheduleUpdate = () => {\n if (animationFrame !== null) cancelAnimationFrame(animationFrame);\n\n animationFrame = requestAnimationFrame(() => {\n animationFrame = null;\n updateHighlight();\n });\n };\n\n updateHighlight();\n\n const observer = new MutationObserver(scheduleUpdate);\n observer.observe(root, { subtree: true, childList: true, characterData: true });\n\n return () => {\n observer.disconnect();\n if (animationFrame !== null) cancelAnimationFrame(animationFrame);\n CSS.highlights.delete(HIGHLIGHT_NAME);\n };\n }, [root, search]);\n\n return { ref: setRoot };\n}\n"],"names":[],"mappings":";;;AAOA,MAAM,cAAA,GAAiB,eAAA;AAMvB,MAAM,iBAAA,GAAoB,CAAA;AAO1B,MAAM,iBAAA,GAAoB,kBAAA;AAE1B,SAAS,aAAa,KAAA,EAAe;AACnC,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,qBAAA,EAAuB,MAAM,CAAA;AACpD;AAmBO,SAAS,iBACd,MAAA,EACkC;AAClC,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAA0B,IAAI,CAAA;AAEtD,EAAA,yBAAA,CAA0B,MAAM;AAC9B,IAAA,IACE,CAAC,IAAA,IACD,MAAA,CAAO,IAAA,GAAO,MAAA,GAAS,iBAAA,IACvB,OAAO,GAAA,KAAQ,eACf,EAAE,YAAA,IAAgB,GAAA,CAAA,IAClB,OAAO,gBAAgB,WAAA,EACvB;AACA,MAAA,GAAA,EAAK,UAAA,EAAY,OAAO,cAAc,CAAA;AACtC,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,cAAA,GAAgC,IAAA;AAEpC,IAAA,MAAM,kBAAkB,MAAM;AAC5B,MAAA,MAAM,SAAwB,EAAC;AAC/B,MAAA,MAAM,QAAQ,IAAI,MAAA,CAAO,YAAA,CAAa,MAAM,GAAG,KAAK,CAAA;AAEpD,MAAA,MAAM,MAAA,GAAS,QAAA,CAAS,gBAAA,CAAiB,IAAA,EAAM,WAAW,SAAA,EAAW;AAAA,QACnE,WAAW,IAAA,EAAM;AAEf,UAAA,MAAM,SAAS,IAAA,CAAK,aAAA;AACpB,UAAA,OAAO,OAAO,OAAA,CAAQ,iBAAiB,CAAA,GAAI,UAAA,CAAW,gBAAgB,UAAA,CAAW,aAAA;AAAA,QACnF;AAAA,OACD,CAAA;AAED,MAAA,OAAO,MAAA,CAAO,UAAS,EAAG;AACxB,QAAA,MAAM,WAAW,MAAA,CAAO,WAAA;AACxB,QAAA,KAAA,CAAM,SAAA,GAAY,CAAA;AAElB,QAAA,IAAI,KAAA;AACJ,QAAA,OAAA,CAAQ,QAAQ,KAAA,CAAM,IAAA,CAAK,QAAA,CAAS,IAAI,OAAO,IAAA,EAAM;AACnD,UAAA,MAAA,CAAO,IAAA;AAAA,YACL,IAAI,WAAA,CAAY;AAAA,cACd,cAAA,EAAgB,QAAA;AAAA,cAChB,aAAa,KAAA,CAAM,KAAA;AAAA,cACnB,YAAA,EAAc,QAAA;AAAA,cACd,SAAA,EAAW,KAAA,CAAM,KAAA,GAAQ,KAAA,CAAM,CAAC,CAAA,CAAE;AAAA,aACnC;AAAA,WACH;AAAA,QACF;AAAA,MACF;AAEA,MAAA,GAAA,CAAI,WAAW,GAAA,CAAI,cAAA,EAAgB,IAAI,SAAA,CAAU,GAAG,MAAM,CAAC,CAAA;AAAA,IAC7D,CAAA;AAEA,IAAA,MAAM,iBAAiB,MAAM;AAC3B,MAAA,IAAI,cAAA,KAAmB,IAAA,EAAM,oBAAA,CAAqB,cAAc,CAAA;AAEhE,MAAA,cAAA,GAAiB,sBAAsB,MAAM;AAC3C,QAAA,cAAA,GAAiB,IAAA;AACjB,QAAA,eAAA,EAAgB;AAAA,MAClB,CAAC,CAAA;AAAA,IACH,CAAA;AAEA,IAAA,eAAA,EAAgB;AAEhB,IAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,cAAc,CAAA;AACpD,IAAA,QAAA,CAAS,OAAA,CAAQ,MAAM,EAAE,OAAA,EAAS,MAAM,SAAA,EAAW,IAAA,EAAM,aAAA,EAAe,IAAA,EAAM,CAAA;AAE9E,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,UAAA,EAAW;AACpB,MAAA,IAAI,cAAA,KAAmB,IAAA,EAAM,oBAAA,CAAqB,cAAc,CAAA;AAChE,MAAA,GAAA,CAAI,UAAA,CAAW,OAAO,cAAc,CAAA;AAAA,IACtC,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAA,EAAM,MAAM,CAAC,CAAA;AAEjB,EAAA,OAAO,EAAE,KAAK,OAAA,EAAQ;AACxB;;;;"}
|
|
@@ -26,9 +26,14 @@ function SearchFieldBlock({
|
|
|
26
26
|
size,
|
|
27
27
|
variant,
|
|
28
28
|
isMinimized,
|
|
29
|
-
onMinimizedChange
|
|
29
|
+
onMinimizedChange,
|
|
30
|
+
inputRef: externalInputRef
|
|
30
31
|
}) {
|
|
31
32
|
const inputRef = React.useRef(null);
|
|
33
|
+
const setInputRef = (element) => {
|
|
34
|
+
inputRef.current = element;
|
|
35
|
+
if (externalInputRef) externalInputRef.current = element;
|
|
36
|
+
};
|
|
32
37
|
const buttonSize = size === "default" ? "lg" : size;
|
|
33
38
|
React.useEffect(() => {
|
|
34
39
|
if (isMinimized === false) {
|
|
@@ -58,7 +63,7 @@ function SearchFieldBlock({
|
|
|
58
63
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
59
64
|
input.Input,
|
|
60
65
|
{
|
|
61
|
-
ref:
|
|
66
|
+
ref: setInputRef,
|
|
62
67
|
id: `input-${name}`,
|
|
63
68
|
name,
|
|
64
69
|
disabled,
|
|
@@ -114,4 +119,4 @@ function SearchFieldBlock({
|
|
|
114
119
|
}
|
|
115
120
|
|
|
116
121
|
exports.SearchFieldBlock = SearchFieldBlock;
|
|
117
|
-
//# sourceMappingURL=search-field-block-
|
|
122
|
+
//# sourceMappingURL=search-field-block-CjCIzUhN.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-field-block-CjCIzUhN.cjs","sources":["../src/ds/components/FormFieldBlocks/fields/search-field-block.tsx"],"sourcesContent":["import { SearchIcon, XIcon } from 'lucide-react';\nimport { useEffect, useRef, type RefObject } from 'react';\nimport { Button } from '../../Button';\nimport { Input } from '../../Input';\nimport type { InputProps } from '../../Input';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../../Tooltip';\nimport { FieldBlock } from '../block/field-block';\nimport { cn } from '@/lib/utils';\n\nexport type SearchFieldBlockProps = {\n name: string;\n testId?: string;\n label?: string;\n labelIsHidden?: boolean;\n required?: boolean;\n disabled?: boolean;\n value?: string;\n placeholder?: string;\n onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;\n onReset?: () => void;\n helpText?: string;\n error?: boolean;\n errorMsg?: string;\n layout?: 'horizontal' | 'vertical';\n className?: string;\n size?: InputProps['size'];\n variant?: InputProps['variant'];\n isMinimized?: boolean;\n onMinimizedChange?: (minimized: boolean) => void;\n /** Gives the caller access to the underlying input, e.g. to focus it from a keyboard shortcut. */\n inputRef?: RefObject<HTMLInputElement | null>;\n};\n\nexport function SearchFieldBlock({\n name,\n helpText,\n errorMsg,\n required = false,\n disabled = false,\n value,\n label,\n labelIsHidden = false,\n layout = 'vertical',\n placeholder = 'Search...',\n onChange,\n onReset,\n className,\n size,\n variant,\n isMinimized,\n onMinimizedChange,\n inputRef: externalInputRef,\n}: SearchFieldBlockProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n\n const setInputRef = (element: HTMLInputElement | null) => {\n inputRef.current = element;\n if (externalInputRef) externalInputRef.current = element;\n };\n const buttonSize = size === 'default' ? 'lg' : size;\n\n useEffect(() => {\n if (isMinimized === false) {\n inputRef.current?.focus();\n }\n }, [isMinimized]);\n\n if (isMinimized) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n size={buttonSize || 'sm'}\n aria-label={label || 'Search'}\n disabled={disabled}\n onClick={() => onMinimizedChange?.(false)}\n >\n <SearchIcon />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{label || 'Search'}</TooltipContent>\n </Tooltip>\n );\n }\n\n return (\n <FieldBlock.Layout layout={layout} className={className}>\n {layout === 'horizontal' ? (\n <FieldBlock.Column className={labelIsHidden ? 'sr-only' : undefined}>\n <FieldBlock.Label name={name} required={required}>\n {label}\n </FieldBlock.Label>\n </FieldBlock.Column>\n ) : null}\n <FieldBlock.Column className={layout === 'horizontal' && labelIsHidden ? 'col-span-full' : undefined}>\n {layout === 'vertical' && label ? (\n <FieldBlock.Label name={name} required={required} className={labelIsHidden ? 'sr-only' : undefined}>\n {label}\n </FieldBlock.Label>\n ) : null}\n <div className=\"group relative\">\n <Input\n ref={setInputRef}\n id={`input-${name}`}\n name={name}\n disabled={disabled}\n value={value}\n placeholder={placeholder}\n onChange={onChange}\n size={size}\n variant={variant}\n className={cn(\n size === 'sm' && 'px-8',\n size === 'md' && 'px-9',\n (!size || size === 'default') && 'px-10',\n size === 'lg' && 'px-11',\n )}\n />\n <SearchIcon\n aria-hidden=\"true\"\n className={cn(\n 'absolute top-1/2 left-3 -translate-y-1/2 text-neutral4 opacity-50 group-has-focus:opacity-100',\n size === 'sm' && 'size-3.5',\n size === 'md' && 'size-4',\n (!size || size === 'default') && 'size-[1.125rem]',\n size === 'lg' && 'size-5',\n )}\n />\n {onReset && (value || isMinimized === false) && (\n <Button\n variant=\"ghost\"\n size={buttonSize || 'lg'}\n aria-label=\"Clear search\"\n onClick={() => {\n if (value) {\n onReset();\n }\n if (isMinimized === false) {\n onMinimizedChange?.(true);\n }\n }}\n className=\"absolute top-1/2 right-0 -translate-y-1/2\"\n >\n <XIcon />\n </Button>\n )}\n </div>\n {helpText && <FieldBlock.HelpText>{helpText}</FieldBlock.HelpText>}\n {errorMsg && <FieldBlock.ErrorMsg>{errorMsg}</FieldBlock.ErrorMsg>}\n </FieldBlock.Column>\n </FieldBlock.Layout>\n );\n}\n"],"names":["useRef","useEffect","Tooltip","jsx","TooltipTrigger","Button","SearchIcon","TooltipContent","jsxs","FieldBlock","Input","cn","XIcon"],"mappings":"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"}
|
|
@@ -24,9 +24,14 @@ function SearchFieldBlock({
|
|
|
24
24
|
size,
|
|
25
25
|
variant,
|
|
26
26
|
isMinimized,
|
|
27
|
-
onMinimizedChange
|
|
27
|
+
onMinimizedChange,
|
|
28
|
+
inputRef: externalInputRef
|
|
28
29
|
}) {
|
|
29
30
|
const inputRef = useRef(null);
|
|
31
|
+
const setInputRef = (element) => {
|
|
32
|
+
inputRef.current = element;
|
|
33
|
+
if (externalInputRef) externalInputRef.current = element;
|
|
34
|
+
};
|
|
30
35
|
const buttonSize = size === "default" ? "lg" : size;
|
|
31
36
|
useEffect(() => {
|
|
32
37
|
if (isMinimized === false) {
|
|
@@ -56,7 +61,7 @@ function SearchFieldBlock({
|
|
|
56
61
|
/* @__PURE__ */ jsx(
|
|
57
62
|
Input,
|
|
58
63
|
{
|
|
59
|
-
ref:
|
|
64
|
+
ref: setInputRef,
|
|
60
65
|
id: `input-${name}`,
|
|
61
66
|
name,
|
|
62
67
|
disabled,
|
|
@@ -112,4 +117,4 @@ function SearchFieldBlock({
|
|
|
112
117
|
}
|
|
113
118
|
|
|
114
119
|
export { SearchFieldBlock as S };
|
|
115
|
-
//# sourceMappingURL=search-field-block-
|
|
120
|
+
//# sourceMappingURL=search-field-block-DoNywsJC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-field-block-DoNywsJC.js","sources":["../src/ds/components/FormFieldBlocks/fields/search-field-block.tsx"],"sourcesContent":["import { SearchIcon, XIcon } from 'lucide-react';\nimport { useEffect, useRef, type RefObject } from 'react';\nimport { Button } from '../../Button';\nimport { Input } from '../../Input';\nimport type { InputProps } from '../../Input';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../../Tooltip';\nimport { FieldBlock } from '../block/field-block';\nimport { cn } from '@/lib/utils';\n\nexport type SearchFieldBlockProps = {\n name: string;\n testId?: string;\n label?: string;\n labelIsHidden?: boolean;\n required?: boolean;\n disabled?: boolean;\n value?: string;\n placeholder?: string;\n onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;\n onReset?: () => void;\n helpText?: string;\n error?: boolean;\n errorMsg?: string;\n layout?: 'horizontal' | 'vertical';\n className?: string;\n size?: InputProps['size'];\n variant?: InputProps['variant'];\n isMinimized?: boolean;\n onMinimizedChange?: (minimized: boolean) => void;\n /** Gives the caller access to the underlying input, e.g. to focus it from a keyboard shortcut. */\n inputRef?: RefObject<HTMLInputElement | null>;\n};\n\nexport function SearchFieldBlock({\n name,\n helpText,\n errorMsg,\n required = false,\n disabled = false,\n value,\n label,\n labelIsHidden = false,\n layout = 'vertical',\n placeholder = 'Search...',\n onChange,\n onReset,\n className,\n size,\n variant,\n isMinimized,\n onMinimizedChange,\n inputRef: externalInputRef,\n}: SearchFieldBlockProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n\n const setInputRef = (element: HTMLInputElement | null) => {\n inputRef.current = element;\n if (externalInputRef) externalInputRef.current = element;\n };\n const buttonSize = size === 'default' ? 'lg' : size;\n\n useEffect(() => {\n if (isMinimized === false) {\n inputRef.current?.focus();\n }\n }, [isMinimized]);\n\n if (isMinimized) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n size={buttonSize || 'sm'}\n aria-label={label || 'Search'}\n disabled={disabled}\n onClick={() => onMinimizedChange?.(false)}\n >\n <SearchIcon />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{label || 'Search'}</TooltipContent>\n </Tooltip>\n );\n }\n\n return (\n <FieldBlock.Layout layout={layout} className={className}>\n {layout === 'horizontal' ? (\n <FieldBlock.Column className={labelIsHidden ? 'sr-only' : undefined}>\n <FieldBlock.Label name={name} required={required}>\n {label}\n </FieldBlock.Label>\n </FieldBlock.Column>\n ) : null}\n <FieldBlock.Column className={layout === 'horizontal' && labelIsHidden ? 'col-span-full' : undefined}>\n {layout === 'vertical' && label ? (\n <FieldBlock.Label name={name} required={required} className={labelIsHidden ? 'sr-only' : undefined}>\n {label}\n </FieldBlock.Label>\n ) : null}\n <div className=\"group relative\">\n <Input\n ref={setInputRef}\n id={`input-${name}`}\n name={name}\n disabled={disabled}\n value={value}\n placeholder={placeholder}\n onChange={onChange}\n size={size}\n variant={variant}\n className={cn(\n size === 'sm' && 'px-8',\n size === 'md' && 'px-9',\n (!size || size === 'default') && 'px-10',\n size === 'lg' && 'px-11',\n )}\n />\n <SearchIcon\n aria-hidden=\"true\"\n className={cn(\n 'absolute top-1/2 left-3 -translate-y-1/2 text-neutral4 opacity-50 group-has-focus:opacity-100',\n size === 'sm' && 'size-3.5',\n size === 'md' && 'size-4',\n (!size || size === 'default') && 'size-[1.125rem]',\n size === 'lg' && 'size-5',\n )}\n />\n {onReset && (value || isMinimized === false) && (\n <Button\n variant=\"ghost\"\n size={buttonSize || 'lg'}\n aria-label=\"Clear search\"\n onClick={() => {\n if (value) {\n onReset();\n }\n if (isMinimized === false) {\n onMinimizedChange?.(true);\n }\n }}\n className=\"absolute top-1/2 right-0 -translate-y-1/2\"\n >\n <XIcon />\n </Button>\n )}\n </div>\n {helpText && <FieldBlock.HelpText>{helpText}</FieldBlock.HelpText>}\n {errorMsg && <FieldBlock.ErrorMsg>{errorMsg}</FieldBlock.ErrorMsg>}\n </FieldBlock.Column>\n </FieldBlock.Layout>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { LightSpanRecord } from '@mastra/core/storage';
|
|
2
1
|
import { ReactNode } from 'react';
|
|
3
2
|
import { TraceUsageSummary } from '../trace-list-columns';
|
|
3
|
+
import { SearchableSpan } from '../types';
|
|
4
4
|
import { LinkComponent } from '../../../ds/types/link-component';
|
|
5
5
|
export type TraceDataPanelPlacement = 'traces-list' | 'trace-page';
|
|
6
6
|
export type TraceDataPanelTab = 'details' | 'scores' | 'feedback';
|
|
7
7
|
export interface TraceDataPanelViewProps {
|
|
8
8
|
traceId: string;
|
|
9
9
|
/** Lightweight spans for the trace. Caller fetches via useTraceLightSpans. */
|
|
10
|
-
spans:
|
|
10
|
+
spans: SearchableSpan[] | undefined;
|
|
11
11
|
/**
|
|
12
12
|
* Token and estimated-cost totals for the trace (from `useTraceUsage`).
|
|
13
13
|
* Rendered in the trace summary when the panel is in the list side-panel
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Dispatch, SetStateAction } from 'react';
|
|
1
|
+
import { Dispatch, ReactNode, SetStateAction } from 'react';
|
|
2
2
|
import { UISpan } from '../types';
|
|
3
3
|
type TraceTimelineProps = {
|
|
4
4
|
hierarchicalSpans: UISpan[];
|
|
@@ -10,6 +10,8 @@ type TraceTimelineProps = {
|
|
|
10
10
|
setExpandedSpanIds?: Dispatch<SetStateAction<string[]>>;
|
|
11
11
|
featuredSpanIds?: string[];
|
|
12
12
|
chartWidth?: 'wide' | 'default';
|
|
13
|
+
/** Rendered on the left of the span type legend row. */
|
|
14
|
+
leadingSlot?: ReactNode;
|
|
13
15
|
};
|
|
14
|
-
export declare function TraceTimeline({ hierarchicalSpans, onSpanClick, selectedSpanId, isLoading, fadedTypes, expandedSpanIds, setExpandedSpanIds, featuredSpanIds, chartWidth, }: TraceTimelineProps): import("react").JSX.Element;
|
|
16
|
+
export declare function TraceTimeline({ hierarchicalSpans, onSpanClick, selectedSpanId, isLoading, fadedTypes, expandedSpanIds, setExpandedSpanIds, featuredSpanIds, chartWidth, leadingSlot, }: TraceTimelineProps): import("react").JSX.Element;
|
|
15
17
|
export {};
|
|
@@ -4,6 +4,7 @@ export { useDownloadTraceJson } from './use-download-trace-json';
|
|
|
4
4
|
export { useSpanDetail } from './use-span-detail';
|
|
5
5
|
export { useTraceLightSpans } from './use-trace-light-spans';
|
|
6
6
|
export { useTraceOrBranchSpans, type UseTraceOrBranchSpansArgs, type UseTraceOrBranchSpansResult, } from './use-trace-or-branch-spans';
|
|
7
|
+
export { useTraceSearch, type UseTraceSearchResult } from './use-trace-search';
|
|
7
8
|
export { useTraceSpans } from './use-trace-spans';
|
|
8
9
|
export { useTraces } from './use-traces';
|
|
9
10
|
export { useTags } from './use-tags';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { LightSpanRecord } from '@mastra/core/storage';
|
|
2
1
|
import { UseQueryResult } from '@tanstack/react-query';
|
|
2
|
+
import { SearchableSpan } from '../types';
|
|
3
3
|
export interface UseBranchArgs {
|
|
4
4
|
traceId: string | null | undefined;
|
|
5
5
|
spanId: string | null | undefined;
|
|
@@ -7,5 +7,5 @@ export interface UseBranchArgs {
|
|
|
7
7
|
}
|
|
8
8
|
export declare function useBranch({ traceId, spanId, depth, }: UseBranchArgs): UseQueryResult<{
|
|
9
9
|
traceId: string;
|
|
10
|
-
spans:
|
|
10
|
+
spans: SearchableSpan[];
|
|
11
11
|
} | null>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { LightSpanRecord } from '@mastra/core/storage';
|
|
2
1
|
import { UseQueryResult } from '@tanstack/react-query';
|
|
2
|
+
import { SearchableSpan } from '../types';
|
|
3
3
|
export declare function useTraceLightSpans(traceId: string | null | undefined): UseQueryResult<{
|
|
4
4
|
traceId: string;
|
|
5
|
-
spans:
|
|
5
|
+
spans: SearchableSpan[];
|
|
6
6
|
} | null>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { LightSpanRecord } from '@mastra/core/storage';
|
|
2
1
|
import { TraceListMode } from '../trace-filters';
|
|
2
|
+
import { SearchableSpan } from '../types';
|
|
3
3
|
export interface UseTraceOrBranchSpansArgs {
|
|
4
4
|
traceId: string | null | undefined;
|
|
5
5
|
/** Required when `listMode === 'branches'` — the anchor span identifying the displayed
|
|
@@ -10,7 +10,7 @@ export interface UseTraceOrBranchSpansArgs {
|
|
|
10
10
|
depth?: number;
|
|
11
11
|
}
|
|
12
12
|
export interface UseTraceOrBranchSpansResult {
|
|
13
|
-
spans:
|
|
13
|
+
spans: SearchableSpan[] | undefined;
|
|
14
14
|
/** Set in branches mode; undefined in traces mode (which uses parentSpanId == null). */
|
|
15
15
|
anchorSpanId: string | undefined;
|
|
16
16
|
isLoading: boolean;
|
|
@@ -21,5 +21,8 @@ export interface UseTraceOrBranchSpansResult {
|
|
|
21
21
|
* Unified data source for the trace/span detail panel. Returns trace spans (full tree from the
|
|
22
22
|
* root) in traces mode, or branch spans (subtree rooted at `anchorSpanId`) in branches mode.
|
|
23
23
|
* Only the active query fires; the inactive one is disabled via its `enabled` flag.
|
|
24
|
+
*
|
|
25
|
+
* Both modes carry full span payloads: the panel renders and searches them, so a lightweight
|
|
26
|
+
* projection here would hide content from the reader looking straight at it.
|
|
24
27
|
*/
|
|
25
28
|
export declare function useTraceOrBranchSpans({ traceId, anchorSpanId, listMode, depth, }: UseTraceOrBranchSpansArgs): UseTraceOrBranchSpansResult;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { SearchableSpan } from '../types';
|
|
2
|
+
export interface UseTraceSearchResult {
|
|
3
|
+
/** The immediate, user-facing input value. Bind this to the search field. */
|
|
4
|
+
query: string;
|
|
5
|
+
setQuery: (query: string) => void;
|
|
6
|
+
/** Rows matching the deferred query. An empty query returns the input array reference. */
|
|
7
|
+
results: SearchableSpan[];
|
|
8
|
+
/** True while the deferred value is behind `query` (the list is still catching up). */
|
|
9
|
+
isPending: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Client-side search over a flat span list.
|
|
13
|
+
*
|
|
14
|
+
* Matching is a substring test against `searchText`, the haystack built once per span when
|
|
15
|
+
* the query resolved (see `toSearchableSpans`). That is what makes the open-ended `metadata`
|
|
16
|
+
* and `error` payloads searchable: their shapes are unknown, so no fixed list of fields can
|
|
17
|
+
* read them. Both sides are already lowercased, so the test is a bare `includes`.
|
|
18
|
+
*
|
|
19
|
+
* Filtering is keyed on a deferred copy of the query, so typing stays responsive while a
|
|
20
|
+
* large list re-filters at lower priority — bind the input to `query`, not to the deferred
|
|
21
|
+
* value. A matching span keeps its ancestors and its whole subtree, so the hierarchy stays
|
|
22
|
+
* intact.
|
|
23
|
+
*
|
|
24
|
+
* `spans` is required. Resolving the loading/empty state is the caller's job — a component
|
|
25
|
+
* holding a query result passes `data?.spans ?? []`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function useTraceSearch(spans: SearchableSpan[]): UseTraceSearchResult;
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import { LightSpanRecord } from '@mastra/core/storage';
|
|
2
1
|
import { UseQueryResult } from '@tanstack/react-query';
|
|
2
|
+
import { SearchableSpan } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Every span of a single trace, with its full payload.
|
|
5
|
+
*
|
|
6
|
+
* The lightweight projection exists to keep blob columns off the read path of a
|
|
7
|
+
* *list*, where the cost is paid once per trace on screen. A trace that is open
|
|
8
|
+
* has already narrowed that to one, and the panel both renders and searches
|
|
9
|
+
* these spans -- `input`, `output` and `attributes` included -- so the
|
|
10
|
+
* projection would only hide content the reader is looking at.
|
|
11
|
+
*/
|
|
3
12
|
export declare function useTraceSpans(traceId: string | null | undefined): UseQueryResult<{
|
|
4
13
|
traceId: string;
|
|
5
|
-
spans:
|
|
14
|
+
spans: SearchableSpan[];
|
|
6
15
|
} | null>;
|
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
import { EntityType } from '@mastra/core/observability';
|
|
2
|
+
import { LightSpanRecord } from '@mastra/core/storage';
|
|
2
3
|
import { ReactNode } from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* A light span carrying a precomputed haystack of everything it holds.
|
|
6
|
+
*
|
|
7
|
+
* `LightSpanRecord` exposes searchable content across a fixed set of columns
|
|
8
|
+
* plus open-ended payloads whose shape is unknown, so a search cannot read it
|
|
9
|
+
* field by field. `searchText` is that content flattened once — see
|
|
10
|
+
* `flattenToSearchText` — so filtering is a substring test per span instead of
|
|
11
|
+
* a re-walk of every payload on every keystroke.
|
|
12
|
+
*
|
|
13
|
+
* It holds field names as well as values, so a span is findable by the shape of
|
|
14
|
+
* its payload and not only by its content.
|
|
15
|
+
*/
|
|
16
|
+
export type SearchableSpan = LightSpanRecord & {
|
|
17
|
+
searchText: string;
|
|
18
|
+
};
|
|
3
19
|
export type UISpan = {
|
|
4
20
|
id: string;
|
|
5
21
|
name: string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { LightSpanRecord } from '@mastra/core/storage';
|
|
2
|
+
/**
|
|
3
|
+
* Filter a flat span list down to the spans matching `predicate`, plus every
|
|
4
|
+
* ancestor needed to keep those spans connected to their root, plus the whole
|
|
5
|
+
* subtree below each match — a matching span is shown intact, not truncated.
|
|
6
|
+
*
|
|
7
|
+
* `spans` may arrive in any order. Trace payloads are flat lists sorted by
|
|
8
|
+
* `startedAt` (and the list API defaults to `direction: 'DESC'`), so children
|
|
9
|
+
* routinely precede their parents; the traversal below indexes the list up
|
|
10
|
+
* front rather than assuming a topological order.
|
|
11
|
+
*
|
|
12
|
+
* The output preserves the input's relative order, so it can be fed straight
|
|
13
|
+
* into `formatHierarchicalSpans`. `predicate` is called exactly once per span.
|
|
14
|
+
*
|
|
15
|
+
* Generic over the span type: only `spanId` and `parentSpanId` are read, and the
|
|
16
|
+
* exact input type comes back out, so enriched spans such as `SearchableSpan`
|
|
17
|
+
* survive the filter instead of being widened to `LightSpanRecord`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function filterSpansKeepingAncestors<T extends Pick<LightSpanRecord, 'spanId' | 'parentSpanId'>>(spans: T[], predicate: (span: T) => boolean): T[];
|