@perses-dev/tempo-plugin 0.55.0 → 0.57.0-beta.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 (150) hide show
  1. package/__mf/js/Tempo.7093dd4a.js +6 -0
  2. package/__mf/js/async/1233.6db7be6b.js +1 -0
  3. package/__mf/js/async/1490.cc0a832d.js +22 -0
  4. package/__mf/js/async/1616.46a1ec79.js +1 -0
  5. package/__mf/js/async/1728.21067e6f.js +1 -0
  6. package/__mf/js/async/1969.91de01f7.js +1 -0
  7. package/__mf/js/async/2012.543b6dce.js +1 -0
  8. package/__mf/js/async/2043.5826341c.js +2 -0
  9. package/__mf/js/async/2386.53c46472.js +2 -0
  10. package/__mf/js/async/2545.d42b194b.js +2 -0
  11. package/__mf/js/async/3181.b5749ad3.js +2 -0
  12. package/__mf/js/async/3617.32db58a8.js +110 -0
  13. package/__mf/js/async/3849.d1b5a7aa.js +7 -0
  14. package/__mf/js/async/392.fd3eade4.js +2 -0
  15. package/__mf/js/async/{1964.e6c5b93b.js → 4121.fae8ac21.js} +2 -2
  16. package/__mf/js/async/4746.c0ce20c6.js +2 -0
  17. package/__mf/js/async/4783.97c4e55a.js +2 -0
  18. package/__mf/js/async/4793.4fc513d0.js +2 -0
  19. package/__mf/js/async/{8930.dee9777e.js → 5002.41103df8.js} +1 -1
  20. package/__mf/js/async/501.3a82cccb.js +1 -0
  21. package/__mf/js/async/5071.f9a877b0.js +1 -0
  22. package/__mf/js/async/5214.d2077bec.js +2 -0
  23. package/__mf/js/async/{5214.c44cbfe5.js → 5587.eadcaae7.js} +1 -1
  24. package/__mf/js/async/6110.f6b3b766.js +1 -0
  25. package/__mf/js/async/6258.212dc324.js +2 -0
  26. package/__mf/js/async/6274.eff58da4.js +2 -0
  27. package/__mf/js/async/6283.3c7349ec.js +2 -0
  28. package/__mf/js/async/7177.31d891f2.js +1 -0
  29. package/__mf/js/async/7192.3f00df4c.js +1 -0
  30. package/__mf/js/async/7583.bfd2f519.js +1 -0
  31. package/__mf/js/async/7968.99f881c1.js +1 -0
  32. package/__mf/js/async/7978.68e24de8.js +1 -0
  33. package/__mf/js/async/8035.ce79a5fb.js +38 -0
  34. package/__mf/js/async/8356.4c9d459d.js +1 -0
  35. package/__mf/js/async/8470.84ab0006.js +2 -0
  36. package/__mf/js/async/8580.fc8466c9.js +1 -0
  37. package/__mf/js/async/873.e471eddb.js +1 -0
  38. package/__mf/js/async/8988.c5f79a01.js +1 -0
  39. package/__mf/js/async/9184.a0c2523b.js +1 -0
  40. package/__mf/js/async/9235.e08df974.js +1 -0
  41. package/__mf/js/async/941.9922745e.js +2 -0
  42. package/__mf/js/async/9588.aa754dda.js +1 -0
  43. package/__mf/js/async/9836.be31231c.js +1 -0
  44. package/__mf/js/async/__federation_expose_TempoDatasource.a0c321ab.js +2 -0
  45. package/__mf/js/async/__federation_expose_TempoExplorer.79065666.js +1 -0
  46. package/__mf/js/async/__federation_expose_TempoTraceQuery.e1786579.js +1 -0
  47. package/__mf/js/async/lib-router.4c755752.js +2 -0
  48. package/__mf/js/main.db74e654.js +6 -0
  49. package/lib/bootstrap.js +1 -1
  50. package/lib/bootstrap.js.map +1 -1
  51. package/lib/cjs/components/complete.js +4 -4
  52. package/lib/cjs/explore/TempoExplorer.js +12 -4
  53. package/lib/cjs/explore/links.js +15 -15
  54. package/lib/cjs/index-federation.js +12 -12
  55. package/lib/cjs/model/api-types.js +7 -0
  56. package/lib/cjs/model/tempo-client.js +7 -7
  57. package/lib/cjs/model/tempo-selectors.js +5 -5
  58. package/lib/cjs/plugins/tempo-trace-query/TempoTraceQueryEditor.js +14 -27
  59. package/lib/cjs/plugins/tempo-trace-query/get-trace-data.js +35 -24
  60. package/lib/cjs/test/mock-data.js +10 -8
  61. package/lib/components/AttributeFilters.js +1 -1
  62. package/lib/components/AttributeFilters.js.map +1 -1
  63. package/lib/components/TraceQLEditor.js +1 -1
  64. package/lib/components/TraceQLEditor.js.map +1 -1
  65. package/lib/explore/TempoExplorer.d.ts.map +1 -1
  66. package/lib/explore/TempoExplorer.js +14 -6
  67. package/lib/explore/TempoExplorer.js.map +1 -1
  68. package/lib/model/api-types.d.ts +1 -0
  69. package/lib/model/api-types.d.ts.map +1 -1
  70. package/lib/model/api-types.js +1 -1
  71. package/lib/model/api-types.js.map +1 -1
  72. package/lib/plugins/TempoDatasourceEditor.js +1 -1
  73. package/lib/plugins/TempoDatasourceEditor.js.map +1 -1
  74. package/lib/plugins/tempo-trace-query/TempoTraceQueryEditor.d.ts.map +1 -1
  75. package/lib/plugins/tempo-trace-query/TempoTraceQueryEditor.js +6 -19
  76. package/lib/plugins/tempo-trace-query/TempoTraceQueryEditor.js.map +1 -1
  77. package/lib/plugins/tempo-trace-query/get-trace-data.d.ts.map +1 -1
  78. package/lib/plugins/tempo-trace-query/get-trace-data.js +32 -21
  79. package/lib/plugins/tempo-trace-query/get-trace-data.js.map +1 -1
  80. package/lib/test/mock-data.js +3 -1
  81. package/lib/test/mock-data.js.map +1 -1
  82. package/mf-manifest.json +101 -93
  83. package/mf-stats.json +103 -93
  84. package/package.json +9 -9
  85. package/__mf/js/Tempo.146e84b3.js +0 -5
  86. package/__mf/js/async/1197.850698db.js +0 -1
  87. package/__mf/js/async/1576.1cf74df0.js +0 -1
  88. package/__mf/js/async/2178.6b2e432f.js +0 -2
  89. package/__mf/js/async/2188.685c7491.js +0 -2
  90. package/__mf/js/async/2292.75e9aa11.js +0 -2
  91. package/__mf/js/async/2472.cc8dcf44.js +0 -22
  92. package/__mf/js/async/2972.32076d91.js +0 -101
  93. package/__mf/js/async/3224.ce173388.js +0 -1
  94. package/__mf/js/async/3863.8d56ecec.js +0 -2
  95. package/__mf/js/async/3960.401ff0b0.js +0 -2
  96. package/__mf/js/async/3980.4d5490b2.js +0 -2
  97. package/__mf/js/async/4075.edf1dc62.js +0 -1
  98. package/__mf/js/async/4238.9b78e9fe.js +0 -1
  99. package/__mf/js/async/4269.0cfaf9bb.js +0 -2
  100. package/__mf/js/async/4310.7407645f.js +0 -7
  101. package/__mf/js/async/4421.5f2a2324.js +0 -1
  102. package/__mf/js/async/4535.72cddf33.js +0 -1
  103. package/__mf/js/async/5266.1c520126.js +0 -10
  104. package/__mf/js/async/5409.676a5f3f.js +0 -1
  105. package/__mf/js/async/5790.b4d4134d.js +0 -1
  106. package/__mf/js/async/5981.c6edce96.js +0 -2
  107. package/__mf/js/async/6134.a2707cf7.js +0 -38
  108. package/__mf/js/async/6292.463b4f49.js +0 -1
  109. package/__mf/js/async/6333.367d6758.js +0 -2
  110. package/__mf/js/async/6527.5341d09f.js +0 -2
  111. package/__mf/js/async/6620.c48ce7b1.js +0 -2
  112. package/__mf/js/async/6770.d9c238f2.js +0 -1
  113. package/__mf/js/async/694.c2c37771.js +0 -1
  114. package/__mf/js/async/7376.588b7a17.js +0 -1
  115. package/__mf/js/async/738.93d35dc9.js +0 -1
  116. package/__mf/js/async/7569.842552f0.js +0 -1
  117. package/__mf/js/async/7740.0500bfc6.js +0 -1
  118. package/__mf/js/async/800.7f3113d0.js +0 -2
  119. package/__mf/js/async/8216.2f92a883.js +0 -1
  120. package/__mf/js/async/8488.6c9a25e4.js +0 -1
  121. package/__mf/js/async/8597.d5ba4ca7.js +0 -1
  122. package/__mf/js/async/9173.69dc268d.js +0 -2
  123. package/__mf/js/async/__federation_expose_TempoDatasource.9aa3663e.js +0 -2
  124. package/__mf/js/async/__federation_expose_TempoExplorer.354aef77.js +0 -2
  125. package/__mf/js/async/__federation_expose_TempoTraceQuery.810d0c2c.js +0 -1
  126. package/__mf/js/async/lib-router.312ca028.js +0 -2
  127. package/__mf/js/main.b263c225.js +0 -5
  128. /package/__mf/css/async/{1576.d3010b86.css → 1233.d3010b86.css} +0 -0
  129. /package/__mf/css/async/{2188.d3010b86.css → 6110.d3010b86.css} +0 -0
  130. /package/__mf/css/async/{2341.d3010b86.css → 6258.d3010b86.css} +0 -0
  131. /package/__mf/js/async/{2472.cc8dcf44.js.LICENSE.txt → 1490.cc0a832d.js.LICENSE.txt} +0 -0
  132. /package/__mf/js/async/{2292.75e9aa11.js.LICENSE.txt → 2043.5826341c.js.LICENSE.txt} +0 -0
  133. /package/__mf/js/async/{2188.685c7491.js.LICENSE.txt → 2386.53c46472.js.LICENSE.txt} +0 -0
  134. /package/__mf/js/async/{3863.8d56ecec.js.LICENSE.txt → 2545.d42b194b.js.LICENSE.txt} +0 -0
  135. /package/__mf/js/async/{4269.0cfaf9bb.js.LICENSE.txt → 3181.b5749ad3.js.LICENSE.txt} +0 -0
  136. /package/__mf/js/async/{5266.1c520126.js.LICENSE.txt → 3617.32db58a8.js.LICENSE.txt} +0 -0
  137. /package/__mf/js/async/{4310.7407645f.js.LICENSE.txt → 3849.d1b5a7aa.js.LICENSE.txt} +0 -0
  138. /package/__mf/js/async/{5981.c6edce96.js.LICENSE.txt → 392.fd3eade4.js.LICENSE.txt} +0 -0
  139. /package/__mf/js/async/{1964.e6c5b93b.js.LICENSE.txt → 4121.fae8ac21.js.LICENSE.txt} +0 -0
  140. /package/__mf/js/async/{2178.6b2e432f.js.LICENSE.txt → 4746.c0ce20c6.js.LICENSE.txt} +0 -0
  141. /package/__mf/js/async/{6333.367d6758.js.LICENSE.txt → 4783.97c4e55a.js.LICENSE.txt} +0 -0
  142. /package/__mf/js/async/{6527.5341d09f.js.LICENSE.txt → 4793.4fc513d0.js.LICENSE.txt} +0 -0
  143. /package/__mf/js/async/{6620.c48ce7b1.js.LICENSE.txt → 5214.d2077bec.js.LICENSE.txt} +0 -0
  144. /package/__mf/js/async/{800.7f3113d0.js.LICENSE.txt → 6258.212dc324.js.LICENSE.txt} +0 -0
  145. /package/__mf/js/async/{3960.401ff0b0.js.LICENSE.txt → 6274.eff58da4.js.LICENSE.txt} +0 -0
  146. /package/__mf/js/async/{3980.4d5490b2.js.LICENSE.txt → 6283.3c7349ec.js.LICENSE.txt} +0 -0
  147. /package/__mf/js/async/{9173.69dc268d.js.LICENSE.txt → 8470.84ab0006.js.LICENSE.txt} +0 -0
  148. /package/__mf/js/async/{__federation_expose_TempoDatasource.9aa3663e.js.LICENSE.txt → 941.9922745e.js.LICENSE.txt} +0 -0
  149. /package/__mf/js/async/{__federation_expose_TempoExplorer.354aef77.js.LICENSE.txt → __federation_expose_TempoDatasource.a0c321ab.js.LICENSE.txt} +0 -0
  150. /package/__mf/js/async/{lib-router.312ca028.js.LICENSE.txt → lib-router.4c755752.js.LICENSE.txt} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/plugins/tempo-trace-query/TempoTraceQueryEditor.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 { Box, Button, FormControl, InputLabel, MenuItem, Select, Stack } from '@mui/material';\nimport { useId } from '@perses-dev/components';\nimport {\n DatasourceSelect,\n DatasourceSelectProps,\n useDatasourceClient,\n useDatasourceSelectValueToSelector,\n} from '@perses-dev/plugin-system';\nimport { produce } from 'immer';\nimport { ReactElement, useCallback, useState } from 'react';\nimport { TraceQLEditor } from '../../components';\nimport { TempoClient } from '../../model/tempo-client';\nimport {\n DEFAULT_TEMPO,\n isDefaultTempoSelector,\n isTempoDatasourceSelector,\n TEMPO_DATASOURCE_KIND,\n} from '../../model/tempo-selectors';\nimport { AttributeFilters } from '../../components/AttributeFilters';\nimport { filterToTraceQL } from '../../components/filter/filter_to_traceql';\nimport { traceQLToFilter } from '../../components/filter/traceql_to_filter';\nimport { TraceQueryEditorProps, useQueryState } from './query-editor-model';\n\nexport function TempoTraceQueryEditor(props: TraceQueryEditorProps): ReactElement {\n const {\n onChange,\n value,\n value: { datasource, limit },\n queryHandlerSettings,\n } = props;\n\n const datasourceSelectValue = datasource ?? DEFAULT_TEMPO;\n const selectedDatasource = useDatasourceSelectValueToSelector(datasourceSelectValue, TEMPO_DATASOURCE_KIND);\n const datasourceSelectLabelID = useId('tempo-datasource-label'); // for panels with multiple queries, this component is rendered multiple times on the same page\n\n const { data: client } = useDatasourceClient<TempoClient>(selectedDatasource);\n const { query, handleQueryChange, handleQueryBlur } = useQueryState(props);\n const [showAttributeFilters, setShowAttributeFilters] = useState(() => isSimpleTraceQLQuery(query));\n\n const handleDatasourceChange: DatasourceSelectProps['onChange'] = (next) => {\n if (isTempoDatasourceSelector(next)) {\n onChange(\n produce(value, (draft) => {\n // If they're using the default, just omit the datasource prop (i.e. set to undefined)\n const nextDatasource = isDefaultTempoSelector(next) ? undefined : next;\n draft.datasource = nextDatasource;\n })\n );\n if (queryHandlerSettings?.setWatchOtherSpecs)\n queryHandlerSettings.setWatchOtherSpecs({ ...value, datasource: next });\n return;\n }\n\n throw new Error('Got unexpected non-Tempo datasource selector');\n };\n\n const runQuery = (newQuery: string) => {\n if (queryHandlerSettings?.watchQueryChanges) {\n queryHandlerSettings.watchQueryChanges(newQuery);\n }\n onChange(\n produce(value, (draft) => {\n draft.query = newQuery;\n })\n );\n };\n\n const handleTraceQueryChange = useCallback(\n (e: string) => {\n handleQueryChange(e);\n if (queryHandlerSettings?.watchQueryChanges) {\n queryHandlerSettings.watchQueryChanges(e);\n }\n },\n [handleQueryChange, queryHandlerSettings]\n );\n\n return (\n <Stack spacing={2}>\n <FormControl margin=\"dense\" fullWidth={false}>\n <DatasourceSelect\n datasourcePluginKind={TEMPO_DATASOURCE_KIND}\n value={datasourceSelectValue}\n onChange={handleDatasourceChange}\n labelId={datasourceSelectLabelID}\n label=\"Tempo Datasource\"\n notched\n />\n </FormControl>\n <Stack direction=\"row\" spacing={2} sx={{ alignItems: 'flex-start' }}>\n {showAttributeFilters ? (\n <AttributeFilters client={client} query={query} setQuery={runQuery} />\n ) : (\n <TraceQLEditor\n client={client}\n value={query}\n onChange={handleTraceQueryChange}\n onBlur={queryHandlerSettings?.runWithOnBlur ? handleQueryBlur : undefined}\n />\n )}\n <Button onClick={() => setShowAttributeFilters(!showAttributeFilters)}>\n {showAttributeFilters ? 'Show query' : 'Hide query'}\n </Button>\n <LimitSelect\n value={limit ?? 20}\n setValue={(newLimit: number) =>\n onChange(\n produce(value, (draft) => {\n draft.limit = newLimit;\n })\n )\n }\n />\n </Stack>\n </Stack>\n );\n}\n\nfunction isSimpleTraceQLQuery(query: string) {\n // if a query can be transformed to a filter and back to the original query, we can show the attribute filter toolbar\n return query == '' || filterToTraceQL(traceQLToFilter(query)) === query;\n}\n\nconst limitOptions = [20, 50, 100, 500, 1000, 5000];\n\ninterface LimitSelectProps {\n value: number;\n setValue: (x: number) => void;\n}\n\nexport function LimitSelect(props: LimitSelectProps) {\n const { value, setValue } = props;\n\n // the outer <Box> is required, because <FormControl> has display: inline-flex, which doesn't work with the parent <Stack> of the query editor\n return (\n <Box>\n <FormControl size=\"small\">\n <InputLabel id=\"max-traces-label\">Max Traces</InputLabel>\n <Select\n labelId=\"max-traces-label\"\n id=\"max-traces-select\"\n value={value}\n label=\"Max Traces\"\n onChange={(e) => setValue(typeof e.target.value === 'number' ? e.target.value : parseInt(e.target.value))}\n sx={{ width: 110 }}\n >\n {limitOptions.map((option) => (\n <MenuItem key={option} value={option}>\n {option}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n </Box>\n );\n}\n"],"names":["Box","Button","FormControl","InputLabel","MenuItem","Select","Stack","useId","DatasourceSelect","useDatasourceClient","useDatasourceSelectValueToSelector","produce","useCallback","useState","TraceQLEditor","DEFAULT_TEMPO","isDefaultTempoSelector","isTempoDatasourceSelector","TEMPO_DATASOURCE_KIND","AttributeFilters","filterToTraceQL","traceQLToFilter","useQueryState","TempoTraceQueryEditor","props","onChange","value","datasource","limit","queryHandlerSettings","datasourceSelectValue","selectedDatasource","datasourceSelectLabelID","data","client","query","handleQueryChange","handleQueryBlur","showAttributeFilters","setShowAttributeFilters","isSimpleTraceQLQuery","handleDatasourceChange","next","draft","nextDatasource","undefined","setWatchOtherSpecs","Error","runQuery","newQuery","watchQueryChanges","handleTraceQueryChange","e","spacing","margin","fullWidth","datasourcePluginKind","labelId","label","notched","direction","sx","alignItems","setQuery","onBlur","runWithOnBlur","onClick","LimitSelect","setValue","newLimit","limitOptions","size","id","target","parseInt","width","map","option"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/plugins/tempo-trace-query/TempoTraceQueryEditor.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 { Box, Button, FormControl, InputLabel, MenuItem, Select, Stack } from '@mui/material';\nimport { useId } from '@perses-dev/components';\nimport {\n DatasourceSelect,\n DatasourceSelectProps,\n useDatasourceClient,\n useDatasourceSelectValueToSelector,\n} from '@perses-dev/plugin-system';\nimport { produce } from 'immer';\nimport { ReactElement, useCallback, useState } from 'react';\nimport {\n TempoClient,\n DEFAULT_TEMPO,\n isDefaultTempoSelector,\n isTempoDatasourceSelector,\n TEMPO_DATASOURCE_KIND,\n} from '../../model';\nimport { AttributeFilters } from '../../components/AttributeFilters';\nimport { TraceQLEditor, filterToTraceQL, traceQLToFilter } from '../../components';\nimport { TraceQueryEditorProps, useQueryState } from './query-editor-model';\n\nexport function TempoTraceQueryEditor(props: TraceQueryEditorProps): ReactElement {\n const {\n onChange,\n value,\n value: { datasource, limit },\n } = props;\n\n const datasourceSelectValue = datasource ?? DEFAULT_TEMPO;\n const selectedDatasource = useDatasourceSelectValueToSelector(datasourceSelectValue, TEMPO_DATASOURCE_KIND);\n const datasourceSelectLabelID = useId('tempo-datasource-label'); // for panels with multiple queries, this component is rendered multiple times on the same page\n\n const { data: client } = useDatasourceClient<TempoClient>(selectedDatasource);\n const { query, handleQueryChange, handleQueryBlur } = useQueryState(props);\n const [showAttributeFilters, setShowAttributeFilters] = useState(() => isSimpleTraceQLQuery(query));\n\n const handleDatasourceChange: DatasourceSelectProps['onChange'] = (next) => {\n if (isTempoDatasourceSelector(next)) {\n onChange(\n produce(value, (draft) => {\n // If they're using the default, just omit the datasource prop (i.e. set to undefined)\n const nextDatasource = isDefaultTempoSelector(next) ? undefined : next;\n draft.datasource = nextDatasource;\n })\n );\n return;\n }\n\n throw new Error('Got unexpected non-Tempo datasource selector');\n };\n\n const runQuery = (newQuery: string) => {\n onChange(\n produce(value, (draft) => {\n draft.query = newQuery;\n })\n );\n };\n\n const handleTraceQueryChange = useCallback(\n (e: string) => {\n handleQueryChange(e);\n },\n [handleQueryChange]\n );\n\n return (\n <Stack spacing={2}>\n <FormControl margin=\"dense\" fullWidth={false}>\n <DatasourceSelect\n datasourcePluginKind={TEMPO_DATASOURCE_KIND}\n value={datasourceSelectValue}\n onChange={handleDatasourceChange}\n labelId={datasourceSelectLabelID}\n label=\"Tempo Datasource\"\n notched\n />\n </FormControl>\n <Stack direction=\"row\" spacing={2} sx={{ alignItems: 'flex-start' }}>\n {showAttributeFilters ? (\n <AttributeFilters client={client} query={query} setQuery={runQuery} />\n ) : (\n <TraceQLEditor client={client} value={query} onChange={handleTraceQueryChange} onBlur={handleQueryBlur} />\n )}\n <Button onClick={() => setShowAttributeFilters(!showAttributeFilters)}>\n {showAttributeFilters ? 'Show query' : 'Hide query'}\n </Button>\n <LimitSelect\n value={limit ?? 20}\n setValue={(newLimit: number) =>\n onChange(\n produce(value, (draft) => {\n draft.limit = newLimit;\n })\n )\n }\n />\n </Stack>\n </Stack>\n );\n}\n\nfunction isSimpleTraceQLQuery(query: string) {\n // if a query can be transformed to a filter and back to the original query, we can show the attribute filter toolbar\n return query == '' || filterToTraceQL(traceQLToFilter(query)) === query;\n}\n\nconst limitOptions = [20, 50, 100, 500, 1000, 5000];\n\ninterface LimitSelectProps {\n value: number;\n setValue: (x: number) => void;\n}\n\nexport function LimitSelect(props: LimitSelectProps) {\n const { value, setValue } = props;\n\n // the outer <Box> is required, because <FormControl> has display: inline-flex, which doesn't work with the parent <Stack> of the query editor\n return (\n <Box>\n <FormControl size=\"small\">\n <InputLabel id=\"max-traces-label\">Max Traces</InputLabel>\n <Select\n labelId=\"max-traces-label\"\n id=\"max-traces-select\"\n value={value}\n label=\"Max Traces\"\n onChange={(e) => setValue(typeof e.target.value === 'number' ? e.target.value : parseInt(e.target.value))}\n sx={{ width: 110 }}\n >\n {limitOptions.map((option) => (\n <MenuItem key={option} value={option}>\n {option}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n </Box>\n );\n}\n"],"names":["Box","Button","FormControl","InputLabel","MenuItem","Select","Stack","useId","DatasourceSelect","useDatasourceClient","useDatasourceSelectValueToSelector","produce","useCallback","useState","DEFAULT_TEMPO","isDefaultTempoSelector","isTempoDatasourceSelector","TEMPO_DATASOURCE_KIND","AttributeFilters","TraceQLEditor","filterToTraceQL","traceQLToFilter","useQueryState","TempoTraceQueryEditor","props","onChange","value","datasource","limit","datasourceSelectValue","selectedDatasource","datasourceSelectLabelID","data","client","query","handleQueryChange","handleQueryBlur","showAttributeFilters","setShowAttributeFilters","isSimpleTraceQLQuery","handleDatasourceChange","next","draft","nextDatasource","undefined","Error","runQuery","newQuery","handleTraceQueryChange","e","spacing","margin","fullWidth","datasourcePluginKind","labelId","label","notched","direction","sx","alignItems","setQuery","onBlur","onClick","LimitSelect","setValue","newLimit","limitOptions","size","id","target","parseInt","width","map","option"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"get-trace-data.d.ts","sourceRoot":"","sources":["../../../../src/plugins/tempo-trace-query/get-trace-data.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,iBAAiB,EAAkD,MAAM,kBAAkB,CAAC;AACrG,OAAO,EAAmC,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE9F,OAAO,EAAkD,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAIlG,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,iBAAiB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAM7F;AAED,eAAO,MAAM,YAAY,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAC,cAAc,CA2D9E,CAAC"}
1
+ {"version":3,"file":"get-trace-data.d.ts","sourceRoot":"","sources":["../../../../src/plugins/tempo-trace-query/get-trace-data.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,iBAAiB,EAA0D,MAAM,kBAAkB,CAAC;AAC7G,OAAO,EAAmC,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE9F,OAAO,EAAkD,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAIlG,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,iBAAiB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAM7F;AAED,eAAO,MAAM,YAAY,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAC,cAAc,CAyE9E,CAAC"}
@@ -14,6 +14,7 @@ import { isValidTraceId } from '@perses-dev/core';
14
14
  import { datasourceSelectValueToSelector } from '@perses-dev/plugin-system';
15
15
  import { getUnixTime } from 'date-fns';
16
16
  import { TEMPO_DATASOURCE_KIND } from '../../model';
17
+ import { DEFAULT_SEARCH_LIMIT } from '../../model/api-types';
17
18
  export function getUnixTimeRange(timeRange) {
18
19
  const { start, end } = timeRange;
19
20
  return {
@@ -35,21 +36,6 @@ export const getTraceData = async (spec, context)=>{
35
36
  const listDatasourceSelectItems = await context.datasourceStore.listDatasourceSelectItems(TEMPO_DATASOURCE_KIND);
36
37
  const datasourceSelector = datasourceSelectValueToSelector(spec.datasource, context.variableState, listDatasourceSelectItems) ?? defaultTempoDatasource;
37
38
  const client = await context.datasourceStore.getDatasourceClient(datasourceSelector);
38
- const getQuery = ()=>{
39
- const params = {
40
- q: spec.query
41
- };
42
- // handle time range selection from UI drop down (e.g. last 5 minutes, last 1 hour )
43
- if (context.absoluteTimeRange) {
44
- const { start, end } = getUnixTimeRange(context.absoluteTimeRange);
45
- params.start = start;
46
- params.end = end;
47
- }
48
- if (spec.limit) {
49
- params.limit = spec.limit;
50
- }
51
- return params;
52
- };
53
39
  /**
54
40
  * determine type of query:
55
41
  * if the query is a valid traceId, fetch the trace by traceId
@@ -65,11 +51,37 @@ export const getTraceData = async (spec, context)=>{
65
51
  }
66
52
  };
67
53
  } else {
68
- const response = await client.searchWithFallback(getQuery());
54
+ const params = {
55
+ q: spec.query
56
+ };
57
+ // handle time range selection from UI drop down (e.g. last 5 minutes, last 1 hour )
58
+ if (context.absoluteTimeRange) {
59
+ const { start, end } = getUnixTimeRange(context.absoluteTimeRange);
60
+ params.start = start;
61
+ params.end = end;
62
+ }
63
+ // Fetch one more trace than requested.
64
+ // This way we can check if there are more traces available matching the search request, and show a notice to the user.
65
+ const limit = spec.limit ?? DEFAULT_SEARCH_LIMIT;
66
+ params.limit = limit + 1;
67
+ const response = await client.searchWithFallback(params);
68
+ const searchResult = parseSearchResponse(response);
69
+ const hasMoreResults = searchResult.length > limit;
70
+ const notices = [];
71
+ if (hasMoreResults) {
72
+ notices.push({
73
+ type: 'info',
74
+ message: 'Not all matching traces are currently displayed. Increase the result limit to view additional traces.'
75
+ });
76
+ // Remove the extra element, i.e. do not return more results than requested.
77
+ searchResult.splice(limit);
78
+ }
69
79
  return {
70
- searchResult: parseSearchResponse(response),
80
+ searchResult,
71
81
  metadata: {
72
- executedQueryString: spec.query
82
+ executedQueryString: spec.query,
83
+ hasMoreResults,
84
+ notices
73
85
  }
74
86
  };
75
87
  }
@@ -80,8 +92,7 @@ function parseTraceResponse(response) {
80
92
  };
81
93
  // Tempo returns Trace ID and Span ID base64-encoded.
82
94
  // The OTLP spec defines the encoding in the hex format:
83
- // Spec: https://opentelemetry.io/docs/specs/otlp/#json-protobuf-encoding
84
- // Example: https://github.com/open-telemetry/opentelemetry-proto/blob/v1.7.0/examples/trace.json
95
+ // Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#retrieving-the-traceid-and-spanid
85
96
  // Therefore, let's convert it to hex encoding.
86
97
  for (const resourceSpan of trace.resourceSpans){
87
98
  for (const scopeSpan of resourceSpan.scopeSpans){
@@ -110,7 +121,7 @@ function parseTraceResponse(response) {
110
121
  }
111
122
  function base64ToHex(str) {
112
123
  try {
113
- return atob(str).split('').map((char)=>char.charCodeAt(0).toString(16).padStart(2, '0').toUpperCase()).join('');
124
+ return atob(str).split('').map((char)=>char.charCodeAt(0).toString(16).padStart(2, '0')).join('');
114
125
  } catch {
115
126
  return str;
116
127
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/plugins/tempo-trace-query/get-trace-data.ts"],"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 { AbsoluteTimeRange, isValidTraceId, otlptracev1, TraceSearchResult } from '@perses-dev/core';\nimport { datasourceSelectValueToSelector, TraceQueryPlugin } from '@perses-dev/plugin-system';\nimport { getUnixTime } from 'date-fns';\nimport { TEMPO_DATASOURCE_KIND, TempoDatasourceSelector, TempoTraceQuerySpec } from '../../model';\nimport { QueryResponse, SearchRequestParameters, SearchResponse } from '../../model/api-types';\nimport { TempoClient } from '../../model/tempo-client';\n\nexport function getUnixTimeRange(timeRange: AbsoluteTimeRange): { start: number; end: number } {\n const { start, end } = timeRange;\n return {\n start: Math.ceil(getUnixTime(start)),\n end: Math.ceil(getUnixTime(end)),\n };\n}\n\nexport const getTraceData: TraceQueryPlugin<TempoTraceQuerySpec>['getTraceData'] = async (spec, context) => {\n if (spec.query === undefined || spec.query === null || spec.query === '') {\n // Do not make a request to the backend, instead return an empty TraceData\n console.error('TempoTraceQuery is undefined, null, or an empty string.');\n return { searchResult: [] };\n }\n\n const defaultTempoDatasource: TempoDatasourceSelector = {\n kind: TEMPO_DATASOURCE_KIND,\n };\n\n const listDatasourceSelectItems = await context.datasourceStore.listDatasourceSelectItems(TEMPO_DATASOURCE_KIND);\n const datasourceSelector =\n datasourceSelectValueToSelector(spec.datasource, context.variableState, listDatasourceSelectItems) ??\n defaultTempoDatasource;\n\n const client = await context.datasourceStore.getDatasourceClient<TempoClient>(datasourceSelector);\n\n const getQuery = (): SearchRequestParameters => {\n const params: SearchRequestParameters = {\n q: spec.query,\n };\n\n // handle time range selection from UI drop down (e.g. last 5 minutes, last 1 hour )\n if (context.absoluteTimeRange) {\n const { start, end } = getUnixTimeRange(context.absoluteTimeRange);\n params.start = start;\n params.end = end;\n }\n\n if (spec.limit) {\n params.limit = spec.limit;\n }\n\n return params;\n };\n\n /**\n * determine type of query:\n * if the query is a valid traceId, fetch the trace by traceId\n * otherwise, execute a TraceQL query\n */\n if (isValidTraceId(spec.query)) {\n const response = await client.query({ traceId: spec.query });\n return {\n trace: parseTraceResponse(response),\n metadata: {\n executedQueryString: spec.query,\n },\n };\n } else {\n const response = await client.searchWithFallback(getQuery());\n return {\n searchResult: parseSearchResponse(response),\n metadata: {\n executedQueryString: spec.query,\n },\n };\n }\n};\n\nfunction parseTraceResponse(response: QueryResponse): otlptracev1.TracesData {\n const trace = {\n resourceSpans: response.batches,\n };\n\n // Tempo returns Trace ID and Span ID base64-encoded.\n // The OTLP spec defines the encoding in the hex format:\n // Spec: https://opentelemetry.io/docs/specs/otlp/#json-protobuf-encoding\n // Example: https://github.com/open-telemetry/opentelemetry-proto/blob/v1.7.0/examples/trace.json\n // Therefore, let's convert it to hex encoding.\n for (const resourceSpan of trace.resourceSpans) {\n for (const scopeSpan of resourceSpan.scopeSpans) {\n for (const span of scopeSpan.spans) {\n if (span.traceId.length != 32) {\n span.traceId = base64ToHex(span.traceId);\n }\n if (span.spanId.length != 16) {\n span.spanId = base64ToHex(span.spanId);\n }\n if (span.parentSpanId && span.parentSpanId.length != 16) {\n span.parentSpanId = base64ToHex(span.parentSpanId);\n }\n\n for (const link of span.links ?? []) {\n if (link.traceId.length != 32) {\n link.traceId = base64ToHex(link.traceId);\n }\n if (link.spanId.length != 16) {\n link.spanId = base64ToHex(link.spanId);\n }\n }\n }\n }\n }\n\n return trace;\n}\n\nfunction base64ToHex(str: string) {\n try {\n return atob(str)\n .split('')\n .map((char) => char.charCodeAt(0).toString(16).padStart(2, '0').toUpperCase())\n .join('');\n } catch {\n return str;\n }\n}\n\nfunction parseSearchResponse(response: SearchResponse): TraceSearchResult[] {\n return response.traces.map((trace) => ({\n startTimeUnixMs: parseInt(trace.startTimeUnixNano) * 1e-6, // convert to millisecond for eChart time format,\n durationMs: trace.durationMs ?? 0, // Tempo API doesn't return 0 values\n traceId: trace.traceID,\n rootServiceName: trace.rootServiceName,\n rootTraceName: trace.rootTraceName,\n serviceStats: trace.serviceStats || {},\n }));\n}\n"],"names":["isValidTraceId","datasourceSelectValueToSelector","getUnixTime","TEMPO_DATASOURCE_KIND","getUnixTimeRange","timeRange","start","end","Math","ceil","getTraceData","spec","context","query","undefined","console","error","searchResult","defaultTempoDatasource","kind","listDatasourceSelectItems","datasourceStore","datasourceSelector","datasource","variableState","client","getDatasourceClient","getQuery","params","q","absoluteTimeRange","limit","response","traceId","trace","parseTraceResponse","metadata","executedQueryString","searchWithFallback","parseSearchResponse","resourceSpans","batches","resourceSpan","scopeSpan","scopeSpans","span","spans","length","base64ToHex","spanId","parentSpanId","link","links","str","atob","split","map","char","charCodeAt","toString","padStart","toUpperCase","join","traces","startTimeUnixMs","parseInt","startTimeUnixNano","durationMs","traceID","rootServiceName","rootTraceName","serviceStats"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/plugins/tempo-trace-query/get-trace-data.ts"],"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 { AbsoluteTimeRange, isValidTraceId, Notice, otlptracev1, TraceSearchResult } from '@perses-dev/core';\nimport { datasourceSelectValueToSelector, TraceQueryPlugin } from '@perses-dev/plugin-system';\nimport { getUnixTime } from 'date-fns';\nimport { TEMPO_DATASOURCE_KIND, TempoDatasourceSelector, TempoTraceQuerySpec } from '../../model';\nimport { DEFAULT_SEARCH_LIMIT, QueryResponse, SearchRequestParameters, SearchResponse } from '../../model/api-types';\nimport { TempoClient } from '../../model/tempo-client';\n\nexport function getUnixTimeRange(timeRange: AbsoluteTimeRange): { start: number; end: number } {\n const { start, end } = timeRange;\n return {\n start: Math.ceil(getUnixTime(start)),\n end: Math.ceil(getUnixTime(end)),\n };\n}\n\nexport const getTraceData: TraceQueryPlugin<TempoTraceQuerySpec>['getTraceData'] = async (spec, context) => {\n if (spec.query === undefined || spec.query === null || spec.query === '') {\n // Do not make a request to the backend, instead return an empty TraceData\n console.error('TempoTraceQuery is undefined, null, or an empty string.');\n return { searchResult: [] };\n }\n\n const defaultTempoDatasource: TempoDatasourceSelector = {\n kind: TEMPO_DATASOURCE_KIND,\n };\n\n const listDatasourceSelectItems = await context.datasourceStore.listDatasourceSelectItems(TEMPO_DATASOURCE_KIND);\n const datasourceSelector =\n datasourceSelectValueToSelector(spec.datasource, context.variableState, listDatasourceSelectItems) ??\n defaultTempoDatasource;\n\n const client = await context.datasourceStore.getDatasourceClient<TempoClient>(datasourceSelector);\n\n /**\n * determine type of query:\n * if the query is a valid traceId, fetch the trace by traceId\n * otherwise, execute a TraceQL query\n */\n if (isValidTraceId(spec.query)) {\n const response = await client.query({ traceId: spec.query });\n return {\n trace: parseTraceResponse(response),\n metadata: {\n executedQueryString: spec.query,\n },\n };\n } else {\n const params: SearchRequestParameters = {\n q: spec.query,\n };\n\n // handle time range selection from UI drop down (e.g. last 5 minutes, last 1 hour )\n if (context.absoluteTimeRange) {\n const { start, end } = getUnixTimeRange(context.absoluteTimeRange);\n params.start = start;\n params.end = end;\n }\n\n // Fetch one more trace than requested.\n // This way we can check if there are more traces available matching the search request, and show a notice to the user.\n const limit = spec.limit ?? DEFAULT_SEARCH_LIMIT;\n params.limit = limit + 1;\n\n const response = await client.searchWithFallback(params);\n const searchResult = parseSearchResponse(response);\n const hasMoreResults = searchResult.length > limit;\n\n const notices: Notice[] = [];\n if (hasMoreResults) {\n notices.push({\n type: 'info',\n message:\n 'Not all matching traces are currently displayed. Increase the result limit to view additional traces.',\n });\n\n // Remove the extra element, i.e. do not return more results than requested.\n searchResult.splice(limit);\n }\n\n return {\n searchResult,\n metadata: {\n executedQueryString: spec.query,\n hasMoreResults,\n notices,\n },\n };\n }\n};\n\nfunction parseTraceResponse(response: QueryResponse): otlptracev1.TracesData {\n const trace = {\n resourceSpans: response.batches,\n };\n\n // Tempo returns Trace ID and Span ID base64-encoded.\n // The OTLP spec defines the encoding in the hex format:\n // Spec: https://opentelemetry.io/docs/specs/otel/trace/api/#retrieving-the-traceid-and-spanid\n // Therefore, let's convert it to hex encoding.\n for (const resourceSpan of trace.resourceSpans) {\n for (const scopeSpan of resourceSpan.scopeSpans) {\n for (const span of scopeSpan.spans) {\n if (span.traceId.length != 32) {\n span.traceId = base64ToHex(span.traceId);\n }\n if (span.spanId.length != 16) {\n span.spanId = base64ToHex(span.spanId);\n }\n if (span.parentSpanId && span.parentSpanId.length != 16) {\n span.parentSpanId = base64ToHex(span.parentSpanId);\n }\n\n for (const link of span.links ?? []) {\n if (link.traceId.length != 32) {\n link.traceId = base64ToHex(link.traceId);\n }\n if (link.spanId.length != 16) {\n link.spanId = base64ToHex(link.spanId);\n }\n }\n }\n }\n }\n\n return trace;\n}\n\nfunction base64ToHex(str: string) {\n try {\n return atob(str)\n .split('')\n .map((char) => char.charCodeAt(0).toString(16).padStart(2, '0'))\n .join('');\n } catch {\n return str;\n }\n}\n\nfunction parseSearchResponse(response: SearchResponse): TraceSearchResult[] {\n return response.traces.map((trace) => ({\n startTimeUnixMs: parseInt(trace.startTimeUnixNano) * 1e-6, // convert to millisecond for eChart time format,\n durationMs: trace.durationMs ?? 0, // Tempo API doesn't return 0 values\n traceId: trace.traceID,\n rootServiceName: trace.rootServiceName,\n rootTraceName: trace.rootTraceName,\n serviceStats: trace.serviceStats || {},\n }));\n}\n"],"names":["isValidTraceId","datasourceSelectValueToSelector","getUnixTime","TEMPO_DATASOURCE_KIND","DEFAULT_SEARCH_LIMIT","getUnixTimeRange","timeRange","start","end","Math","ceil","getTraceData","spec","context","query","undefined","console","error","searchResult","defaultTempoDatasource","kind","listDatasourceSelectItems","datasourceStore","datasourceSelector","datasource","variableState","client","getDatasourceClient","response","traceId","trace","parseTraceResponse","metadata","executedQueryString","params","q","absoluteTimeRange","limit","searchWithFallback","parseSearchResponse","hasMoreResults","length","notices","push","type","message","splice","resourceSpans","batches","resourceSpan","scopeSpan","scopeSpans","span","spans","base64ToHex","spanId","parentSpanId","link","links","str","atob","split","map","char","charCodeAt","toString","padStart","join","traces","startTimeUnixMs","parseInt","startTimeUnixNano","durationMs","traceID","rootServiceName","rootTraceName","serviceStats"],"mappings":"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"}
@@ -2416,7 +2416,9 @@ export const MOCK_TRACE_DATA_SEARCHRESULT = {
2416
2416
  }
2417
2417
  ],
2418
2418
  metadata: {
2419
- executedQueryString: 'duration > 900ms'
2419
+ executedQueryString: 'duration > 900ms',
2420
+ hasMoreResults: false,
2421
+ notices: []
2420
2422
  }
2421
2423
  };
2422
2424