@perses-dev/tempo-plugin 0.57.0 → 0.57.1
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/__mf/js/{Tempo.a15c7ca4.js → Tempo.6c9a48e0.js} +5 -5
- package/__mf/js/async/{1728.988e2b29.js → 1728.67c7a01e.js} +1 -1
- package/__mf/js/async/3.6db4a205.js +4 -0
- package/__mf/js/async/3208.47804c05.js +2 -0
- package/__mf/js/async/54.0f34f4f8.js +22 -0
- package/__mf/js/async/9811.b4b6d8ee.js +7 -0
- package/__mf/js/async/__federation_expose_TempoDatasource.a723b8ee.js +2 -0
- package/__mf/js/async/{__federation_expose_TempoExplorer.003c9970.js → __federation_expose_TempoExplorer.8d4424e2.js} +1 -1
- package/__mf/js/async/__federation_expose_TempoTraceQuery.629ec38d.js +1 -0
- package/__mf/js/{main.6a6654b6.js → main.019cca86.js} +3 -3
- package/lib/cjs/components/AttributeFilters.js +76 -51
- package/lib/cjs/components/complete.js +3 -3
- package/lib/cjs/components/filter/filter.js +2 -2
- package/lib/cjs/components/filter/filter_to_traceql.js +1 -1
- package/lib/cjs/components/filter/traceql_to_filter.js +5 -5
- package/lib/cjs/plugins/tempo-trace-query/TempoTraceQueryEditor.js +1 -1
- package/lib/cjs/plugins/tempo-trace-query/get-trace-data.js +6 -7
- package/lib/components/AttributeFilters.d.ts.map +1 -1
- package/lib/components/AttributeFilters.js +72 -47
- package/lib/components/AttributeFilters.js.map +1 -1
- package/lib/components/ClosableAlert.d.ts +2 -1
- package/lib/components/ClosableAlert.d.ts.map +1 -1
- package/lib/components/ClosableAlert.js.map +1 -1
- package/lib/components/complete.js +1 -1
- package/lib/components/complete.js.map +1 -1
- package/lib/components/filter/filter.d.ts.map +1 -1
- package/lib/components/filter/filter.js +2 -2
- package/lib/components/filter/filter.js.map +1 -1
- package/lib/components/filter/filter_to_traceql.d.ts.map +1 -1
- package/lib/components/filter/filter_to_traceql.js +1 -1
- package/lib/components/filter/filter_to_traceql.js.map +1 -1
- package/lib/components/filter/traceql_to_filter.js +5 -5
- package/lib/components/filter/traceql_to_filter.js.map +1 -1
- package/lib/plugins/tempo-trace-query/TempoTraceQueryEditor.d.ts +1 -1
- package/lib/plugins/tempo-trace-query/TempoTraceQueryEditor.d.ts.map +1 -1
- package/lib/plugins/tempo-trace-query/TempoTraceQueryEditor.js +1 -1
- package/lib/plugins/tempo-trace-query/TempoTraceQueryEditor.js.map +1 -1
- package/lib/plugins/tempo-trace-query/get-trace-data.d.ts.map +1 -1
- package/lib/plugins/tempo-trace-query/get-trace-data.js +6 -7
- package/lib/plugins/tempo-trace-query/get-trace-data.js.map +1 -1
- package/mf-manifest.json +24 -24
- package/mf-stats.json +26 -31
- package/package.json +6 -6
- package/__mf/js/async/1905.d3c01a20.js +0 -2
- package/__mf/js/async/2545.d42b194b.js +0 -2
- package/__mf/js/async/54.812deb71.js +0 -22
- package/__mf/js/async/7958.4ba5d596.js +0 -7
- package/__mf/js/async/__federation_expose_TempoDatasource.1f9ab43f.js +0 -2
- package/__mf/js/async/__federation_expose_TempoTraceQuery.eff34861.js +0 -1
- /package/__mf/js/async/{1905.d3c01a20.js.LICENSE.txt → 3.6db4a205.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{2545.d42b194b.js.LICENSE.txt → 3208.47804c05.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{54.812deb71.js.LICENSE.txt → 54.0f34f4f8.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{7958.4ba5d596.js.LICENSE.txt → 9811.b4b6d8ee.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{__federation_expose_TempoDatasource.1f9ab43f.js.LICENSE.txt → __federation_expose_TempoDatasource.a723b8ee.js.LICENSE.txt} +0 -0
|
@@ -25,10 +25,8 @@ const _react = require("react");
|
|
|
25
25
|
const _material = require("@mui/material");
|
|
26
26
|
const _pluginsystem = require("@perses-dev/plugin-system");
|
|
27
27
|
const _reactquery = require("@tanstack/react-query");
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const _traceql_to_filter = require("./filter/traceql_to_filter");
|
|
31
|
-
const _filter = require("./filter/filter");
|
|
28
|
+
const _plugins = require("../plugins");
|
|
29
|
+
const _filter = require("./filter");
|
|
32
30
|
const statusOptions = [
|
|
33
31
|
'unset',
|
|
34
32
|
'ok',
|
|
@@ -36,65 +34,92 @@ const statusOptions = [
|
|
|
36
34
|
];
|
|
37
35
|
function AttributeFilters(props) {
|
|
38
36
|
const { client, query, setQuery } = props;
|
|
39
|
-
const filter = (0,
|
|
37
|
+
const filter = (0, _filter.traceQLToFilter)(query);
|
|
40
38
|
const setFilter = (filter)=>{
|
|
41
|
-
setQuery((0,
|
|
39
|
+
setQuery((0, _filter.filterToTraceQL)(filter));
|
|
42
40
|
};
|
|
43
41
|
const { absoluteTimeRange } = (0, _pluginsystem.useTimeRange)();
|
|
44
|
-
const { start, end } = (0,
|
|
45
|
-
const { data: serviceNameOptions } = useTagValues(client, 'resource.service.name', (0,
|
|
42
|
+
const { start, end } = (0, _plugins.getUnixTimeRange)(absoluteTimeRange);
|
|
43
|
+
const { data: serviceNameOptions } = useTagValues(client, 'resource.service.name', (0, _filter.filterToTraceQL)({
|
|
46
44
|
...filter,
|
|
47
45
|
serviceName: []
|
|
48
46
|
}), start, end);
|
|
49
|
-
const { data: spanNameOptions } = useTagValues(client, 'name', (0,
|
|
47
|
+
const { data: spanNameOptions } = useTagValues(client, 'name', (0, _filter.filterToTraceQL)({
|
|
50
48
|
...filter,
|
|
51
49
|
spanName: []
|
|
52
50
|
}), start, end);
|
|
53
|
-
return /*#__PURE__*/ (0, _jsxruntime.jsxs)(
|
|
51
|
+
return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
|
|
52
|
+
direction: "column",
|
|
53
|
+
flex: 1,
|
|
54
|
+
gap: 1,
|
|
54
55
|
children: [
|
|
55
|
-
/*#__PURE__*/ (0, _jsxruntime.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
56
|
+
/*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
|
|
57
|
+
direction: "row",
|
|
58
|
+
flex: 1,
|
|
59
|
+
gap: 1,
|
|
60
|
+
sx: {
|
|
61
|
+
'& > *:nth-of-type(1)': {
|
|
62
|
+
flex: 2
|
|
63
|
+
},
|
|
64
|
+
'& > *:nth-of-type(2)': {
|
|
65
|
+
flex: 2
|
|
66
|
+
},
|
|
67
|
+
'& > *:nth-of-type(3)': {
|
|
68
|
+
flex: 1
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
children: [
|
|
72
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(StringAttributeFilter, {
|
|
73
|
+
label: "Service Name",
|
|
74
|
+
options: serviceNameOptions ?? [],
|
|
75
|
+
value: filter.serviceName,
|
|
76
|
+
setValue: (x)=>setFilter({
|
|
77
|
+
...filter,
|
|
78
|
+
serviceName: x
|
|
79
|
+
})
|
|
80
|
+
}),
|
|
81
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(StringAttributeFilter, {
|
|
82
|
+
label: "Span Name",
|
|
83
|
+
options: spanNameOptions ?? [],
|
|
84
|
+
value: filter.spanName,
|
|
85
|
+
setValue: (x)=>setFilter({
|
|
86
|
+
...filter,
|
|
87
|
+
spanName: x
|
|
88
|
+
})
|
|
89
|
+
}),
|
|
90
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(StringAttributeFilter, {
|
|
91
|
+
label: "Status",
|
|
92
|
+
options: statusOptions ?? [],
|
|
93
|
+
value: filter.status,
|
|
94
|
+
setValue: (x)=>setFilter({
|
|
95
|
+
...filter,
|
|
96
|
+
status: x
|
|
97
|
+
})
|
|
89
98
|
})
|
|
99
|
+
]
|
|
90
100
|
}),
|
|
91
|
-
/*#__PURE__*/ (0, _jsxruntime.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
101
|
+
/*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
|
|
102
|
+
direction: "row",
|
|
103
|
+
flex: 1,
|
|
104
|
+
gap: 1,
|
|
105
|
+
children: [
|
|
106
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(DurationAttributeFilter, {
|
|
107
|
+
label: "Trace Duration",
|
|
108
|
+
value: filter.traceDuration,
|
|
109
|
+
setValue: (value)=>setFilter({
|
|
110
|
+
...filter,
|
|
111
|
+
traceDuration: value
|
|
112
|
+
})
|
|
113
|
+
}),
|
|
114
|
+
/*#__PURE__*/ (0, _jsxruntime.jsx)(CustomAttributesFilter, {
|
|
115
|
+
label: "Custom Attributes",
|
|
116
|
+
value: filter.customMatchers,
|
|
117
|
+
setValue: (value)=>setFilter({
|
|
118
|
+
...filter,
|
|
119
|
+
customMatchers: value
|
|
120
|
+
})
|
|
97
121
|
})
|
|
122
|
+
]
|
|
98
123
|
})
|
|
99
124
|
]
|
|
100
125
|
});
|
|
@@ -203,7 +228,7 @@ function CustomAttributesFilter(props) {
|
|
|
203
228
|
/** A <TextField> which calls props.setValue when the input field is blurred and the validation passes. */ function LazyTextInput(props) {
|
|
204
229
|
const { validationRegex, validationFailedMessage, value, setValue, ...otherProps } = props;
|
|
205
230
|
const [draftValue, setDraftValue] = (0, _react.useState)(value);
|
|
206
|
-
const isValidInput = draftValue
|
|
231
|
+
const isValidInput = draftValue === '' || validationRegex === undefined || validationRegex.test(draftValue);
|
|
207
232
|
(0, _react.useEffect)(()=>{
|
|
208
233
|
setDraftValue(value);
|
|
209
234
|
}, [
|
|
@@ -34,7 +34,7 @@ _export(exports, {
|
|
|
34
34
|
const _autocomplete = require("@codemirror/autocomplete");
|
|
35
35
|
const _language = require("@codemirror/language");
|
|
36
36
|
const _lezertraceql = require("@grafana/lezer-traceql");
|
|
37
|
-
const
|
|
37
|
+
const _plugins = require("../plugins");
|
|
38
38
|
const quoteChars = [
|
|
39
39
|
'"',
|
|
40
40
|
'`'
|
|
@@ -294,7 +294,7 @@ async function completeTagName(completionCfg, scope) {
|
|
|
294
294
|
if (!completionCfg.client) {
|
|
295
295
|
return [];
|
|
296
296
|
}
|
|
297
|
-
const { start, end } = completionCfg.timeRange ? (0,
|
|
297
|
+
const { start, end } = completionCfg.timeRange ? (0, _plugins.getUnixTimeRange)(completionCfg.timeRange) : {};
|
|
298
298
|
const { limit, maxStaleValues } = completionCfg;
|
|
299
299
|
const response = await completionCfg.client.searchTags({
|
|
300
300
|
scope,
|
|
@@ -340,7 +340,7 @@ async function completeTagValue(completionCfg, tag) {
|
|
|
340
340
|
if (!completionCfg.client) {
|
|
341
341
|
return [];
|
|
342
342
|
}
|
|
343
|
-
const { start, end } = completionCfg.timeRange ? (0,
|
|
343
|
+
const { start, end } = completionCfg.timeRange ? (0, _plugins.getUnixTimeRange)(completionCfg.timeRange) : {};
|
|
344
344
|
const { limit, maxStaleValues } = completionCfg;
|
|
345
345
|
const response = await completionCfg.client.searchTagValues({
|
|
346
346
|
tag,
|
|
@@ -25,9 +25,9 @@ function splitByUnquotedWhitespace(x) {
|
|
|
25
25
|
let from = 0;
|
|
26
26
|
const chunks = [];
|
|
27
27
|
for(let i = 0; i < x.length; i++){
|
|
28
|
-
if (x[i]
|
|
28
|
+
if (x[i] === '"' && x[i - 1] !== '\\') {
|
|
29
29
|
quote = !quote;
|
|
30
|
-
} else if (x[i]
|
|
30
|
+
} else if (x[i] === ' ' && !quote) {
|
|
31
31
|
chunks.push(x.slice(from, i));
|
|
32
32
|
from = i + 1;
|
|
33
33
|
}
|
|
@@ -83,9 +83,9 @@ function reverseStringMatcher(matches) {
|
|
|
83
83
|
const values = [];
|
|
84
84
|
for (const { operator, value } of matches ?? []){
|
|
85
85
|
const unescaped = unescape(value.slice(1, -1));
|
|
86
|
-
if (operator
|
|
86
|
+
if (operator === '=') {
|
|
87
87
|
values.push(unescaped);
|
|
88
|
-
} else if (operator
|
|
88
|
+
} else if (operator === '=~') {
|
|
89
89
|
values.push(...unescaped.split('|'));
|
|
90
90
|
}
|
|
91
91
|
}
|
|
@@ -94,7 +94,7 @@ function reverseStringMatcher(matches) {
|
|
|
94
94
|
function reverseIntrinsicMatcher(matches) {
|
|
95
95
|
const values = [];
|
|
96
96
|
for (const { operator, value } of matches ?? []){
|
|
97
|
-
if (operator
|
|
97
|
+
if (operator === '=') {
|
|
98
98
|
values.push(value);
|
|
99
99
|
}
|
|
100
100
|
}
|
|
@@ -103,9 +103,9 @@ function reverseIntrinsicMatcher(matches) {
|
|
|
103
103
|
function reverseDurationMatcher(matches) {
|
|
104
104
|
const duration = {};
|
|
105
105
|
for (const { operator, value } of matches ?? []){
|
|
106
|
-
if (operator
|
|
106
|
+
if (operator === '>=') {
|
|
107
107
|
duration.min = value;
|
|
108
|
-
} else if (operator
|
|
108
|
+
} else if (operator === '<=') {
|
|
109
109
|
duration.max = value;
|
|
110
110
|
}
|
|
111
111
|
}
|
|
@@ -116,7 +116,7 @@ function TempoTraceQueryEditor(props) {
|
|
|
116
116
|
}
|
|
117
117
|
function isSimpleTraceQLQuery(query) {
|
|
118
118
|
// if a query can be transformed to a filter and back to the original query, we can show the attribute filter toolbar
|
|
119
|
-
return query
|
|
119
|
+
return query === '' || (0, _components1.filterToTraceQL)((0, _components1.traceQLToFilter)(query)) === query;
|
|
120
120
|
}
|
|
121
121
|
const limitOptions = [
|
|
122
122
|
20,
|
|
@@ -32,7 +32,6 @@ const _core = require("@perses-dev/core");
|
|
|
32
32
|
const _pluginsystem = require("@perses-dev/plugin-system");
|
|
33
33
|
const _datefns = require("date-fns");
|
|
34
34
|
const _model = require("../../model");
|
|
35
|
-
const _apitypes = require("../../model/api-types");
|
|
36
35
|
function getUnixTimeRange(timeRange) {
|
|
37
36
|
const { start, end } = timeRange;
|
|
38
37
|
return {
|
|
@@ -80,7 +79,7 @@ const getTraceData = async (spec, context)=>{
|
|
|
80
79
|
}
|
|
81
80
|
// Fetch one more trace than requested.
|
|
82
81
|
// This way we can check if there are more traces available matching the search request, and show a notice to the user.
|
|
83
|
-
const limit = spec.limit ??
|
|
82
|
+
const limit = spec.limit ?? _model.DEFAULT_SEARCH_LIMIT;
|
|
84
83
|
params.limit = limit + 1;
|
|
85
84
|
const response = await client.searchWithFallback(params);
|
|
86
85
|
const searchResult = parseSearchResponse(response);
|
|
@@ -115,20 +114,20 @@ function parseTraceResponse(response) {
|
|
|
115
114
|
for (const resourceSpan of trace.resourceSpans){
|
|
116
115
|
for (const scopeSpan of resourceSpan.scopeSpans){
|
|
117
116
|
for (const span of scopeSpan.spans){
|
|
118
|
-
if (span.traceId.length
|
|
117
|
+
if (span.traceId.length !== 32) {
|
|
119
118
|
span.traceId = base64ToHex(span.traceId);
|
|
120
119
|
}
|
|
121
|
-
if (span.spanId.length
|
|
120
|
+
if (span.spanId.length !== 16) {
|
|
122
121
|
span.spanId = base64ToHex(span.spanId);
|
|
123
122
|
}
|
|
124
|
-
if (span.parentSpanId && span.parentSpanId.length
|
|
123
|
+
if (span.parentSpanId && span.parentSpanId.length !== 16) {
|
|
125
124
|
span.parentSpanId = base64ToHex(span.parentSpanId);
|
|
126
125
|
}
|
|
127
126
|
for (const link of span.links ?? []){
|
|
128
|
-
if (link.traceId.length
|
|
127
|
+
if (link.traceId.length !== 32) {
|
|
129
128
|
link.traceId = base64ToHex(link.traceId);
|
|
130
129
|
}
|
|
131
|
-
if (link.spanId.length
|
|
130
|
+
if (link.spanId.length !== 16) {
|
|
132
131
|
link.spanId = base64ToHex(link.spanId);
|
|
133
132
|
}
|
|
134
133
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AttributeFilters.d.ts","sourceRoot":"","sources":["../../../src/components/AttributeFilters.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAoD,MAAM,OAAO,CAAC;AAIvF,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"AttributeFilters.d.ts","sourceRoot":"","sources":["../../../src/components/AttributeFilters.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAoD,MAAM,OAAO,CAAC;AAIvF,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAMvC,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,YAAY,CAuE3E"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// Copyright The Perses Authors
|
|
3
3
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
// you may not use this file except in compliance with the License.
|
|
@@ -15,10 +15,8 @@ import { useCallback, useEffect, useState } from 'react';
|
|
|
15
15
|
import { Autocomplete, Checkbox, Stack, TextField } from '@mui/material';
|
|
16
16
|
import { useTimeRange } from '@perses-dev/plugin-system';
|
|
17
17
|
import { useQuery } from '@tanstack/react-query';
|
|
18
|
-
import { getUnixTimeRange } from '../plugins
|
|
19
|
-
import { filterToTraceQL } from './filter
|
|
20
|
-
import { traceQLToFilter } from './filter/traceql_to_filter';
|
|
21
|
-
import { splitByUnquotedWhitespace } from './filter/filter';
|
|
18
|
+
import { getUnixTimeRange } from '../plugins';
|
|
19
|
+
import { filterToTraceQL, traceQLToFilter, splitByUnquotedWhitespace } from './filter';
|
|
22
20
|
const statusOptions = [
|
|
23
21
|
'unset',
|
|
24
22
|
'ok',
|
|
@@ -40,51 +38,78 @@ export function AttributeFilters(props) {
|
|
|
40
38
|
...filter,
|
|
41
39
|
spanName: []
|
|
42
40
|
}), start, end);
|
|
43
|
-
return /*#__PURE__*/ _jsxs(
|
|
41
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
42
|
+
direction: "column",
|
|
43
|
+
flex: 1,
|
|
44
|
+
gap: 1,
|
|
44
45
|
children: [
|
|
45
|
-
/*#__PURE__*/
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
46
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
47
|
+
direction: "row",
|
|
48
|
+
flex: 1,
|
|
49
|
+
gap: 1,
|
|
50
|
+
sx: {
|
|
51
|
+
'& > *:nth-of-type(1)': {
|
|
52
|
+
flex: 2
|
|
53
|
+
},
|
|
54
|
+
'& > *:nth-of-type(2)': {
|
|
55
|
+
flex: 2
|
|
56
|
+
},
|
|
57
|
+
'& > *:nth-of-type(3)': {
|
|
58
|
+
flex: 1
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
children: [
|
|
62
|
+
/*#__PURE__*/ _jsx(StringAttributeFilter, {
|
|
63
|
+
label: "Service Name",
|
|
64
|
+
options: serviceNameOptions ?? [],
|
|
65
|
+
value: filter.serviceName,
|
|
66
|
+
setValue: (x)=>setFilter({
|
|
67
|
+
...filter,
|
|
68
|
+
serviceName: x
|
|
69
|
+
})
|
|
70
|
+
}),
|
|
71
|
+
/*#__PURE__*/ _jsx(StringAttributeFilter, {
|
|
72
|
+
label: "Span Name",
|
|
73
|
+
options: spanNameOptions ?? [],
|
|
74
|
+
value: filter.spanName,
|
|
75
|
+
setValue: (x)=>setFilter({
|
|
76
|
+
...filter,
|
|
77
|
+
spanName: x
|
|
78
|
+
})
|
|
79
|
+
}),
|
|
80
|
+
/*#__PURE__*/ _jsx(StringAttributeFilter, {
|
|
81
|
+
label: "Status",
|
|
82
|
+
options: statusOptions ?? [],
|
|
83
|
+
value: filter.status,
|
|
84
|
+
setValue: (x)=>setFilter({
|
|
85
|
+
...filter,
|
|
86
|
+
status: x
|
|
87
|
+
})
|
|
79
88
|
})
|
|
89
|
+
]
|
|
80
90
|
}),
|
|
81
|
-
/*#__PURE__*/
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
91
|
+
/*#__PURE__*/ _jsxs(Stack, {
|
|
92
|
+
direction: "row",
|
|
93
|
+
flex: 1,
|
|
94
|
+
gap: 1,
|
|
95
|
+
children: [
|
|
96
|
+
/*#__PURE__*/ _jsx(DurationAttributeFilter, {
|
|
97
|
+
label: "Trace Duration",
|
|
98
|
+
value: filter.traceDuration,
|
|
99
|
+
setValue: (value)=>setFilter({
|
|
100
|
+
...filter,
|
|
101
|
+
traceDuration: value
|
|
102
|
+
})
|
|
103
|
+
}),
|
|
104
|
+
/*#__PURE__*/ _jsx(CustomAttributesFilter, {
|
|
105
|
+
label: "Custom Attributes",
|
|
106
|
+
value: filter.customMatchers,
|
|
107
|
+
setValue: (value)=>setFilter({
|
|
108
|
+
...filter,
|
|
109
|
+
customMatchers: value
|
|
110
|
+
})
|
|
87
111
|
})
|
|
112
|
+
]
|
|
88
113
|
})
|
|
89
114
|
]
|
|
90
115
|
});
|
|
@@ -193,7 +218,7 @@ function CustomAttributesFilter(props) {
|
|
|
193
218
|
/** A <TextField> which calls props.setValue when the input field is blurred and the validation passes. */ function LazyTextInput(props) {
|
|
194
219
|
const { validationRegex, validationFailedMessage, value, setValue, ...otherProps } = props;
|
|
195
220
|
const [draftValue, setDraftValue] = useState(value);
|
|
196
|
-
const isValidInput = draftValue
|
|
221
|
+
const isValidInput = draftValue === '' || validationRegex === undefined || validationRegex.test(draftValue);
|
|
197
222
|
useEffect(()=>{
|
|
198
223
|
setDraftValue(value);
|
|
199
224
|
}, [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/AttributeFilters.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ReactElement, SyntheticEvent, useCallback, useEffect, useState } from 'react';\nimport { Autocomplete, Checkbox, Stack, TextField, TextFieldProps } from '@mui/material';\nimport { useTimeRange } from '@perses-dev/plugin-system';\nimport { useQuery } from '@tanstack/react-query';\nimport { TempoClient } from '../model';\nimport { getUnixTimeRange } from '../plugins/tempo-trace-query/get-trace-data';\nimport { filterToTraceQL } from './filter/filter_to_traceql';\nimport { traceQLToFilter } from './filter/traceql_to_filter';\nimport { DurationField, Filter, splitByUnquotedWhitespace } from './filter/filter';\n\nconst statusOptions = ['unset', 'ok', 'error'];\n\nexport interface AttributeFiltersProps {\n client?: TempoClient;\n query: string;\n setQuery: (x: string) => void;\n}\n\nexport function AttributeFilters(props: AttributeFiltersProps): ReactElement {\n const { client, query, setQuery } = props;\n\n const filter = traceQLToFilter(query);\n const setFilter = (filter: Filter) => {\n setQuery(filterToTraceQL(filter));\n };\n\n const { absoluteTimeRange } = useTimeRange();\n const { start, end } = getUnixTimeRange(absoluteTimeRange);\n\n const { data: serviceNameOptions } = useTagValues(\n client,\n 'resource.service.name',\n filterToTraceQL({ ...filter, serviceName: [] }),\n start,\n end\n );\n const { data: spanNameOptions } = useTagValues(\n client,\n 'name',\n filterToTraceQL({ ...filter, spanName: [] }),\n start,\n end\n );\n\n return (\n <>\n <StringAttributeFilter\n label=\"Service Name\"\n options={serviceNameOptions ?? []}\n value={filter.serviceName}\n setValue={(x) => setFilter({ ...filter, serviceName: x })}\n />\n <StringAttributeFilter\n label=\"Span Name\"\n options={spanNameOptions ?? []}\n value={filter.spanName}\n setValue={(x) => setFilter({ ...filter, spanName: x })}\n />\n <StringAttributeFilter\n label=\"Status\"\n width={210}\n options={statusOptions ?? []}\n value={filter.status}\n setValue={(x) => setFilter({ ...filter, status: x })}\n />\n <DurationAttributeFilter\n label=\"Trace Duration\"\n value={filter.traceDuration}\n setValue={(value) => setFilter({ ...filter, traceDuration: value })}\n />\n <CustomAttributesFilter\n label=\"Custom Attributes\"\n value={filter.customMatchers}\n setValue={(value) => setFilter({ ...filter, customMatchers: value })}\n />\n </>\n );\n}\n\ninterface StringAttributeFilterProps {\n label: string;\n width?: number;\n options: string[];\n value: string[];\n setValue: (value: string[]) => void;\n}\n\nfunction StringAttributeFilter(props: StringAttributeFilterProps) {\n const { label, width, options, value, setValue } = props;\n\n return (\n <Autocomplete\n multiple\n size=\"small\"\n limitTags={1}\n disableCloseOnSelect\n value={value}\n onChange={(_event: SyntheticEvent, newValue: string[]) => setValue(newValue)}\n options={options}\n renderOption={(props, option, { selected }) => {\n const { key, ...optionProps } = props;\n return (\n <li key={key} {...optionProps}>\n <Checkbox style={{ marginRight: 8 }} checked={selected} />\n {option}\n </li>\n );\n }}\n renderInput={(params) => <TextField {...params} label={label} />}\n // Reduce the size of the chips to make space for the <input> element, the +X text and the X button to avoid a line break.\n // See https://github.com/mui/material-ui/issues/38835 for more details.\n slotProps={{ chip: { sx: { maxWidth: 'calc(100% - 45px) !important' } } }}\n // Reduce the size of the <input> field\n sx={{ width: width ?? 250, '& input': { minWidth: '5px !important' } }}\n />\n );\n}\n\ninterface DurationAttributeFilterProps {\n label: string;\n value: DurationField;\n setValue: (value: DurationField) => void;\n}\n\nfunction DurationAttributeFilter(props: DurationAttributeFilterProps) {\n const { label, value, setValue } = props;\n const { min, max } = value;\n\n return (\n <Stack direction=\"row\" gap={0.5}>\n <DurationTextInput label={`Min ${label}`} value={min ?? ''} setValue={(min) => setValue({ min, max })} />\n <DurationTextInput label={`Max ${label}`} value={max ?? ''} setValue={(max) => setValue({ min, max })} />\n </Stack>\n );\n}\n\nconst durationFormatRegex = /^([0-9]+\\.)?[0-9]+(ns|ms|s|m|h)$/;\n\ninterface DurationTextInputProps {\n label: string;\n value: string;\n setValue: (value: string) => void;\n}\n\nfunction DurationTextInput(props: DurationTextInputProps) {\n const { label, value, setValue } = props;\n\n return (\n <LazyTextInput\n label={label}\n size=\"small\"\n value={value}\n setValue={setValue}\n validationRegex={durationFormatRegex}\n validationFailedMessage=\"Invalid format. Accepted format e.g. 100ms, accepted units: ns, ms, s, m, h\"\n sx={{ width: 150 }}\n />\n );\n}\n\ninterface CustomAttributesFilterProps {\n label: string;\n value: string[];\n setValue: (value: string[]) => void;\n}\n\nfunction CustomAttributesFilter(props: CustomAttributesFilterProps) {\n const { label, value, setValue } = props;\n\n return (\n <LazyTextInput\n label={label}\n size=\"small\"\n placeholder='span.http.status_code=200 span.http.method=\"GET\"'\n value={value.join(' ')}\n setValue={(x) => setValue(splitByUnquotedWhitespace(x))}\n sx={{ flexGrow: 1 }}\n />\n );\n}\n\ninterface LazyTextInputProps extends Omit<TextFieldProps, 'variant'> {\n validationRegex?: RegExp;\n validationFailedMessage?: string;\n value: string;\n setValue: (value: string) => void;\n}\n\n/** A <TextField> which calls props.setValue when the input field is blurred and the validation passes. */\nfunction LazyTextInput(props: LazyTextInputProps) {\n const { validationRegex, validationFailedMessage, value, setValue, ...otherProps } = props;\n const [draftValue, setDraftValue] = useState(value);\n const isValidInput = draftValue == '' || validationRegex == undefined || validationRegex.test(draftValue);\n\n useEffect(() => {\n setDraftValue(value);\n }, [value, setDraftValue]);\n\n const handleChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {\n setDraftValue(event.target.value);\n }, []);\n\n const handleBlur = useCallback(() => {\n if (isValidInput) {\n setValue(draftValue);\n }\n }, [isValidInput, setValue, draftValue]);\n\n return (\n <TextField\n {...otherProps}\n error={!isValidInput}\n helperText={isValidInput ? undefined : validationFailedMessage}\n value={draftValue}\n onChange={handleChange}\n onBlur={handleBlur}\n />\n );\n}\n\nfunction useTagValues(client: TempoClient | undefined, tag: string, query: string, start?: number, end?: number) {\n return useQuery({\n queryKey: ['useTagValues', client, tag, query, start, end],\n enabled: !!client,\n queryFn: async function () {\n if (!client) return;\n const values = await client.searchTagValues({ tag, q: query, start, end });\n return values.tagValues.map((tagValue) => tagValue.value ?? '').sort();\n },\n staleTime: 60 * 1000, // cache tag value response for 1m\n });\n}\n"],"names":["useCallback","useEffect","useState","Autocomplete","Checkbox","Stack","TextField","useTimeRange","useQuery","getUnixTimeRange","filterToTraceQL","traceQLToFilter","splitByUnquotedWhitespace","statusOptions","AttributeFilters","props","client","query","setQuery","filter","setFilter","absoluteTimeRange","start","end","data","serviceNameOptions","useTagValues","serviceName","spanNameOptions","spanName","StringAttributeFilter","label","options","value","setValue","x","width","status","DurationAttributeFilter","traceDuration","CustomAttributesFilter","customMatchers","multiple","size","limitTags","disableCloseOnSelect","onChange","_event","newValue","renderOption","option","selected","key","optionProps","li","style","marginRight","checked","renderInput","params","slotProps","chip","sx","maxWidth","minWidth","min","max","direction","gap","DurationTextInput","durationFormatRegex","LazyTextInput","validationRegex","validationFailedMessage","placeholder","join","flexGrow","otherProps","draftValue","setDraftValue","isValidInput","undefined","test","handleChange","event","target","handleBlur","error","helperText","onBlur","tag","queryKey","enabled","queryFn","values","searchTagValues","q","tagValues","map","tagValue","sort","staleTime"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/AttributeFilters.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ReactElement, SyntheticEvent, useCallback, useEffect, useState } from 'react';\nimport { Autocomplete, Checkbox, Stack, TextField, TextFieldProps } from '@mui/material';\nimport { useTimeRange } from '@perses-dev/plugin-system';\nimport { useQuery, UseQueryResult } from '@tanstack/react-query';\nimport { TempoClient } from '../model';\nimport { getUnixTimeRange } from '../plugins';\nimport { filterToTraceQL, traceQLToFilter, DurationField, Filter, splitByUnquotedWhitespace } from './filter';\n\nconst statusOptions = ['unset', 'ok', 'error'];\n\nexport interface AttributeFiltersProps {\n client?: TempoClient;\n query: string;\n setQuery: (x: string) => void;\n}\n\nexport function AttributeFilters(props: AttributeFiltersProps): ReactElement {\n const { client, query, setQuery } = props;\n\n const filter = traceQLToFilter(query);\n const setFilter = (filter: Filter): void => {\n setQuery(filterToTraceQL(filter));\n };\n\n const { absoluteTimeRange } = useTimeRange();\n const { start, end } = getUnixTimeRange(absoluteTimeRange);\n\n const { data: serviceNameOptions } = useTagValues(\n client,\n 'resource.service.name',\n filterToTraceQL({ ...filter, serviceName: [] }),\n start,\n end\n );\n const { data: spanNameOptions } = useTagValues(\n client,\n 'name',\n filterToTraceQL({ ...filter, spanName: [] }),\n start,\n end\n );\n\n return (\n <Stack direction=\"column\" flex={1} gap={1}>\n <Stack\n direction=\"row\"\n flex={1}\n gap={1}\n sx={{\n '& > *:nth-of-type(1)': { flex: 2 }, // Service Name\n '& > *:nth-of-type(2)': { flex: 2 }, // Span Name\n '& > *:nth-of-type(3)': { flex: 1 }, // Status\n }}\n >\n <StringAttributeFilter\n label=\"Service Name\"\n options={serviceNameOptions ?? []}\n value={filter.serviceName}\n setValue={(x) => setFilter({ ...filter, serviceName: x })}\n />\n <StringAttributeFilter\n label=\"Span Name\"\n options={spanNameOptions ?? []}\n value={filter.spanName}\n setValue={(x) => setFilter({ ...filter, spanName: x })}\n />\n <StringAttributeFilter\n label=\"Status\"\n options={statusOptions ?? []}\n value={filter.status}\n setValue={(x) => setFilter({ ...filter, status: x })}\n />\n </Stack>\n <Stack direction=\"row\" flex={1} gap={1}>\n <DurationAttributeFilter\n label=\"Trace Duration\"\n value={filter.traceDuration}\n setValue={(value) => setFilter({ ...filter, traceDuration: value })}\n />\n <CustomAttributesFilter\n label=\"Custom Attributes\"\n value={filter.customMatchers}\n setValue={(value) => setFilter({ ...filter, customMatchers: value })}\n />\n </Stack>\n </Stack>\n );\n}\n\ninterface StringAttributeFilterProps {\n label: string;\n width?: number;\n options: string[];\n value: string[];\n setValue: (value: string[]) => void;\n}\n\nfunction StringAttributeFilter(props: StringAttributeFilterProps): ReactElement {\n const { label, width, options, value, setValue } = props;\n\n return (\n <Autocomplete\n multiple\n size=\"small\"\n limitTags={1}\n disableCloseOnSelect\n value={value}\n onChange={(_event: SyntheticEvent, newValue: string[]) => setValue(newValue)}\n options={options}\n renderOption={(props, option, { selected }) => {\n const { key, ...optionProps } = props;\n return (\n <li key={key} {...optionProps}>\n <Checkbox style={{ marginRight: 8 }} checked={selected} />\n {option}\n </li>\n );\n }}\n renderInput={(params) => <TextField {...params} label={label} />}\n // Reduce the size of the chips to make space for the <input> element, the +X text and the X button to avoid a line break.\n // See https://github.com/mui/material-ui/issues/38835 for more details.\n slotProps={{ chip: { sx: { maxWidth: 'calc(100% - 45px) !important' } } }}\n // Reduce the size of the <input> field\n sx={{ width: width ?? 250, '& input': { minWidth: '5px !important' } }}\n />\n );\n}\n\ninterface DurationAttributeFilterProps {\n label: string;\n value: DurationField;\n setValue: (value: DurationField) => void;\n}\n\nfunction DurationAttributeFilter(props: DurationAttributeFilterProps): ReactElement {\n const { label, value, setValue } = props;\n const { min, max } = value;\n\n return (\n <Stack direction=\"row\" gap={0.5}>\n <DurationTextInput label={`Min ${label}`} value={min ?? ''} setValue={(min) => setValue({ min, max })} />\n <DurationTextInput label={`Max ${label}`} value={max ?? ''} setValue={(max) => setValue({ min, max })} />\n </Stack>\n );\n}\n\nconst durationFormatRegex = /^([0-9]+\\.)?[0-9]+(ns|ms|s|m|h)$/;\n\ninterface DurationTextInputProps {\n label: string;\n value: string;\n setValue: (value: string) => void;\n}\n\nfunction DurationTextInput(props: DurationTextInputProps): ReactElement {\n const { label, value, setValue } = props;\n\n return (\n <LazyTextInput\n label={label}\n size=\"small\"\n value={value}\n setValue={setValue}\n validationRegex={durationFormatRegex}\n validationFailedMessage=\"Invalid format. Accepted format e.g. 100ms, accepted units: ns, ms, s, m, h\"\n sx={{ width: 150 }}\n />\n );\n}\n\ninterface CustomAttributesFilterProps {\n label: string;\n value: string[];\n setValue: (value: string[]) => void;\n}\n\nfunction CustomAttributesFilter(props: CustomAttributesFilterProps): ReactElement {\n const { label, value, setValue } = props;\n\n return (\n <LazyTextInput\n label={label}\n size=\"small\"\n placeholder='span.http.status_code=200 span.http.method=\"GET\"'\n value={value.join(' ')}\n setValue={(x) => setValue(splitByUnquotedWhitespace(x))}\n sx={{ flexGrow: 1 }}\n />\n );\n}\n\ninterface LazyTextInputProps extends Omit<TextFieldProps, 'variant'> {\n validationRegex?: RegExp;\n validationFailedMessage?: string;\n value: string;\n setValue: (value: string) => void;\n}\n\n/** A <TextField> which calls props.setValue when the input field is blurred and the validation passes. */\nfunction LazyTextInput(props: LazyTextInputProps): ReactElement {\n const { validationRegex, validationFailedMessage, value, setValue, ...otherProps } = props;\n const [draftValue, setDraftValue] = useState(value);\n const isValidInput = draftValue === '' || validationRegex === undefined || validationRegex.test(draftValue);\n\n useEffect(() => {\n setDraftValue(value);\n }, [value, setDraftValue]);\n\n const handleChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {\n setDraftValue(event.target.value);\n }, []);\n\n const handleBlur = useCallback(() => {\n if (isValidInput) {\n setValue(draftValue);\n }\n }, [isValidInput, setValue, draftValue]);\n\n return (\n <TextField\n {...otherProps}\n error={!isValidInput}\n helperText={isValidInput ? undefined : validationFailedMessage}\n value={draftValue}\n onChange={handleChange}\n onBlur={handleBlur}\n />\n );\n}\n\nfunction useTagValues(\n client: TempoClient | undefined,\n tag: string,\n query: string,\n start?: number,\n end?: number\n): UseQueryResult<string[] | undefined> {\n return useQuery({\n queryKey: ['useTagValues', client, tag, query, start, end],\n enabled: !!client,\n queryFn: async function () {\n if (!client) return;\n const values = await client.searchTagValues({ tag, q: query, start, end });\n return values.tagValues.map((tagValue) => tagValue.value ?? '').sort();\n },\n staleTime: 60 * 1000, // cache tag value response for 1m\n });\n}\n"],"names":["useCallback","useEffect","useState","Autocomplete","Checkbox","Stack","TextField","useTimeRange","useQuery","getUnixTimeRange","filterToTraceQL","traceQLToFilter","splitByUnquotedWhitespace","statusOptions","AttributeFilters","props","client","query","setQuery","filter","setFilter","absoluteTimeRange","start","end","data","serviceNameOptions","useTagValues","serviceName","spanNameOptions","spanName","direction","flex","gap","sx","StringAttributeFilter","label","options","value","setValue","x","status","DurationAttributeFilter","traceDuration","CustomAttributesFilter","customMatchers","width","multiple","size","limitTags","disableCloseOnSelect","onChange","_event","newValue","renderOption","option","selected","key","optionProps","li","style","marginRight","checked","renderInput","params","slotProps","chip","maxWidth","minWidth","min","max","DurationTextInput","durationFormatRegex","LazyTextInput","validationRegex","validationFailedMessage","placeholder","join","flexGrow","otherProps","draftValue","setDraftValue","isValidInput","undefined","test","handleChange","event","target","handleBlur","error","helperText","onBlur","tag","queryKey","enabled","queryFn","values","searchTagValues","q","tagValues","map","tagValue","sort","staleTime"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
1
2
|
import { AlertProps } from '@mui/material';
|
|
2
|
-
export declare function ClosableAlert(props: AlertProps):
|
|
3
|
+
export declare function ClosableAlert(props: AlertProps): ReactElement | null;
|
|
3
4
|
//# sourceMappingURL=ClosableAlert.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClosableAlert.d.ts","sourceRoot":"","sources":["../../../src/components/ClosableAlert.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ClosableAlert.d.ts","sourceRoot":"","sources":["../../../src/components/ClosableAlert.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAyB,MAAM,OAAO,CAAC;AAC5D,OAAO,EAAS,UAAU,EAAE,MAAM,eAAe,CAAC;AAElD,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,YAAY,GAAG,IAAI,CAYpE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ClosableAlert.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { useCallback, useState } from 'react';\nimport { Alert, AlertProps } from '@mui/material';\n\nexport function ClosableAlert(props: AlertProps) {\n const [isVisible, setVisible] = useState(true);\n\n const handleClose = useCallback(() => {\n setVisible(false);\n }, [setVisible]);\n\n if (!isVisible) {\n return null;\n }\n\n return <Alert {...props} onClose={handleClose} />;\n}\n"],"names":["useCallback","useState","Alert","ClosableAlert","props","isVisible","setVisible","handleClose","onClose"],"mappings":";AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ClosableAlert.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ReactElement, useCallback, useState } from 'react';\nimport { Alert, AlertProps } from '@mui/material';\n\nexport function ClosableAlert(props: AlertProps): ReactElement | null {\n const [isVisible, setVisible] = useState(true);\n\n const handleClose = useCallback(() => {\n setVisible(false);\n }, [setVisible]);\n\n if (!isVisible) {\n return null;\n }\n\n return <Alert {...props} onClose={handleClose} />;\n}\n"],"names":["useCallback","useState","Alert","ClosableAlert","props","isVisible","setVisible","handleClose","onClose"],"mappings":";AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAAuBA,WAAW,EAAEC,QAAQ,QAAQ,QAAQ;AAC5D,SAASC,KAAK,QAAoB,gBAAgB;AAElD,OAAO,SAASC,cAAcC,KAAiB;IAC7C,MAAM,CAACC,WAAWC,WAAW,GAAGL,SAAS;IAEzC,MAAMM,cAAcP,YAAY;QAC9BM,WAAW;IACb,GAAG;QAACA;KAAW;IAEf,IAAI,CAACD,WAAW;QACd,OAAO;IACT;IAEA,qBAAO,KAACH;QAAO,GAAGE,KAAK;QAAEI,SAASD;;AACpC"}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import { insertCompletionText } from '@codemirror/autocomplete';
|
|
14
14
|
import { syntaxTree } from '@codemirror/language';
|
|
15
15
|
import { String as StringType, FieldExpression, AttributeField, Resource, Identifier, Span, SpansetFilter, FieldOp } from '@grafana/lezer-traceql';
|
|
16
|
-
import { getUnixTimeRange } from '../plugins
|
|
16
|
+
import { getUnixTimeRange } from '../plugins';
|
|
17
17
|
const quoteChars = [
|
|
18
18
|
'"',
|
|
19
19
|
'`'
|