@perses-dev/tempo-plugin 0.53.2 → 0.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/__mf/css/async/1576.d3010b86.css +1 -0
  2. package/__mf/css/async/2188.d3010b86.css +1 -0
  3. package/__mf/css/async/2341.d3010b86.css +1 -0
  4. package/__mf/js/{Tempo.2d6235bb.js → Tempo.146e84b3.js} +4 -4
  5. package/__mf/js/async/{6495.eae3d4b4.js → 1197.850698db.js} +1 -1
  6. package/__mf/js/async/1576.1cf74df0.js +1 -0
  7. package/__mf/js/async/2178.6b2e432f.js +2 -0
  8. package/__mf/js/async/2188.685c7491.js +2 -0
  9. package/__mf/js/async/2472.cc8dcf44.js +22 -0
  10. package/__mf/js/async/{9368.f0418d24.js → 2972.32076d91.js} +4 -4
  11. package/__mf/js/async/{4075.4c5ac93a.js → 4075.edf1dc62.js} +1 -1
  12. package/__mf/js/async/{4238.7962a7a1.js → 4238.9b78e9fe.js} +1 -1
  13. package/__mf/js/async/4310.7407645f.js +7 -0
  14. package/__mf/js/async/4421.5f2a2324.js +1 -0
  15. package/__mf/js/async/4535.72cddf33.js +1 -0
  16. package/__mf/js/async/6134.a2707cf7.js +38 -0
  17. package/__mf/js/async/6620.c48ce7b1.js +2 -0
  18. package/__mf/js/async/7569.842552f0.js +1 -0
  19. package/__mf/js/async/800.7f3113d0.js +2 -0
  20. package/__mf/js/async/__federation_expose_TempoDatasource.9aa3663e.js +2 -0
  21. package/__mf/js/async/__federation_expose_TempoExplorer.354aef77.js +2 -0
  22. package/__mf/js/async/__federation_expose_TempoTraceQuery.810d0c2c.js +1 -0
  23. package/__mf/js/{main.a9e2b86c.js → main.b263c225.js} +3 -3
  24. package/lib/cjs/components/AttributeFilters.js +5 -22
  25. package/lib/cjs/components/TraceQLEditor.js +3 -3
  26. package/lib/cjs/components/complete.js +3 -15
  27. package/lib/components/AttributeFilters.d.ts.map +1 -1
  28. package/lib/components/AttributeFilters.js +5 -17
  29. package/lib/components/AttributeFilters.js.map +1 -1
  30. package/lib/components/TraceQLEditor.js +3 -3
  31. package/lib/components/TraceQLEditor.js.map +1 -1
  32. package/lib/components/TraceQLExtension.d.ts +2 -2
  33. package/lib/components/TraceQLExtension.d.ts.map +1 -1
  34. package/lib/components/TraceQLExtension.js.map +1 -1
  35. package/lib/components/complete.d.ts.map +1 -1
  36. package/lib/components/complete.js +3 -15
  37. package/lib/components/complete.js.map +1 -1
  38. package/mf-manifest.json +54 -54
  39. package/mf-stats.json +54 -54
  40. package/package.json +9 -9
  41. package/__mf/css/async/1576.c10cf504.css +0 -1
  42. package/__mf/css/async/2341.c10cf504.css +0 -1
  43. package/__mf/css/async/9314.c10cf504.css +0 -1
  44. package/__mf/js/async/1576.83b7de56.js +0 -1
  45. package/__mf/js/async/2981.8fe4ed12.js +0 -2
  46. package/__mf/js/async/3391.41e6de04.js +0 -73
  47. package/__mf/js/async/4368.2c879fe0.js +0 -2
  48. package/__mf/js/async/4421.838809cd.js +0 -1
  49. package/__mf/js/async/4535.7c92d3fd.js +0 -1
  50. package/__mf/js/async/6286.6e0d8da6.js +0 -7
  51. package/__mf/js/async/6714.11904981.js +0 -2
  52. package/__mf/js/async/6751.03514b88.js +0 -1
  53. package/__mf/js/async/7127.a0877987.js +0 -38
  54. package/__mf/js/async/9314.4b8565a0.js +0 -2
  55. package/__mf/js/async/__federation_expose_TempoDatasource.a20f4483.js +0 -2
  56. package/__mf/js/async/__federation_expose_TempoExplorer.bc71c3ab.js +0 -2
  57. package/__mf/js/async/__federation_expose_TempoTraceQuery.3098cb27.js +0 -1
  58. /package/__mf/js/async/{4368.2c879fe0.js.LICENSE.txt → 2178.6b2e432f.js.LICENSE.txt} +0 -0
  59. /package/__mf/js/async/{2981.8fe4ed12.js.LICENSE.txt → 2188.685c7491.js.LICENSE.txt} +0 -0
  60. /package/__mf/js/async/{3391.41e6de04.js.LICENSE.txt → 2472.cc8dcf44.js.LICENSE.txt} +0 -0
  61. /package/__mf/js/async/{6286.6e0d8da6.js.LICENSE.txt → 4310.7407645f.js.LICENSE.txt} +0 -0
  62. /package/__mf/js/async/{6714.11904981.js.LICENSE.txt → 6620.c48ce7b1.js.LICENSE.txt} +0 -0
  63. /package/__mf/js/async/{9314.4b8565a0.js.LICENSE.txt → 800.7f3113d0.js.LICENSE.txt} +0 -0
  64. /package/__mf/js/async/{__federation_expose_TempoDatasource.a20f4483.js.LICENSE.txt → __federation_expose_TempoDatasource.9aa3663e.js.LICENSE.txt} +0 -0
  65. /package/__mf/js/async/{__federation_expose_TempoExplorer.bc71c3ab.js.LICENSE.txt → __federation_expose_TempoExplorer.354aef77.js.LICENSE.txt} +0 -0
@@ -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 _core = require("@perses-dev/core");
37
+ const _tempotracequery = require("../plugins/tempo-trace-query");
38
38
  const quoteChars = [
39
39
  '"',
40
40
  '`'
@@ -290,23 +290,11 @@ function identifyCompletions(state, pos, tree) {
290
290
  const options = await Promise.all(results);
291
291
  return options.flat();
292
292
  }
293
- function getUnixTimeRange(timeRange) {
294
- if (!timeRange) {
295
- return {};
296
- }
297
- const absTimeRange = !(0, _core.isAbsoluteTimeRange)(timeRange) ? (0, _core.toAbsoluteTimeRange)(timeRange) : timeRange;
298
- const start = Math.round(absTimeRange.start.getTime() / 1000);
299
- const end = Math.round(absTimeRange.end.getTime() / 1000);
300
- return {
301
- start,
302
- end
303
- };
304
- }
305
293
  async function completeTagName(completionCfg, scope) {
306
294
  if (!completionCfg.client) {
307
295
  return [];
308
296
  }
309
- const { start, end } = getUnixTimeRange(completionCfg.timeRange);
297
+ const { start, end } = completionCfg.timeRange ? (0, _tempotracequery.getUnixTimeRange)(completionCfg.timeRange) : {};
310
298
  const { limit, maxStaleValues } = completionCfg;
311
299
  const response = await completionCfg.client.searchTags({
312
300
  scope,
@@ -352,7 +340,7 @@ async function completeTagValue(completionCfg, tag) {
352
340
  if (!completionCfg.client) {
353
341
  return [];
354
342
  }
355
- const { start, end } = getUnixTimeRange(completionCfg.timeRange);
343
+ const { start, end } = completionCfg.timeRange ? (0, _tempotracequery.getUnixTimeRange)(completionCfg.timeRange) : {};
356
344
  const { limit, maxStaleValues } = completionCfg;
357
345
  const response = await completionCfg.client.searchTagValues({
358
346
  tag,
@@ -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;AAOvF,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAOvC,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,CA6D3E"}
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;AAQvC,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,CA2D3E"}
@@ -13,11 +13,9 @@
13
13
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
14
14
  import { useCallback, useEffect, useState } from 'react';
15
15
  import { Autocomplete, Checkbox, Stack, TextField } from '@mui/material';
16
- import { isAbsoluteTimeRange, toAbsoluteTimeRange } from '@perses-dev/core';
17
16
  import { useTimeRange } from '@perses-dev/plugin-system';
18
17
  import { useQuery } from '@tanstack/react-query';
19
- import CheckboxOutline from 'mdi-material-ui/CheckboxOutline';
20
- import CheckboxBlankOutline from 'mdi-material-ui/CheckboxBlankOutline';
18
+ import { getUnixTimeRange } from '../plugins/tempo-trace-query/get-trace-data';
21
19
  import { filterToTraceQL } from './filter/filter_to_traceql';
22
20
  import { traceQLToFilter } from './filter/traceql_to_filter';
23
21
  import { splitByUnquotedWhitespace } from './filter/filter';
@@ -32,18 +30,16 @@ export function AttributeFilters(props) {
32
30
  const setFilter = (filter)=>{
33
31
  setQuery(filterToTraceQL(filter));
34
32
  };
35
- const { timeRange } = useTimeRange();
36
- const absTimeRange = !isAbsoluteTimeRange(timeRange) ? toAbsoluteTimeRange(timeRange) : timeRange;
37
- const startTime = Math.round(absTimeRange.start.getTime() / 1000);
38
- const endTime = Math.round(absTimeRange.end.getTime() / 1000);
33
+ const { absoluteTimeRange } = useTimeRange();
34
+ const { start, end } = getUnixTimeRange(absoluteTimeRange);
39
35
  const { data: serviceNameOptions } = useTagValues(client, 'resource.service.name', filterToTraceQL({
40
36
  ...filter,
41
37
  serviceName: []
42
- }), startTime, endTime);
38
+ }), start, end);
43
39
  const { data: spanNameOptions } = useTagValues(client, 'name', filterToTraceQL({
44
40
  ...filter,
45
41
  spanName: []
46
- }), startTime, endTime);
42
+ }), start, end);
47
43
  return /*#__PURE__*/ _jsxs(_Fragment, {
48
44
  children: [
49
45
  /*#__PURE__*/ _jsx(StringAttributeFilter, {
@@ -93,12 +89,6 @@ export function AttributeFilters(props) {
93
89
  ]
94
90
  });
95
91
  }
96
- const checkboxBlankIcon = /*#__PURE__*/ _jsx(CheckboxBlankOutline, {
97
- fontSize: "small"
98
- });
99
- const checkedMarkedIcon = /*#__PURE__*/ _jsx(CheckboxOutline, {
100
- fontSize: "small"
101
- });
102
92
  function StringAttributeFilter(props) {
103
93
  const { label, width, options, value, setValue } = props;
104
94
  return /*#__PURE__*/ _jsx(Autocomplete, {
@@ -115,8 +105,6 @@ function StringAttributeFilter(props) {
115
105
  ...optionProps,
116
106
  children: [
117
107
  /*#__PURE__*/ _jsx(Checkbox, {
118
- icon: checkboxBlankIcon,
119
- checkedIcon: checkedMarkedIcon,
120
108
  style: {
121
109
  marginRight: 8
122
110
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/AttributeFilters.tsx"],"sourcesContent":["// Copyright 2025 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 { isAbsoluteTimeRange, toAbsoluteTimeRange } from '@perses-dev/core';\nimport { useTimeRange } from '@perses-dev/plugin-system';\nimport { useQuery } from '@tanstack/react-query';\nimport CheckboxOutline from 'mdi-material-ui/CheckboxOutline';\nimport CheckboxBlankOutline from 'mdi-material-ui/CheckboxBlankOutline';\nimport { TempoClient } from '../model';\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 { timeRange } = useTimeRange();\n const absTimeRange = !isAbsoluteTimeRange(timeRange) ? toAbsoluteTimeRange(timeRange) : timeRange;\n const startTime = Math.round(absTimeRange.start.getTime() / 1000);\n const endTime = Math.round(absTimeRange.end.getTime() / 1000);\n\n const { data: serviceNameOptions } = useTagValues(\n client,\n 'resource.service.name',\n filterToTraceQL({ ...filter, serviceName: [] }),\n startTime,\n endTime\n );\n const { data: spanNameOptions } = useTagValues(\n client,\n 'name',\n filterToTraceQL({ ...filter, spanName: [] }),\n startTime,\n endTime\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\nconst checkboxBlankIcon = <CheckboxBlankOutline fontSize=\"small\" />;\nconst checkedMarkedIcon = <CheckboxOutline fontSize=\"small\" />;\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\n icon={checkboxBlankIcon}\n checkedIcon={checkedMarkedIcon}\n style={{ marginRight: 8 }}\n checked={selected}\n />\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","isAbsoluteTimeRange","toAbsoluteTimeRange","useTimeRange","useQuery","CheckboxOutline","CheckboxBlankOutline","filterToTraceQL","traceQLToFilter","splitByUnquotedWhitespace","statusOptions","AttributeFilters","props","client","query","setQuery","filter","setFilter","timeRange","absTimeRange","startTime","Math","round","start","getTime","endTime","end","data","serviceNameOptions","useTagValues","serviceName","spanNameOptions","spanName","StringAttributeFilter","label","options","value","setValue","x","width","status","DurationAttributeFilter","traceDuration","CustomAttributesFilter","customMatchers","checkboxBlankIcon","fontSize","checkedMarkedIcon","multiple","size","limitTags","disableCloseOnSelect","onChange","_event","newValue","renderOption","option","selected","key","optionProps","li","icon","checkedIcon","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 2025 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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"}
@@ -20,15 +20,15 @@ import { TraceQLExtension } from './TraceQLExtension';
20
20
  export function TraceQLEditor({ client, ...rest }) {
21
21
  const theme = useTheme();
22
22
  const isDarkMode = theme.palette.mode === 'dark';
23
- const { timeRange } = useTimeRange();
23
+ const { absoluteTimeRange } = useTimeRange();
24
24
  const traceQLExtension = useMemo(()=>{
25
25
  return TraceQLExtension({
26
26
  client,
27
- timeRange
27
+ timeRange: absoluteTimeRange
28
28
  });
29
29
  }, [
30
30
  client,
31
- timeRange
31
+ absoluteTimeRange
32
32
  ]);
33
33
  const codemirrorTheme = useMemo(()=>{
34
34
  // https://github.com/mui/material-ui/blob/v5.16.7/packages/mui-material/src/OutlinedInput/OutlinedInput.js#L43
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/TraceQLEditor.tsx"],"sourcesContent":["// Copyright 2025 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, useMemo } from 'react';\nimport { InputLabel, Stack, useTheme } from '@mui/material';\nimport CodeMirror, { EditorView, ReactCodeMirrorProps } from '@uiw/react-codemirror';\nimport { isValidTraceId } from '@perses-dev/core';\nimport { useTimeRange } from '@perses-dev/plugin-system';\nimport { TempoClient } from '../model';\nimport { TraceQLExtension } from './TraceQLExtension';\n\nexport interface TraceQLEditorProps extends Omit<ReactCodeMirrorProps, 'theme' | 'extensions'> {\n client?: TempoClient;\n}\n\nexport function TraceQLEditor({ client, ...rest }: TraceQLEditorProps): ReactElement {\n const theme = useTheme();\n const isDarkMode = theme.palette.mode === 'dark';\n\n const { timeRange } = useTimeRange();\n const traceQLExtension = useMemo(() => {\n return TraceQLExtension({ client, timeRange });\n }, [client, timeRange]);\n\n const codemirrorTheme = useMemo(() => {\n // https://github.com/mui/material-ui/blob/v5.16.7/packages/mui-material/src/OutlinedInput/OutlinedInput.js#L43\n const borderColor = theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)';\n\n return EditorView.theme({\n '&': {\n backgroundColor: 'transparent !important', // required for dark mode\n border: `1px solid ${borderColor}`,\n borderRadius: `${theme.shape.borderRadius}px`,\n },\n '&.cm-focused.cm-editor': {\n outline: 'none', // remove dotted outline on focus\n },\n '.cm-content': {\n padding: '8px',\n },\n });\n }, [theme]);\n\n return (\n <Stack position=\"relative\" sx={{ flexGrow: 1 }}>\n <InputLabel // reproduce the same kind of input label that regular MUI TextFields have\n shrink\n sx={{\n position: 'absolute',\n top: '-6px',\n left: '10px',\n padding: '0 4px',\n color: theme.palette.text.primary,\n backgroundColor: theme.palette.background.default,\n zIndex: 1,\n }}\n >\n TraceQL Expression\n </InputLabel>\n <CodeMirror\n {...rest}\n theme={isDarkMode ? 'dark' : 'light'}\n basicSetup={{\n lineNumbers: false,\n highlightActiveLine: false,\n highlightActiveLineGutter: false,\n foldGutter: false,\n // The explore view accepts either a TraceQL query or a Trace ID as input. The lezer grammar marks Trace IDs as invalid,\n // therefore let's disable syntax highlighting if the input is a Trace ID.\n syntaxHighlighting: !isValidTraceId(rest.value ?? ''),\n }}\n extensions={[EditorView.lineWrapping, traceQLExtension, codemirrorTheme]}\n placeholder='Example: {span.http.method = \"GET\"}'\n />\n </Stack>\n );\n}\n"],"names":["useMemo","InputLabel","Stack","useTheme","CodeMirror","EditorView","isValidTraceId","useTimeRange","TraceQLExtension","TraceQLEditor","client","rest","theme","isDarkMode","palette","mode","timeRange","traceQLExtension","codemirrorTheme","borderColor","backgroundColor","border","borderRadius","shape","outline","padding","position","sx","flexGrow","shrink","top","left","color","text","primary","background","default","zIndex","basicSetup","lineNumbers","highlightActiveLine","highlightActiveLineGutter","foldGutter","syntaxHighlighting","value","extensions","lineWrapping","placeholder"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAAuBA,OAAO,QAAQ,QAAQ;AAC9C,SAASC,UAAU,EAAEC,KAAK,EAAEC,QAAQ,QAAQ,gBAAgB;AAC5D,OAAOC,cAAcC,UAAU,QAA8B,wBAAwB;AACrF,SAASC,cAAc,QAAQ,mBAAmB;AAClD,SAASC,YAAY,QAAQ,4BAA4B;AAEzD,SAASC,gBAAgB,QAAQ,qBAAqB;AAMtD,OAAO,SAASC,cAAc,EAAEC,MAAM,EAAE,GAAGC,MAA0B;IACnE,MAAMC,QAAQT;IACd,MAAMU,aAAaD,MAAME,OAAO,CAACC,IAAI,KAAK;IAE1C,MAAM,EAAEC,SAAS,EAAE,GAAGT;IACtB,MAAMU,mBAAmBjB,QAAQ;QAC/B,OAAOQ,iBAAiB;YAAEE;YAAQM;QAAU;IAC9C,GAAG;QAACN;QAAQM;KAAU;IAEtB,MAAME,kBAAkBlB,QAAQ;QAC9B,+GAA+G;QAC/G,MAAMmB,cAAcP,MAAME,OAAO,CAACC,IAAI,KAAK,UAAU,wBAAwB;QAE7E,OAAOV,WAAWO,KAAK,CAAC;YACtB,KAAK;gBACHQ,iBAAiB;gBACjBC,QAAQ,CAAC,UAAU,EAAEF,aAAa;gBAClCG,cAAc,GAAGV,MAAMW,KAAK,CAACD,YAAY,CAAC,EAAE,CAAC;YAC/C;YACA,0BAA0B;gBACxBE,SAAS;YACX;YACA,eAAe;gBACbC,SAAS;YACX;QACF;IACF,GAAG;QAACb;KAAM;IAEV,qBACE,MAACV;QAAMwB,UAAS;QAAWC,IAAI;YAAEC,UAAU;QAAE;;0BAC3C,KAAC3B,WAAW,0EAA0E;;gBACpF4B,MAAM;gBACNF,IAAI;oBACFD,UAAU;oBACVI,KAAK;oBACLC,MAAM;oBACNN,SAAS;oBACTO,OAAOpB,MAAME,OAAO,CAACmB,IAAI,CAACC,OAAO;oBACjCd,iBAAiBR,MAAME,OAAO,CAACqB,UAAU,CAACC,OAAO;oBACjDC,QAAQ;gBACV;0BACD;;0BAGD,KAACjC;gBACE,GAAGO,IAAI;gBACRC,OAAOC,aAAa,SAAS;gBAC7ByB,YAAY;oBACVC,aAAa;oBACbC,qBAAqB;oBACrBC,2BAA2B;oBAC3BC,YAAY;oBACZ,wHAAwH;oBACxH,0EAA0E;oBAC1EC,oBAAoB,CAACrC,eAAeK,KAAKiC,KAAK,IAAI;gBACpD;gBACAC,YAAY;oBAACxC,WAAWyC,YAAY;oBAAE7B;oBAAkBC;iBAAgB;gBACxE6B,aAAY;;;;AAIpB"}
1
+ {"version":3,"sources":["../../../src/components/TraceQLEditor.tsx"],"sourcesContent":["// Copyright 2025 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, useMemo } from 'react';\nimport { InputLabel, Stack, useTheme } from '@mui/material';\nimport CodeMirror, { EditorView, ReactCodeMirrorProps } from '@uiw/react-codemirror';\nimport { isValidTraceId } from '@perses-dev/core';\nimport { useTimeRange } from '@perses-dev/plugin-system';\nimport { TempoClient } from '../model';\nimport { TraceQLExtension } from './TraceQLExtension';\n\nexport interface TraceQLEditorProps extends Omit<ReactCodeMirrorProps, 'theme' | 'extensions'> {\n client?: TempoClient;\n}\n\nexport function TraceQLEditor({ client, ...rest }: TraceQLEditorProps): ReactElement {\n const theme = useTheme();\n const isDarkMode = theme.palette.mode === 'dark';\n\n const { absoluteTimeRange } = useTimeRange();\n const traceQLExtension = useMemo(() => {\n return TraceQLExtension({ client, timeRange: absoluteTimeRange });\n }, [client, absoluteTimeRange]);\n\n const codemirrorTheme = useMemo(() => {\n // https://github.com/mui/material-ui/blob/v5.16.7/packages/mui-material/src/OutlinedInput/OutlinedInput.js#L43\n const borderColor = theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)';\n\n return EditorView.theme({\n '&': {\n backgroundColor: 'transparent !important', // required for dark mode\n border: `1px solid ${borderColor}`,\n borderRadius: `${theme.shape.borderRadius}px`,\n },\n '&.cm-focused.cm-editor': {\n outline: 'none', // remove dotted outline on focus\n },\n '.cm-content': {\n padding: '8px',\n },\n });\n }, [theme]);\n\n return (\n <Stack position=\"relative\" sx={{ flexGrow: 1 }}>\n <InputLabel // reproduce the same kind of input label that regular MUI TextFields have\n shrink\n sx={{\n position: 'absolute',\n top: '-6px',\n left: '10px',\n padding: '0 4px',\n color: theme.palette.text.primary,\n backgroundColor: theme.palette.background.default,\n zIndex: 1,\n }}\n >\n TraceQL Expression\n </InputLabel>\n <CodeMirror\n {...rest}\n theme={isDarkMode ? 'dark' : 'light'}\n basicSetup={{\n lineNumbers: false,\n highlightActiveLine: false,\n highlightActiveLineGutter: false,\n foldGutter: false,\n // The explore view accepts either a TraceQL query or a Trace ID as input. The lezer grammar marks Trace IDs as invalid,\n // therefore let's disable syntax highlighting if the input is a Trace ID.\n syntaxHighlighting: !isValidTraceId(rest.value ?? ''),\n }}\n extensions={[EditorView.lineWrapping, traceQLExtension, codemirrorTheme]}\n placeholder='Example: {span.http.method = \"GET\"}'\n />\n </Stack>\n );\n}\n"],"names":["useMemo","InputLabel","Stack","useTheme","CodeMirror","EditorView","isValidTraceId","useTimeRange","TraceQLExtension","TraceQLEditor","client","rest","theme","isDarkMode","palette","mode","absoluteTimeRange","traceQLExtension","timeRange","codemirrorTheme","borderColor","backgroundColor","border","borderRadius","shape","outline","padding","position","sx","flexGrow","shrink","top","left","color","text","primary","background","default","zIndex","basicSetup","lineNumbers","highlightActiveLine","highlightActiveLineGutter","foldGutter","syntaxHighlighting","value","extensions","lineWrapping","placeholder"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAAuBA,OAAO,QAAQ,QAAQ;AAC9C,SAASC,UAAU,EAAEC,KAAK,EAAEC,QAAQ,QAAQ,gBAAgB;AAC5D,OAAOC,cAAcC,UAAU,QAA8B,wBAAwB;AACrF,SAASC,cAAc,QAAQ,mBAAmB;AAClD,SAASC,YAAY,QAAQ,4BAA4B;AAEzD,SAASC,gBAAgB,QAAQ,qBAAqB;AAMtD,OAAO,SAASC,cAAc,EAAEC,MAAM,EAAE,GAAGC,MAA0B;IACnE,MAAMC,QAAQT;IACd,MAAMU,aAAaD,MAAME,OAAO,CAACC,IAAI,KAAK;IAE1C,MAAM,EAAEC,iBAAiB,EAAE,GAAGT;IAC9B,MAAMU,mBAAmBjB,QAAQ;QAC/B,OAAOQ,iBAAiB;YAAEE;YAAQQ,WAAWF;QAAkB;IACjE,GAAG;QAACN;QAAQM;KAAkB;IAE9B,MAAMG,kBAAkBnB,QAAQ;QAC9B,+GAA+G;QAC/G,MAAMoB,cAAcR,MAAME,OAAO,CAACC,IAAI,KAAK,UAAU,wBAAwB;QAE7E,OAAOV,WAAWO,KAAK,CAAC;YACtB,KAAK;gBACHS,iBAAiB;gBACjBC,QAAQ,CAAC,UAAU,EAAEF,aAAa;gBAClCG,cAAc,GAAGX,MAAMY,KAAK,CAACD,YAAY,CAAC,EAAE,CAAC;YAC/C;YACA,0BAA0B;gBACxBE,SAAS;YACX;YACA,eAAe;gBACbC,SAAS;YACX;QACF;IACF,GAAG;QAACd;KAAM;IAEV,qBACE,MAACV;QAAMyB,UAAS;QAAWC,IAAI;YAAEC,UAAU;QAAE;;0BAC3C,KAAC5B,WAAW,0EAA0E;;gBACpF6B,MAAM;gBACNF,IAAI;oBACFD,UAAU;oBACVI,KAAK;oBACLC,MAAM;oBACNN,SAAS;oBACTO,OAAOrB,MAAME,OAAO,CAACoB,IAAI,CAACC,OAAO;oBACjCd,iBAAiBT,MAAME,OAAO,CAACsB,UAAU,CAACC,OAAO;oBACjDC,QAAQ;gBACV;0BACD;;0BAGD,KAAClC;gBACE,GAAGO,IAAI;gBACRC,OAAOC,aAAa,SAAS;gBAC7B0B,YAAY;oBACVC,aAAa;oBACbC,qBAAqB;oBACrBC,2BAA2B;oBAC3BC,YAAY;oBACZ,wHAAwH;oBACxH,0EAA0E;oBAC1EC,oBAAoB,CAACtC,eAAeK,KAAKkC,KAAK,IAAI;gBACpD;gBACAC,YAAY;oBAACzC,WAAW0C,YAAY;oBAAE9B;oBAAkBE;iBAAgB;gBACxE6B,aAAY;;;;AAIpB"}
@@ -1,12 +1,12 @@
1
1
  import { LRLanguage } from '@codemirror/language';
2
2
  import { Extension } from '@uiw/react-codemirror';
3
- import { TimeRangeValue } from '@perses-dev/core';
3
+ import { AbsoluteTimeRange } from '@perses-dev/core';
4
4
  import { TempoClient } from '../model/tempo-client';
5
5
  export interface CompletionConfig {
6
6
  /** a TempoClient instance, can be created with TempoDatasource.createClient() */
7
7
  client?: TempoClient;
8
8
  /** search for tag values in a given time range */
9
- timeRange?: TimeRangeValue;
9
+ timeRange?: AbsoluteTimeRange;
10
10
  /** limit number of returned tag values */
11
11
  limit?: number;
12
12
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"TraceQLExtension.d.ts","sourceRoot":"","sources":["../../../src/components/TraceQLExtension.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGlD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAgBpD,MAAM,WAAW,gBAAgB;IAC/B,iFAAiF;IACjF,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB,kDAAkD;IAClD,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,gBAAgB,GAAG,KAAK,CAAC,UAAU,GAAG,SAAS,CAAC,CAO/F"}
1
+ {"version":3,"file":"TraceQLExtension.d.ts","sourceRoot":"","sources":["../../../src/components/TraceQLExtension.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGlD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAgBpD,MAAM,WAAW,gBAAgB;IAC/B,iFAAiF;IACjF,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB,kDAAkD;IAClD,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAE9B,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,gBAAgB,GAAG,KAAK,CAAC,UAAU,GAAG,SAAS,CAAC,CAO/F"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/TraceQLExtension.ts"],"sourcesContent":["// Copyright 2024 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 { LRLanguage } from '@codemirror/language';\nimport { parser } from '@grafana/lezer-traceql';\nimport { CompletionContext } from '@codemirror/autocomplete';\nimport { Extension } from '@uiw/react-codemirror';\nimport { TimeRangeValue } from '@perses-dev/core';\nimport { TempoClient } from '../model/tempo-client';\nimport { traceQLHighlight } from './highlight';\nimport { complete } from './complete';\n\nfunction traceQLLanguage(): LRLanguage {\n return LRLanguage.define({\n parser: parser.configure({\n props: [traceQLHighlight],\n }),\n languageData: {\n closeBrackets: { brackets: ['(', '[', '{', \"'\", '\"', '`'] },\n commentTokens: { line: '//' },\n },\n });\n}\n\nexport interface CompletionConfig {\n /** a TempoClient instance, can be created with TempoDatasource.createClient() */\n client?: TempoClient;\n\n /** search for tag values in a given time range */\n timeRange?: TimeRangeValue;\n\n /** limit number of returned tag values */\n limit?: number;\n\n /**\n * stop search early if number of cache hits exceeds this setting\n * https://grafana.com/docs/tempo/latest/api_docs/#search-tag-values-v2\n */\n maxStaleValues?: number;\n}\n\nexport function TraceQLExtension(completionCfg: CompletionConfig): Array<LRLanguage | Extension> {\n const language = traceQLLanguage();\n const completion = language.data.of({\n autocomplete: (ctx: CompletionContext) =>\n complete(completionCfg, ctx).catch((e) => console.error('error during TraceQL auto-complete', e)),\n });\n return [language, completion];\n}\n"],"names":["LRLanguage","parser","traceQLHighlight","complete","traceQLLanguage","define","configure","props","languageData","closeBrackets","brackets","commentTokens","line","TraceQLExtension","completionCfg","language","completion","data","of","autocomplete","ctx","catch","e","console","error"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,UAAU,QAAQ,uBAAuB;AAClD,SAASC,MAAM,QAAQ,yBAAyB;AAKhD,SAASC,gBAAgB,QAAQ,cAAc;AAC/C,SAASC,QAAQ,QAAQ,aAAa;AAEtC,SAASC;IACP,OAAOJ,WAAWK,MAAM,CAAC;QACvBJ,QAAQA,OAAOK,SAAS,CAAC;YACvBC,OAAO;gBAACL;aAAiB;QAC3B;QACAM,cAAc;YACZC,eAAe;gBAAEC,UAAU;oBAAC;oBAAK;oBAAK;oBAAK;oBAAK;oBAAK;iBAAI;YAAC;YAC1DC,eAAe;gBAAEC,MAAM;YAAK;QAC9B;IACF;AACF;AAmBA,OAAO,SAASC,iBAAiBC,aAA+B;IAC9D,MAAMC,WAAWX;IACjB,MAAMY,aAAaD,SAASE,IAAI,CAACC,EAAE,CAAC;QAClCC,cAAc,CAACC,MACbjB,SAASW,eAAeM,KAAKC,KAAK,CAAC,CAACC,IAAMC,QAAQC,KAAK,CAAC,sCAAsCF;IAClG;IACA,OAAO;QAACP;QAAUC;KAAW;AAC/B"}
1
+ {"version":3,"sources":["../../../src/components/TraceQLExtension.ts"],"sourcesContent":["// Copyright 2024 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 { LRLanguage } from '@codemirror/language';\nimport { parser } from '@grafana/lezer-traceql';\nimport { CompletionContext } from '@codemirror/autocomplete';\nimport { Extension } from '@uiw/react-codemirror';\nimport { AbsoluteTimeRange } from '@perses-dev/core';\nimport { TempoClient } from '../model/tempo-client';\nimport { traceQLHighlight } from './highlight';\nimport { complete } from './complete';\n\nfunction traceQLLanguage(): LRLanguage {\n return LRLanguage.define({\n parser: parser.configure({\n props: [traceQLHighlight],\n }),\n languageData: {\n closeBrackets: { brackets: ['(', '[', '{', \"'\", '\"', '`'] },\n commentTokens: { line: '//' },\n },\n });\n}\n\nexport interface CompletionConfig {\n /** a TempoClient instance, can be created with TempoDatasource.createClient() */\n client?: TempoClient;\n\n /** search for tag values in a given time range */\n timeRange?: AbsoluteTimeRange;\n\n /** limit number of returned tag values */\n limit?: number;\n\n /**\n * stop search early if number of cache hits exceeds this setting\n * https://grafana.com/docs/tempo/latest/api_docs/#search-tag-values-v2\n */\n maxStaleValues?: number;\n}\n\nexport function TraceQLExtension(completionCfg: CompletionConfig): Array<LRLanguage | Extension> {\n const language = traceQLLanguage();\n const completion = language.data.of({\n autocomplete: (ctx: CompletionContext) =>\n complete(completionCfg, ctx).catch((e) => console.error('error during TraceQL auto-complete', e)),\n });\n return [language, completion];\n}\n"],"names":["LRLanguage","parser","traceQLHighlight","complete","traceQLLanguage","define","configure","props","languageData","closeBrackets","brackets","commentTokens","line","TraceQLExtension","completionCfg","language","completion","data","of","autocomplete","ctx","catch","e","console","error"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,UAAU,QAAQ,uBAAuB;AAClD,SAASC,MAAM,QAAQ,yBAAyB;AAKhD,SAASC,gBAAgB,QAAQ,cAAc;AAC/C,SAASC,QAAQ,QAAQ,aAAa;AAEtC,SAASC;IACP,OAAOJ,WAAWK,MAAM,CAAC;QACvBJ,QAAQA,OAAOK,SAAS,CAAC;YACvBC,OAAO;gBAACL;aAAiB;QAC3B;QACAM,cAAc;YACZC,eAAe;gBAAEC,UAAU;oBAAC;oBAAK;oBAAK;oBAAK;oBAAK;oBAAK;iBAAI;YAAC;YAC1DC,eAAe;gBAAEC,MAAM;YAAK;QAC9B;IACF;AACF;AAmBA,OAAO,SAASC,iBAAiBC,aAA+B;IAC9D,MAAMC,WAAWX;IACjB,MAAMY,aAAaD,SAASE,IAAI,CAACC,EAAE,CAAC;QAClCC,cAAc,CAACC,MACbjB,SAASW,eAAeM,KAAKC,KAAK,CAAC,CAACC,IAAMC,QAAQC,KAAK,CAAC,sCAAsCF;IAClG;IACA,OAAO;QAACP;QAAUC;KAAW;AAC/B"}
@@ -1 +1 @@
1
- {"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../../src/components/complete.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,gBAAgB,EAAwB,MAAM,0BAA0B,CAAC;AAEjH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAWrC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,uGAAuG;AACvG,KAAK,eAAe,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,WAAW,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAKD,wBAAsB,QAAQ,CAC5B,aAAa,EAAE,gBAAgB,EAC/B,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,iBAAiB,GAChC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAWlC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,WAAW,GAAG,SAAS,CA4HxG;AAqED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAmB9G"}
1
+ {"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../../src/components/complete.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,gBAAgB,EAAwB,MAAM,0BAA0B,CAAC;AAEjH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAWrC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,uGAAuG;AACvG,KAAK,eAAe,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,WAAW,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAKD,wBAAsB,QAAQ,CAC5B,aAAa,EAAE,gBAAgB,EAC/B,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,iBAAiB,GAChC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAWlC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,WAAW,GAAG,SAAS,CA4HxG;AA0DD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAmB9G"}
@@ -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 { isAbsoluteTimeRange, toAbsoluteTimeRange } from '@perses-dev/core';
16
+ import { getUnixTimeRange } from '../plugins/tempo-trace-query';
17
17
  const quoteChars = [
18
18
  '"',
19
19
  '`'
@@ -276,23 +276,11 @@ export async function complete(completionCfg, { state, pos }) {
276
276
  const options = await Promise.all(results);
277
277
  return options.flat();
278
278
  }
279
- function getUnixTimeRange(timeRange) {
280
- if (!timeRange) {
281
- return {};
282
- }
283
- const absTimeRange = !isAbsoluteTimeRange(timeRange) ? toAbsoluteTimeRange(timeRange) : timeRange;
284
- const start = Math.round(absTimeRange.start.getTime() / 1000);
285
- const end = Math.round(absTimeRange.end.getTime() / 1000);
286
- return {
287
- start,
288
- end
289
- };
290
- }
291
279
  async function completeTagName(completionCfg, scope) {
292
280
  if (!completionCfg.client) {
293
281
  return [];
294
282
  }
295
- const { start, end } = getUnixTimeRange(completionCfg.timeRange);
283
+ const { start, end } = completionCfg.timeRange ? getUnixTimeRange(completionCfg.timeRange) : {};
296
284
  const { limit, maxStaleValues } = completionCfg;
297
285
  const response = await completionCfg.client.searchTags({
298
286
  scope,
@@ -344,7 +332,7 @@ async function completeTagValue(completionCfg, tag) {
344
332
  if (!completionCfg.client) {
345
333
  return [];
346
334
  }
347
- const { start, end } = getUnixTimeRange(completionCfg.timeRange);
335
+ const { start, end } = completionCfg.timeRange ? getUnixTimeRange(completionCfg.timeRange) : {};
348
336
  const { limit, maxStaleValues } = completionCfg;
349
337
  const response = await completionCfg.client.searchTagValues({
350
338
  tag,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/complete.ts"],"sourcesContent":["// Copyright 2024 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 { Completion, CompletionContext, CompletionResult, insertCompletionText } from '@codemirror/autocomplete';\nimport { syntaxTree } from '@codemirror/language';\nimport { EditorState } from '@codemirror/state';\nimport { Tree } from '@lezer/common';\nimport {\n String as StringType,\n FieldExpression,\n AttributeField,\n Resource,\n Identifier,\n Span,\n SpansetFilter,\n FieldOp,\n} from '@grafana/lezer-traceql';\nimport { EditorView } from '@uiw/react-codemirror';\nimport { isAbsoluteTimeRange, TimeRangeValue, toAbsoluteTimeRange } from '@perses-dev/core';\nimport { CompletionConfig } from './TraceQLExtension';\n\n/** CompletionScope specifies the completion kind, e.g. whether to complete tag names or values etc. */\ntype CompletionScope =\n | { kind: 'Scopes' } // 'resource'|'span'\n | { kind: 'TagName'; scope: 'resource' | 'span' | 'intrinsic' }\n | { kind: 'TagValue'; tag: string };\n\n/**\n * Completions specifies the identified scopes and position of the completion in the current editor text.\n * For example, when entering '{' the following completions are possible: Scopes(), TagName(scope=intrinsic)\n */\nexport interface Completions {\n scopes: CompletionScope[];\n from: number;\n to?: number;\n}\n\nconst quoteChars = ['\"', '`'];\nconst defaultQuoteChar = '\"';\n\nexport async function complete(\n completionCfg: CompletionConfig,\n { state, pos }: CompletionContext\n): Promise<CompletionResult | null> {\n // First, identify the completion scopes, for example Scopes() and TagName(scope=intrinsic)\n const completions = identifyCompletions(state, pos, syntaxTree(state));\n if (!completions) {\n // No completion scopes found for current cursor position.\n return null;\n }\n\n // Then, retrieve completion options for all identified scopes (from the Tempo API).\n const options = await retrieveOptions(completionCfg, completions.scopes);\n return { options, from: completions.from, to: completions.to };\n}\n\n/**\n * Identify completion scopes (e.g. TagValue) and position, based on the current node in the syntax tree.\n *\n * For development, you can visualize the tree of a TraceQL query using this tool:\n * https://github.com/grafana/lezer-traceql/blob/main/tools/tree-viz.html\n *\n * Function is exported for tests only.\n */\nexport function identifyCompletions(state: EditorState, pos: number, tree: Tree): Completions | undefined {\n const node = tree.resolveInner(pos, -1);\n\n switch (node.type.id) {\n case SpansetFilter:\n // autocomplete {\n // autocomplete {}\n // do not autocomplete if cursor is after } or { status=ok }\n if (\n (node.firstChild === null || node.firstChild?.type.id === 0) &&\n !state.sliceDoc(node.from, pos).includes('}')\n ) {\n return {\n scopes: [{ kind: 'Scopes' }, { kind: 'TagName', scope: 'intrinsic' }],\n from: pos,\n };\n }\n break;\n\n case FieldExpression:\n // autocomplete { status=ok &&\n return {\n scopes: [{ kind: 'Scopes' }, { kind: 'TagName', scope: 'intrinsic' }],\n from: pos,\n };\n\n case AttributeField:\n // autocomplete { resource.\n if (node.firstChild?.type.id === Resource) {\n return { scopes: [{ kind: 'TagName', scope: 'resource' }], from: pos };\n }\n\n // autocomplete { span.\n if (node.firstChild?.type.id === Span) {\n return { scopes: [{ kind: 'TagName', scope: 'span' }], from: pos };\n }\n\n // autocomplete { .\n if (state.sliceDoc(node.from, node.to) === '.') {\n return {\n scopes: [\n { kind: 'TagName', scope: 'resource' },\n { kind: 'TagName', scope: 'span' },\n ],\n from: pos,\n };\n }\n break;\n\n case Identifier:\n if (node.parent?.type.id === AttributeField) {\n const text = state.sliceDoc(node.parent.from, node.parent.to);\n // autocomplete { span:s\n // only intrinsic fields can have a : in the name.\n if (text.includes(':')) {\n return { scopes: [{ kind: 'TagName', scope: 'intrinsic' }], from: node.parent.from };\n }\n\n // autocomplete { resource.s\n if (node.parent?.firstChild?.type.id === Resource) {\n return { scopes: [{ kind: 'TagName', scope: 'resource' }], from: node.from };\n }\n\n // autocomplete { span.s\n if (node.parent?.firstChild?.type.id === Span) {\n return { scopes: [{ kind: 'TagName', scope: 'span' }], from: node.from };\n }\n\n // autocomplete { .s\n if (node.parent?.firstChild?.type.id === Identifier) {\n return {\n scopes: [\n { kind: 'TagName', scope: 'resource' },\n { kind: 'TagName', scope: 'span' },\n ],\n from: node.from,\n };\n }\n }\n break;\n\n case FieldOp:\n // autocomplete { status=\n // autocomplete { span.http.method=\n if (node.parent?.firstChild?.type.id === FieldExpression) {\n const fieldExpr = node.parent.firstChild;\n const attribute = state.sliceDoc(fieldExpr.from, fieldExpr.to);\n return { scopes: [{ kind: 'TagValue', tag: attribute }], from: pos };\n }\n break;\n\n case StringType:\n // autocomplete { resource.service.name=\"\n // do not autocomplete if cursor is after closing quotes { resource.service.name=\"\"\n if (\n node.parent?.parent?.parent?.firstChild?.type.id === FieldExpression &&\n !/^\".*\"$/.test(state.sliceDoc(node.from, pos))\n ) {\n const fieldExpr = node.parent.parent.parent.firstChild;\n const attribute = state.sliceDoc(fieldExpr.from, fieldExpr.to);\n return { scopes: [{ kind: 'TagValue', tag: attribute }], from: node.from + 1 }; // node.from+1 to ignore leading \"\n }\n break;\n\n case 0 /* error node */:\n // autocomplete { status=e\n if (node.prevSibling?.type.id === FieldOp && node.parent?.firstChild?.type.id === FieldExpression) {\n const fieldExpr = node.parent.firstChild;\n const attribute = state.sliceDoc(fieldExpr.from, fieldExpr.to);\n // ignore leading \" in { name=\"HT\n const from = quoteChars.includes(state.sliceDoc(node.from, node.from + 1)) ? node.from + 1 : node.from;\n return { scopes: [{ kind: 'TagValue', tag: attribute }], from };\n }\n\n // autocomplete { s\n // autocomplete { status=ok && s\n if (node.parent?.type.id === SpansetFilter || node.parent?.type.id === FieldExpression) {\n return {\n scopes: [{ kind: 'Scopes' }, { kind: 'TagName', scope: 'intrinsic' }],\n from: node.from,\n };\n }\n break;\n }\n}\n\n/**\n * Retrieve all completion options based on the previously identified completion scopes.\n */\nasync function retrieveOptions(completionCfg: CompletionConfig, completions: CompletionScope[]): Promise<Completion[]> {\n const results: Array<Promise<Completion[]>> = [];\n\n for (const completion of completions) {\n switch (completion.kind) {\n case 'Scopes':\n results.push(Promise.resolve([{ label: 'span' }, { label: 'resource' }]));\n break;\n\n case 'TagName':\n results.push(completeTagName(completionCfg, completion.scope));\n break;\n\n case 'TagValue':\n results.push(completeTagValue(completionCfg, completion.tag));\n break;\n }\n }\n\n // Retrieve options concurrently\n // e.g. for unscoped attribute fields, retrieve list of span and resource attributes concurrently.\n const options = await Promise.all(results);\n return options.flat();\n}\n\nfunction getUnixTimeRange(timeRange?: TimeRangeValue): { start?: number; end?: number } {\n if (!timeRange) {\n return {};\n }\n\n const absTimeRange = !isAbsoluteTimeRange(timeRange) ? toAbsoluteTimeRange(timeRange) : timeRange;\n const start = Math.round(absTimeRange.start.getTime() / 1000);\n const end = Math.round(absTimeRange.end.getTime() / 1000);\n return { start, end };\n}\n\nasync function completeTagName(\n completionCfg: CompletionConfig,\n scope: 'resource' | 'span' | 'intrinsic'\n): Promise<Completion[]> {\n if (!completionCfg.client) {\n return [];\n }\n\n const { start, end } = getUnixTimeRange(completionCfg.timeRange);\n const { limit, maxStaleValues } = completionCfg;\n\n const response = await completionCfg.client.searchTags({ scope, start, end, limit, maxStaleValues });\n return response.scopes.flatMap((scope) => scope.tags).map((tag) => ({ label: tag }));\n}\n\nfunction escapeString(input: string, quoteChar: string) {\n // do not escape raw strings (when using backticks)\n if (quoteChar === '`') {\n return input;\n }\n\n let escaped = input;\n // escape sequences: https://grafana.com/docs/tempo/v2.8.x/traceql/construct-traceql-queries/#quoted-attribute-names\n escaped = escaped.replaceAll('\\\\', '\\\\\\\\');\n escaped = escaped.replaceAll('\"', '\\\\\"');\n return escaped;\n}\n\n/**\n * Add quotes to the completion text in case quotes are not present already.\n * This handles the following cases:\n * { name=HTTP\n * { name=\"x\n * { name=\"x\" where cursor is after the 'x'\n */\nexport function applyQuotedCompletion(view: EditorView, completion: Completion, from: number, to: number): void {\n let quoteChar = defaultQuoteChar;\n if (quoteChars.includes(view.state.sliceDoc(from - 1, from))) {\n quoteChar = view.state.sliceDoc(from - 1, from);\n from--;\n }\n if (quoteChars.includes(view.state.sliceDoc(to, to + 1))) {\n quoteChar = view.state.sliceDoc(to, to + 1);\n to++;\n }\n\n // When using raw strings (`), we cannot escape a backtick.\n // Therefore, switch the quote character.\n if (completion.label.includes('`')) {\n quoteChar = '\"';\n }\n\n const insertText = `${quoteChar}${escapeString(completion.label, quoteChar)}${quoteChar}`;\n view.dispatch(insertCompletionText(view.state, insertText, from, to));\n}\n\nasync function completeTagValue(completionCfg: CompletionConfig, tag: string): Promise<Completion[]> {\n if (!completionCfg.client) {\n return [];\n }\n\n const { start, end } = getUnixTimeRange(completionCfg.timeRange);\n const { limit, maxStaleValues } = completionCfg;\n\n const response = await completionCfg.client.searchTagValues({ tag, start, end, limit, maxStaleValues });\n const completions: Completion[] = [];\n for (const { type, value } of response.tagValues) {\n switch (type) {\n case 'string':\n completions.push({ label: value ?? '', displayLabel: value ?? '(empty string)', apply: applyQuotedCompletion });\n break;\n\n case 'keyword':\n case 'int':\n completions.push({ label: value ?? '', displayLabel: value ?? '(empty string)' });\n break;\n }\n }\n return completions;\n}\n"],"names":["insertCompletionText","syntaxTree","String","StringType","FieldExpression","AttributeField","Resource","Identifier","Span","SpansetFilter","FieldOp","isAbsoluteTimeRange","toAbsoluteTimeRange","quoteChars","defaultQuoteChar","complete","completionCfg","state","pos","completions","identifyCompletions","options","retrieveOptions","scopes","from","to","tree","node","resolveInner","type","id","firstChild","sliceDoc","includes","kind","scope","parent","text","fieldExpr","attribute","tag","test","prevSibling","results","completion","push","Promise","resolve","label","completeTagName","completeTagValue","all","flat","getUnixTimeRange","timeRange","absTimeRange","start","Math","round","getTime","end","client","limit","maxStaleValues","response","searchTags","flatMap","tags","map","escapeString","input","quoteChar","escaped","replaceAll","applyQuotedCompletion","view","insertText","dispatch","searchTagValues","value","tagValues","displayLabel","apply"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/complete.ts"],"sourcesContent":["// Copyright 2024 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 { Completion, CompletionContext, CompletionResult, insertCompletionText } from '@codemirror/autocomplete';\nimport { syntaxTree } from '@codemirror/language';\nimport { EditorState } from '@codemirror/state';\nimport { Tree } from '@lezer/common';\nimport {\n String as StringType,\n FieldExpression,\n AttributeField,\n Resource,\n Identifier,\n Span,\n SpansetFilter,\n FieldOp,\n} from '@grafana/lezer-traceql';\nimport { EditorView } from '@uiw/react-codemirror';\nimport { getUnixTimeRange } from '../plugins/tempo-trace-query';\nimport { CompletionConfig } from './TraceQLExtension';\n\n/** CompletionScope specifies the completion kind, e.g. whether to complete tag names or values etc. */\ntype CompletionScope =\n | { kind: 'Scopes' } // 'resource'|'span'\n | { kind: 'TagName'; scope: 'resource' | 'span' | 'intrinsic' }\n | { kind: 'TagValue'; tag: string };\n\n/**\n * Completions specifies the identified scopes and position of the completion in the current editor text.\n * For example, when entering '{' the following completions are possible: Scopes(), TagName(scope=intrinsic)\n */\nexport interface Completions {\n scopes: CompletionScope[];\n from: number;\n to?: number;\n}\n\nconst quoteChars = ['\"', '`'];\nconst defaultQuoteChar = '\"';\n\nexport async function complete(\n completionCfg: CompletionConfig,\n { state, pos }: CompletionContext\n): Promise<CompletionResult | null> {\n // First, identify the completion scopes, for example Scopes() and TagName(scope=intrinsic)\n const completions = identifyCompletions(state, pos, syntaxTree(state));\n if (!completions) {\n // No completion scopes found for current cursor position.\n return null;\n }\n\n // Then, retrieve completion options for all identified scopes (from the Tempo API).\n const options = await retrieveOptions(completionCfg, completions.scopes);\n return { options, from: completions.from, to: completions.to };\n}\n\n/**\n * Identify completion scopes (e.g. TagValue) and position, based on the current node in the syntax tree.\n *\n * For development, you can visualize the tree of a TraceQL query using this tool:\n * https://github.com/grafana/lezer-traceql/blob/main/tools/tree-viz.html\n *\n * Function is exported for tests only.\n */\nexport function identifyCompletions(state: EditorState, pos: number, tree: Tree): Completions | undefined {\n const node = tree.resolveInner(pos, -1);\n\n switch (node.type.id) {\n case SpansetFilter:\n // autocomplete {\n // autocomplete {}\n // do not autocomplete if cursor is after } or { status=ok }\n if (\n (node.firstChild === null || node.firstChild?.type.id === 0) &&\n !state.sliceDoc(node.from, pos).includes('}')\n ) {\n return {\n scopes: [{ kind: 'Scopes' }, { kind: 'TagName', scope: 'intrinsic' }],\n from: pos,\n };\n }\n break;\n\n case FieldExpression:\n // autocomplete { status=ok &&\n return {\n scopes: [{ kind: 'Scopes' }, { kind: 'TagName', scope: 'intrinsic' }],\n from: pos,\n };\n\n case AttributeField:\n // autocomplete { resource.\n if (node.firstChild?.type.id === Resource) {\n return { scopes: [{ kind: 'TagName', scope: 'resource' }], from: pos };\n }\n\n // autocomplete { span.\n if (node.firstChild?.type.id === Span) {\n return { scopes: [{ kind: 'TagName', scope: 'span' }], from: pos };\n }\n\n // autocomplete { .\n if (state.sliceDoc(node.from, node.to) === '.') {\n return {\n scopes: [\n { kind: 'TagName', scope: 'resource' },\n { kind: 'TagName', scope: 'span' },\n ],\n from: pos,\n };\n }\n break;\n\n case Identifier:\n if (node.parent?.type.id === AttributeField) {\n const text = state.sliceDoc(node.parent.from, node.parent.to);\n // autocomplete { span:s\n // only intrinsic fields can have a : in the name.\n if (text.includes(':')) {\n return { scopes: [{ kind: 'TagName', scope: 'intrinsic' }], from: node.parent.from };\n }\n\n // autocomplete { resource.s\n if (node.parent?.firstChild?.type.id === Resource) {\n return { scopes: [{ kind: 'TagName', scope: 'resource' }], from: node.from };\n }\n\n // autocomplete { span.s\n if (node.parent?.firstChild?.type.id === Span) {\n return { scopes: [{ kind: 'TagName', scope: 'span' }], from: node.from };\n }\n\n // autocomplete { .s\n if (node.parent?.firstChild?.type.id === Identifier) {\n return {\n scopes: [\n { kind: 'TagName', scope: 'resource' },\n { kind: 'TagName', scope: 'span' },\n ],\n from: node.from,\n };\n }\n }\n break;\n\n case FieldOp:\n // autocomplete { status=\n // autocomplete { span.http.method=\n if (node.parent?.firstChild?.type.id === FieldExpression) {\n const fieldExpr = node.parent.firstChild;\n const attribute = state.sliceDoc(fieldExpr.from, fieldExpr.to);\n return { scopes: [{ kind: 'TagValue', tag: attribute }], from: pos };\n }\n break;\n\n case StringType:\n // autocomplete { resource.service.name=\"\n // do not autocomplete if cursor is after closing quotes { resource.service.name=\"\"\n if (\n node.parent?.parent?.parent?.firstChild?.type.id === FieldExpression &&\n !/^\".*\"$/.test(state.sliceDoc(node.from, pos))\n ) {\n const fieldExpr = node.parent.parent.parent.firstChild;\n const attribute = state.sliceDoc(fieldExpr.from, fieldExpr.to);\n return { scopes: [{ kind: 'TagValue', tag: attribute }], from: node.from + 1 }; // node.from+1 to ignore leading \"\n }\n break;\n\n case 0 /* error node */:\n // autocomplete { status=e\n if (node.prevSibling?.type.id === FieldOp && node.parent?.firstChild?.type.id === FieldExpression) {\n const fieldExpr = node.parent.firstChild;\n const attribute = state.sliceDoc(fieldExpr.from, fieldExpr.to);\n // ignore leading \" in { name=\"HT\n const from = quoteChars.includes(state.sliceDoc(node.from, node.from + 1)) ? node.from + 1 : node.from;\n return { scopes: [{ kind: 'TagValue', tag: attribute }], from };\n }\n\n // autocomplete { s\n // autocomplete { status=ok && s\n if (node.parent?.type.id === SpansetFilter || node.parent?.type.id === FieldExpression) {\n return {\n scopes: [{ kind: 'Scopes' }, { kind: 'TagName', scope: 'intrinsic' }],\n from: node.from,\n };\n }\n break;\n }\n}\n\n/**\n * Retrieve all completion options based on the previously identified completion scopes.\n */\nasync function retrieveOptions(completionCfg: CompletionConfig, completions: CompletionScope[]): Promise<Completion[]> {\n const results: Array<Promise<Completion[]>> = [];\n\n for (const completion of completions) {\n switch (completion.kind) {\n case 'Scopes':\n results.push(Promise.resolve([{ label: 'span' }, { label: 'resource' }]));\n break;\n\n case 'TagName':\n results.push(completeTagName(completionCfg, completion.scope));\n break;\n\n case 'TagValue':\n results.push(completeTagValue(completionCfg, completion.tag));\n break;\n }\n }\n\n // Retrieve options concurrently\n // e.g. for unscoped attribute fields, retrieve list of span and resource attributes concurrently.\n const options = await Promise.all(results);\n return options.flat();\n}\n\nasync function completeTagName(\n completionCfg: CompletionConfig,\n scope: 'resource' | 'span' | 'intrinsic'\n): Promise<Completion[]> {\n if (!completionCfg.client) {\n return [];\n }\n\n const { start, end } = completionCfg.timeRange ? getUnixTimeRange(completionCfg.timeRange) : {};\n const { limit, maxStaleValues } = completionCfg;\n\n const response = await completionCfg.client.searchTags({ scope, start, end, limit, maxStaleValues });\n return response.scopes.flatMap((scope) => scope.tags).map((tag) => ({ label: tag }));\n}\n\nfunction escapeString(input: string, quoteChar: string) {\n // do not escape raw strings (when using backticks)\n if (quoteChar === '`') {\n return input;\n }\n\n let escaped = input;\n // escape sequences: https://grafana.com/docs/tempo/v2.8.x/traceql/construct-traceql-queries/#quoted-attribute-names\n escaped = escaped.replaceAll('\\\\', '\\\\\\\\');\n escaped = escaped.replaceAll('\"', '\\\\\"');\n return escaped;\n}\n\n/**\n * Add quotes to the completion text in case quotes are not present already.\n * This handles the following cases:\n * { name=HTTP\n * { name=\"x\n * { name=\"x\" where cursor is after the 'x'\n */\nexport function applyQuotedCompletion(view: EditorView, completion: Completion, from: number, to: number): void {\n let quoteChar = defaultQuoteChar;\n if (quoteChars.includes(view.state.sliceDoc(from - 1, from))) {\n quoteChar = view.state.sliceDoc(from - 1, from);\n from--;\n }\n if (quoteChars.includes(view.state.sliceDoc(to, to + 1))) {\n quoteChar = view.state.sliceDoc(to, to + 1);\n to++;\n }\n\n // When using raw strings (`), we cannot escape a backtick.\n // Therefore, switch the quote character.\n if (completion.label.includes('`')) {\n quoteChar = '\"';\n }\n\n const insertText = `${quoteChar}${escapeString(completion.label, quoteChar)}${quoteChar}`;\n view.dispatch(insertCompletionText(view.state, insertText, from, to));\n}\n\nasync function completeTagValue(completionCfg: CompletionConfig, tag: string): Promise<Completion[]> {\n if (!completionCfg.client) {\n return [];\n }\n\n const { start, end } = completionCfg.timeRange ? getUnixTimeRange(completionCfg.timeRange) : {};\n const { limit, maxStaleValues } = completionCfg;\n\n const response = await completionCfg.client.searchTagValues({ tag, start, end, limit, maxStaleValues });\n const completions: Completion[] = [];\n for (const { type, value } of response.tagValues) {\n switch (type) {\n case 'string':\n completions.push({ label: value ?? '', displayLabel: value ?? '(empty string)', apply: applyQuotedCompletion });\n break;\n\n case 'keyword':\n case 'int':\n completions.push({ label: value ?? '', displayLabel: value ?? '(empty string)' });\n break;\n }\n }\n return completions;\n}\n"],"names":["insertCompletionText","syntaxTree","String","StringType","FieldExpression","AttributeField","Resource","Identifier","Span","SpansetFilter","FieldOp","getUnixTimeRange","quoteChars","defaultQuoteChar","complete","completionCfg","state","pos","completions","identifyCompletions","options","retrieveOptions","scopes","from","to","tree","node","resolveInner","type","id","firstChild","sliceDoc","includes","kind","scope","parent","text","fieldExpr","attribute","tag","test","prevSibling","results","completion","push","Promise","resolve","label","completeTagName","completeTagValue","all","flat","client","start","end","timeRange","limit","maxStaleValues","response","searchTags","flatMap","tags","map","escapeString","input","quoteChar","escaped","replaceAll","applyQuotedCompletion","view","insertText","dispatch","searchTagValues","value","tagValues","displayLabel","apply"],"mappings":"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"}