@perses-dev/tempo-plugin 0.57.0 → 0.57.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/__mf/js/{Tempo.a15c7ca4.js → Tempo.6c9a48e0.js} +5 -5
  2. package/__mf/js/async/{1728.988e2b29.js → 1728.67c7a01e.js} +1 -1
  3. package/__mf/js/async/3.6db4a205.js +4 -0
  4. package/__mf/js/async/3208.47804c05.js +2 -0
  5. package/__mf/js/async/54.0f34f4f8.js +22 -0
  6. package/__mf/js/async/9811.b4b6d8ee.js +7 -0
  7. package/__mf/js/async/__federation_expose_TempoDatasource.a723b8ee.js +2 -0
  8. package/__mf/js/async/{__federation_expose_TempoExplorer.003c9970.js → __federation_expose_TempoExplorer.8d4424e2.js} +1 -1
  9. package/__mf/js/async/__federation_expose_TempoTraceQuery.629ec38d.js +1 -0
  10. package/__mf/js/{main.6a6654b6.js → main.019cca86.js} +3 -3
  11. package/lib/cjs/components/AttributeFilters.js +76 -51
  12. package/lib/cjs/components/complete.js +3 -3
  13. package/lib/cjs/components/filter/filter.js +2 -2
  14. package/lib/cjs/components/filter/filter_to_traceql.js +1 -1
  15. package/lib/cjs/components/filter/traceql_to_filter.js +5 -5
  16. package/lib/cjs/plugins/tempo-trace-query/TempoTraceQueryEditor.js +1 -1
  17. package/lib/cjs/plugins/tempo-trace-query/get-trace-data.js +6 -7
  18. package/lib/components/AttributeFilters.d.ts.map +1 -1
  19. package/lib/components/AttributeFilters.js +72 -47
  20. package/lib/components/AttributeFilters.js.map +1 -1
  21. package/lib/components/ClosableAlert.d.ts +2 -1
  22. package/lib/components/ClosableAlert.d.ts.map +1 -1
  23. package/lib/components/ClosableAlert.js.map +1 -1
  24. package/lib/components/complete.js +1 -1
  25. package/lib/components/complete.js.map +1 -1
  26. package/lib/components/filter/filter.d.ts.map +1 -1
  27. package/lib/components/filter/filter.js +2 -2
  28. package/lib/components/filter/filter.js.map +1 -1
  29. package/lib/components/filter/filter_to_traceql.d.ts.map +1 -1
  30. package/lib/components/filter/filter_to_traceql.js +1 -1
  31. package/lib/components/filter/filter_to_traceql.js.map +1 -1
  32. package/lib/components/filter/traceql_to_filter.js +5 -5
  33. package/lib/components/filter/traceql_to_filter.js.map +1 -1
  34. package/lib/plugins/tempo-trace-query/TempoTraceQueryEditor.d.ts +1 -1
  35. package/lib/plugins/tempo-trace-query/TempoTraceQueryEditor.d.ts.map +1 -1
  36. package/lib/plugins/tempo-trace-query/TempoTraceQueryEditor.js +1 -1
  37. package/lib/plugins/tempo-trace-query/TempoTraceQueryEditor.js.map +1 -1
  38. package/lib/plugins/tempo-trace-query/get-trace-data.d.ts.map +1 -1
  39. package/lib/plugins/tempo-trace-query/get-trace-data.js +6 -7
  40. package/lib/plugins/tempo-trace-query/get-trace-data.js.map +1 -1
  41. package/mf-manifest.json +24 -24
  42. package/mf-stats.json +26 -31
  43. package/package.json +6 -6
  44. package/__mf/js/async/1905.d3c01a20.js +0 -2
  45. package/__mf/js/async/2545.d42b194b.js +0 -2
  46. package/__mf/js/async/54.812deb71.js +0 -22
  47. package/__mf/js/async/7958.4ba5d596.js +0 -7
  48. package/__mf/js/async/__federation_expose_TempoDatasource.1f9ab43f.js +0 -2
  49. package/__mf/js/async/__federation_expose_TempoTraceQuery.eff34861.js +0 -1
  50. /package/__mf/js/async/{1905.d3c01a20.js.LICENSE.txt → 3.6db4a205.js.LICENSE.txt} +0 -0
  51. /package/__mf/js/async/{2545.d42b194b.js.LICENSE.txt → 3208.47804c05.js.LICENSE.txt} +0 -0
  52. /package/__mf/js/async/{54.812deb71.js.LICENSE.txt → 54.0f34f4f8.js.LICENSE.txt} +0 -0
  53. /package/__mf/js/async/{7958.4ba5d596.js.LICENSE.txt → 9811.b4b6d8ee.js.LICENSE.txt} +0 -0
  54. /package/__mf/js/async/{__federation_expose_TempoDatasource.1f9ab43f.js.LICENSE.txt → __federation_expose_TempoDatasource.a723b8ee.js.LICENSE.txt} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/complete.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { 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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"}
1
+ {"version":3,"sources":["../../../src/components/complete.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { 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';\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): 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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../../../src/components/filter/filter.ts"],"names":[],"mappings":"AAaA,oJAAoJ;AACpJ,MAAM,WAAW,MAAM;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,EAAE,aAAa,CAAC;IAC5B,aAAa,EAAE,aAAa,CAAC;IAC7B,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,8DAA8D;AAC9D,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,YAclD"}
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../../../src/components/filter/filter.ts"],"names":[],"mappings":"AAaA,oJAAoJ;AACpJ,MAAM,WAAW,MAAM;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,EAAE,aAAa,CAAC;IAC5B,aAAa,EAAE,aAAa,CAAC;IAC7B,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,8DAA8D;AAC9D,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAc7D"}
@@ -15,9 +15,9 @@
15
15
  let from = 0;
16
16
  const chunks = [];
17
17
  for(let i = 0; i < x.length; i++){
18
- if (x[i] == '"' && x[i - 1] != '\\') {
18
+ if (x[i] === '"' && x[i - 1] !== '\\') {
19
19
  quote = !quote;
20
- } else if (x[i] == ' ' && !quote) {
20
+ } else if (x[i] === ' ' && !quote) {
21
21
  chunks.push(x.slice(from, i));
22
22
  from = i + 1;
23
23
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/filter/filter.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \\\"License\\\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/** A model of a filter bar for common tracing attributes. All attributes are combined with AND, the values of an attribute are combined with OR. */\nexport interface Filter {\n serviceName: string[];\n spanName: string[];\n namespace: string[];\n status: string[];\n spanDuration: DurationField;\n traceDuration: DurationField;\n customMatchers: string[];\n}\n\nexport interface DurationField {\n min?: string;\n max?: string;\n}\n\n/** split a string by whitespace, except when inside quotes */\nexport function splitByUnquotedWhitespace(x: string) {\n let quote = false;\n let from = 0;\n const chunks: string[] = [];\n for (let i = 0; i < x.length; i++) {\n if (x[i] == '\"' && x[i - 1] != '\\\\') {\n quote = !quote;\n } else if (x[i] == ' ' && !quote) {\n chunks.push(x.slice(from, i));\n from = i + 1;\n }\n }\n chunks.push(x.slice(from, x.length));\n return chunks.filter((x) => x);\n}\n"],"names":["splitByUnquotedWhitespace","x","quote","from","chunks","i","length","push","slice","filter"],"mappings":"AAAA,+BAA+B;AAC/B,oEAAoE;AACpE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,sEAAsE;AACtE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,kJAAkJ,GAgBlJ,4DAA4D,GAC5D,OAAO,SAASA,0BAA0BC,CAAS;IACjD,IAAIC,QAAQ;IACZ,IAAIC,OAAO;IACX,MAAMC,SAAmB,EAAE;IAC3B,IAAK,IAAIC,IAAI,GAAGA,IAAIJ,EAAEK,MAAM,EAAED,IAAK;QACjC,IAAIJ,CAAC,CAACI,EAAE,IAAI,OAAOJ,CAAC,CAACI,IAAI,EAAE,IAAI,MAAM;YACnCH,QAAQ,CAACA;QACX,OAAO,IAAID,CAAC,CAACI,EAAE,IAAI,OAAO,CAACH,OAAO;YAChCE,OAAOG,IAAI,CAACN,EAAEO,KAAK,CAACL,MAAME;YAC1BF,OAAOE,IAAI;QACb;IACF;IACAD,OAAOG,IAAI,CAACN,EAAEO,KAAK,CAACL,MAAMF,EAAEK,MAAM;IAClC,OAAOF,OAAOK,MAAM,CAAC,CAACR,IAAMA;AAC9B"}
1
+ {"version":3,"sources":["../../../../src/components/filter/filter.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \\\"License\\\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/** A model of a filter bar for common tracing attributes. All attributes are combined with AND, the values of an attribute are combined with OR. */\nexport interface Filter {\n serviceName: string[];\n spanName: string[];\n namespace: string[];\n status: string[];\n spanDuration: DurationField;\n traceDuration: DurationField;\n customMatchers: string[];\n}\n\nexport interface DurationField {\n min?: string;\n max?: string;\n}\n\n/** split a string by whitespace, except when inside quotes */\nexport function splitByUnquotedWhitespace(x: string): string[] {\n let quote = false;\n let from = 0;\n const chunks: string[] = [];\n for (let i = 0; i < x.length; i++) {\n if (x[i] === '\"' && x[i - 1] !== '\\\\') {\n quote = !quote;\n } else if (x[i] === ' ' && !quote) {\n chunks.push(x.slice(from, i));\n from = i + 1;\n }\n }\n chunks.push(x.slice(from, x.length));\n return chunks.filter((x) => x);\n}\n"],"names":["splitByUnquotedWhitespace","x","quote","from","chunks","i","length","push","slice","filter"],"mappings":"AAAA,+BAA+B;AAC/B,oEAAoE;AACpE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,sEAAsE;AACtE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,kJAAkJ,GAgBlJ,4DAA4D,GAC5D,OAAO,SAASA,0BAA0BC,CAAS;IACjD,IAAIC,QAAQ;IACZ,IAAIC,OAAO;IACX,MAAMC,SAAmB,EAAE;IAC3B,IAAK,IAAIC,IAAI,GAAGA,IAAIJ,EAAEK,MAAM,EAAED,IAAK;QACjC,IAAIJ,CAAC,CAACI,EAAE,KAAK,OAAOJ,CAAC,CAACI,IAAI,EAAE,KAAK,MAAM;YACrCH,QAAQ,CAACA;QACX,OAAO,IAAID,CAAC,CAACI,EAAE,KAAK,OAAO,CAACH,OAAO;YACjCE,OAAOG,IAAI,CAACN,EAAEO,KAAK,CAACL,MAAME;YAC1BF,OAAOE,IAAI;QACb;IACF;IACAD,OAAOG,IAAI,CAACN,EAAEO,KAAK,CAACL,MAAMF,EAAEK,MAAM;IAClC,OAAOF,OAAOK,MAAM,CAAC,CAACR,IAAMA;AAC9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"filter_to_traceql.d.ts","sourceRoot":"","sources":["../../../../src/components/filter/filter_to_traceql.ts"],"names":[],"mappings":"AAaA,OAAO,EAAiB,MAAM,EAAE,MAAM,UAAU,CAAC;AAEjD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,UAe7C"}
1
+ {"version":3,"file":"filter_to_traceql.d.ts","sourceRoot":"","sources":["../../../../src/components/filter/filter_to_traceql.ts"],"names":[],"mappings":"AAaA,OAAO,EAAiB,MAAM,EAAE,MAAM,UAAU,CAAC;AAEjD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAetD"}
@@ -39,7 +39,7 @@ function stringMatcher(attribute, values) {
39
39
  return [
40
40
  `${attribute} =~ "${escapedValues.join('|')}"`
41
41
  ];
42
- } else if (escapedValues.length == 1) {
42
+ } else if (escapedValues.length === 1) {
43
43
  return [
44
44
  `${attribute} = "${escapedValues[0]}"`
45
45
  ];
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/filter/filter_to_traceql.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \\\"License\\\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { DurationField, Filter } from './filter';\n\n/**\n * Construct a TraceQL query from a filter.\n * 1. Creates the matchers, for example 'resource.service.name = \"some_value\"' or 'resource.service.name =~ \"some_value|other_value\"'\n * 2. Join all matchers with '&&'\n * 3. Return the full TraceQL query, for example '{ resource.service.name = \"some_value\" && name = \"span_name\" }'\n */\nexport function filterToTraceQL(filter: Filter) {\n const matchers: string[] = [\n ...stringMatcher('resource.service.name', filter.serviceName),\n ...stringMatcher('name', filter.spanName),\n ...stringMatcher('resource.k8s.namespace.name', filter.namespace),\n ...intrinsicMatcher('status', filter.status),\n ...durationMatcher('duration', filter.spanDuration),\n ...durationMatcher('traceDuration', filter.traceDuration),\n ...customMatcher(filter.customMatchers),\n ];\n\n if (matchers.length === 0) {\n return '{}';\n }\n return `{ ${matchers.join(' && ')} }`;\n}\n\nfunction escape(q: string) {\n return q.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"');\n}\n\nfunction stringMatcher(attribute: string, values: string[]) {\n const escapedValues = values.map(escape);\n if (escapedValues.length > 1) {\n return [`${attribute} =~ \"${escapedValues.join('|')}\"`];\n } else if (escapedValues.length == 1) {\n return [`${attribute} = \"${escapedValues[0]}\"`];\n }\n return [];\n}\n\nfunction intrinsicMatcher(attribute: string, values: string[]) {\n const orConds = values.map((x) => `${attribute} = ${x}`);\n if (orConds.length > 1) {\n return ['(' + orConds.join(' || ') + ')'];\n } else if (orConds.length === 1) {\n return orConds;\n } else {\n return [];\n }\n}\n\nfunction durationMatcher(attribute: string, value: DurationField) {\n const matchers = [];\n if (value.min) {\n matchers.push(`${attribute} >= ${value.min}`);\n }\n if (value.max) {\n matchers.push(`${attribute} <= ${value.max}`);\n }\n return matchers;\n}\n\nfunction customMatcher(customMatchers: string[]) {\n return customMatchers;\n}\n"],"names":["filterToTraceQL","filter","matchers","stringMatcher","serviceName","spanName","namespace","intrinsicMatcher","status","durationMatcher","spanDuration","traceDuration","customMatcher","customMatchers","length","join","escape","q","replaceAll","attribute","values","escapedValues","map","orConds","x","value","min","push","max"],"mappings":"AAAA,+BAA+B;AAC/B,oEAAoE;AACpE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,sEAAsE;AACtE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAIjC;;;;;CAKC,GACD,OAAO,SAASA,gBAAgBC,MAAc;IAC5C,MAAMC,WAAqB;WACtBC,cAAc,yBAAyBF,OAAOG,WAAW;WACzDD,cAAc,QAAQF,OAAOI,QAAQ;WACrCF,cAAc,+BAA+BF,OAAOK,SAAS;WAC7DC,iBAAiB,UAAUN,OAAOO,MAAM;WACxCC,gBAAgB,YAAYR,OAAOS,YAAY;WAC/CD,gBAAgB,iBAAiBR,OAAOU,aAAa;WACrDC,cAAcX,OAAOY,cAAc;KACvC;IAED,IAAIX,SAASY,MAAM,KAAK,GAAG;QACzB,OAAO;IACT;IACA,OAAO,CAAC,EAAE,EAAEZ,SAASa,IAAI,CAAC,QAAQ,EAAE,CAAC;AACvC;AAEA,SAASC,OAAOC,CAAS;IACvB,OAAOA,EAAEC,UAAU,CAAC,MAAM,QAAQA,UAAU,CAAC,KAAK;AACpD;AAEA,SAASf,cAAcgB,SAAiB,EAAEC,MAAgB;IACxD,MAAMC,gBAAgBD,OAAOE,GAAG,CAACN;IACjC,IAAIK,cAAcP,MAAM,GAAG,GAAG;QAC5B,OAAO;YAAC,GAAGK,UAAU,KAAK,EAAEE,cAAcN,IAAI,CAAC,KAAK,CAAC,CAAC;SAAC;IACzD,OAAO,IAAIM,cAAcP,MAAM,IAAI,GAAG;QACpC,OAAO;YAAC,GAAGK,UAAU,IAAI,EAAEE,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC;SAAC;IACjD;IACA,OAAO,EAAE;AACX;AAEA,SAASd,iBAAiBY,SAAiB,EAAEC,MAAgB;IAC3D,MAAMG,UAAUH,OAAOE,GAAG,CAAC,CAACE,IAAM,GAAGL,UAAU,GAAG,EAAEK,GAAG;IACvD,IAAID,QAAQT,MAAM,GAAG,GAAG;QACtB,OAAO;YAAC,MAAMS,QAAQR,IAAI,CAAC,UAAU;SAAI;IAC3C,OAAO,IAAIQ,QAAQT,MAAM,KAAK,GAAG;QAC/B,OAAOS;IACT,OAAO;QACL,OAAO,EAAE;IACX;AACF;AAEA,SAASd,gBAAgBU,SAAiB,EAAEM,KAAoB;IAC9D,MAAMvB,WAAW,EAAE;IACnB,IAAIuB,MAAMC,GAAG,EAAE;QACbxB,SAASyB,IAAI,CAAC,GAAGR,UAAU,IAAI,EAAEM,MAAMC,GAAG,EAAE;IAC9C;IACA,IAAID,MAAMG,GAAG,EAAE;QACb1B,SAASyB,IAAI,CAAC,GAAGR,UAAU,IAAI,EAAEM,MAAMG,GAAG,EAAE;IAC9C;IACA,OAAO1B;AACT;AAEA,SAASU,cAAcC,cAAwB;IAC7C,OAAOA;AACT"}
1
+ {"version":3,"sources":["../../../../src/components/filter/filter_to_traceql.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \\\"License\\\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { DurationField, Filter } from './filter';\n\n/**\n * Construct a TraceQL query from a filter.\n * 1. Creates the matchers, for example 'resource.service.name = \"some_value\"' or 'resource.service.name =~ \"some_value|other_value\"'\n * 2. Join all matchers with '&&'\n * 3. Return the full TraceQL query, for example '{ resource.service.name = \"some_value\" && name = \"span_name\" }'\n */\nexport function filterToTraceQL(filter: Filter): string {\n const matchers: string[] = [\n ...stringMatcher('resource.service.name', filter.serviceName),\n ...stringMatcher('name', filter.spanName),\n ...stringMatcher('resource.k8s.namespace.name', filter.namespace),\n ...intrinsicMatcher('status', filter.status),\n ...durationMatcher('duration', filter.spanDuration),\n ...durationMatcher('traceDuration', filter.traceDuration),\n ...customMatcher(filter.customMatchers),\n ];\n\n if (matchers.length === 0) {\n return '{}';\n }\n return `{ ${matchers.join(' && ')} }`;\n}\n\nfunction escape(q: string): string {\n return q.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"');\n}\n\nfunction stringMatcher(attribute: string, values: string[]): string[] {\n const escapedValues = values.map(escape);\n if (escapedValues.length > 1) {\n return [`${attribute} =~ \"${escapedValues.join('|')}\"`];\n } else if (escapedValues.length === 1) {\n return [`${attribute} = \"${escapedValues[0]}\"`];\n }\n return [];\n}\n\nfunction intrinsicMatcher(attribute: string, values: string[]): string[] {\n const orConds = values.map((x) => `${attribute} = ${x}`);\n if (orConds.length > 1) {\n return ['(' + orConds.join(' || ') + ')'];\n } else if (orConds.length === 1) {\n return orConds;\n } else {\n return [];\n }\n}\n\nfunction durationMatcher(attribute: string, value: DurationField): string[] {\n const matchers = [];\n if (value.min) {\n matchers.push(`${attribute} >= ${value.min}`);\n }\n if (value.max) {\n matchers.push(`${attribute} <= ${value.max}`);\n }\n return matchers;\n}\n\nfunction customMatcher(customMatchers: string[]): string[] {\n return customMatchers;\n}\n"],"names":["filterToTraceQL","filter","matchers","stringMatcher","serviceName","spanName","namespace","intrinsicMatcher","status","durationMatcher","spanDuration","traceDuration","customMatcher","customMatchers","length","join","escape","q","replaceAll","attribute","values","escapedValues","map","orConds","x","value","min","push","max"],"mappings":"AAAA,+BAA+B;AAC/B,oEAAoE;AACpE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,sEAAsE;AACtE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAIjC;;;;;CAKC,GACD,OAAO,SAASA,gBAAgBC,MAAc;IAC5C,MAAMC,WAAqB;WACtBC,cAAc,yBAAyBF,OAAOG,WAAW;WACzDD,cAAc,QAAQF,OAAOI,QAAQ;WACrCF,cAAc,+BAA+BF,OAAOK,SAAS;WAC7DC,iBAAiB,UAAUN,OAAOO,MAAM;WACxCC,gBAAgB,YAAYR,OAAOS,YAAY;WAC/CD,gBAAgB,iBAAiBR,OAAOU,aAAa;WACrDC,cAAcX,OAAOY,cAAc;KACvC;IAED,IAAIX,SAASY,MAAM,KAAK,GAAG;QACzB,OAAO;IACT;IACA,OAAO,CAAC,EAAE,EAAEZ,SAASa,IAAI,CAAC,QAAQ,EAAE,CAAC;AACvC;AAEA,SAASC,OAAOC,CAAS;IACvB,OAAOA,EAAEC,UAAU,CAAC,MAAM,QAAQA,UAAU,CAAC,KAAK;AACpD;AAEA,SAASf,cAAcgB,SAAiB,EAAEC,MAAgB;IACxD,MAAMC,gBAAgBD,OAAOE,GAAG,CAACN;IACjC,IAAIK,cAAcP,MAAM,GAAG,GAAG;QAC5B,OAAO;YAAC,GAAGK,UAAU,KAAK,EAAEE,cAAcN,IAAI,CAAC,KAAK,CAAC,CAAC;SAAC;IACzD,OAAO,IAAIM,cAAcP,MAAM,KAAK,GAAG;QACrC,OAAO;YAAC,GAAGK,UAAU,IAAI,EAAEE,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC;SAAC;IACjD;IACA,OAAO,EAAE;AACX;AAEA,SAASd,iBAAiBY,SAAiB,EAAEC,MAAgB;IAC3D,MAAMG,UAAUH,OAAOE,GAAG,CAAC,CAACE,IAAM,GAAGL,UAAU,GAAG,EAAEK,GAAG;IACvD,IAAID,QAAQT,MAAM,GAAG,GAAG;QACtB,OAAO;YAAC,MAAMS,QAAQR,IAAI,CAAC,UAAU;SAAI;IAC3C,OAAO,IAAIQ,QAAQT,MAAM,KAAK,GAAG;QAC/B,OAAOS;IACT,OAAO;QACL,OAAO,EAAE;IACX;AACF;AAEA,SAASd,gBAAgBU,SAAiB,EAAEM,KAAoB;IAC9D,MAAMvB,WAAW,EAAE;IACnB,IAAIuB,MAAMC,GAAG,EAAE;QACbxB,SAASyB,IAAI,CAAC,GAAGR,UAAU,IAAI,EAAEM,MAAMC,GAAG,EAAE;IAC9C;IACA,IAAID,MAAMG,GAAG,EAAE;QACb1B,SAASyB,IAAI,CAAC,GAAGR,UAAU,IAAI,EAAEM,MAAMG,GAAG,EAAE;IAC9C;IACA,OAAO1B;AACT;AAEA,SAASU,cAAcC,cAAwB;IAC7C,OAAOA;AACT"}
@@ -78,9 +78,9 @@ function reverseStringMatcher(matches) {
78
78
  const values = [];
79
79
  for (const { operator, value } of matches ?? []){
80
80
  const unescaped = unescape(value.slice(1, -1));
81
- if (operator == '=') {
81
+ if (operator === '=') {
82
82
  values.push(unescaped);
83
- } else if (operator == '=~') {
83
+ } else if (operator === '=~') {
84
84
  values.push(...unescaped.split('|'));
85
85
  }
86
86
  }
@@ -89,7 +89,7 @@ function reverseStringMatcher(matches) {
89
89
  function reverseIntrinsicMatcher(matches) {
90
90
  const values = [];
91
91
  for (const { operator, value } of matches ?? []){
92
- if (operator == '=') {
92
+ if (operator === '=') {
93
93
  values.push(value);
94
94
  }
95
95
  }
@@ -98,9 +98,9 @@ function reverseIntrinsicMatcher(matches) {
98
98
  function reverseDurationMatcher(matches) {
99
99
  const duration = {};
100
100
  for (const { operator, value } of matches ?? []){
101
- if (operator == '>=') {
101
+ if (operator === '>=') {
102
102
  duration.min = value;
103
- } else if (operator == '<=') {
103
+ } else if (operator === '<=') {
104
104
  duration.max = value;
105
105
  }
106
106
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/filter/traceql_to_filter.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \\\"License\\\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { AttributeField, FieldExpression, FieldOp, IntrinsicField, Static, parser } from '@grafana/lezer-traceql';\nimport { DurationField, Filter } from './filter';\n\ninterface Matcher {\n operator: string;\n value: string;\n}\n\n/**\n * Construct a Filter from a TraceQL query.\n * 1. Parse the query (using Lezer library) and extract all matchers, e.g. 'some_attribute = \"some_value\"'\n * 2. Create the filter attribute values, a string array with a single value (for 'x = \"y\"') or multiple values (for 'x =~ \"y|z\"')\n * 3. Add the remaining matchers to the set of custom matchers.\n */\nexport function traceQLToFilter(query: string): Filter {\n const matchers = parseQuery(query);\n return {\n serviceName: reverseStringMatcher(matchers['resource.service.name']),\n spanName: reverseStringMatcher(matchers['name']),\n namespace: reverseStringMatcher(matchers['resource.k8s.namespace.name']),\n status: reverseIntrinsicMatcher(matchers['status']),\n spanDuration: reverseDurationMatcher(matchers['duration']),\n traceDuration: reverseDurationMatcher(matchers['traceDuration']),\n customMatchers: reverseCustomMatcher(\n matchers,\n new Set(['resource.service.name', 'name', 'resource.k8s.namespace.name', 'status', 'duration', 'traceDuration'])\n ),\n };\n}\n\nfunction parseQuery(query: string) {\n const matchers: Record<string, Matcher[]> = {};\n let attribute = '';\n let operator = '';\n let value = '';\n\n const syntaxTree = parser.parse(query);\n syntaxTree.iterate({\n enter(node) {\n switch (node.type.id) {\n case AttributeField:\n attribute = query.slice(node.from, node.to);\n return false;\n case IntrinsicField:\n attribute = query.slice(node.from, node.to);\n return false;\n case FieldOp:\n operator = query.slice(node.from, node.to);\n return false;\n case Static:\n value = query.slice(node.from, node.to);\n return false;\n }\n },\n leave(node) {\n if (node.type.id === FieldExpression && node.node.getChild(FieldOp)) {\n const newMatchers = matchers[attribute] ?? [];\n newMatchers.push({ operator, value });\n matchers[attribute] = newMatchers;\n }\n },\n });\n\n return matchers;\n}\n\nfunction unescape(q: string) {\n return q.replaceAll('\\\\\"', '\"').replaceAll('\\\\\\\\', '\\\\');\n}\n\nfunction reverseStringMatcher(matches?: Matcher[]) {\n const values: string[] = [];\n for (const { operator, value } of matches ?? []) {\n const unescaped = unescape(value.slice(1, -1));\n if (operator == '=') {\n values.push(unescaped);\n } else if (operator == '=~') {\n values.push(...unescaped.split('|'));\n }\n }\n return values;\n}\n\nfunction reverseIntrinsicMatcher(matches?: Matcher[]) {\n const values: string[] = [];\n for (const { operator, value } of matches ?? []) {\n if (operator == '=') {\n values.push(value);\n }\n }\n return values;\n}\n\nfunction reverseDurationMatcher(matches?: Matcher[]) {\n const duration: DurationField = {};\n for (const { operator, value } of matches ?? []) {\n if (operator == '>=') {\n duration.min = value;\n } else if (operator == '<=') {\n duration.max = value;\n }\n }\n return duration;\n}\n\nfunction reverseCustomMatcher(matchers: Record<string, Matcher[]>, skipAttrs: Set<string>) {\n const customMatchers: string[] = [];\n for (const [attribute, matches] of Object.entries(matchers)) {\n if (skipAttrs.has(attribute)) {\n continue;\n }\n\n for (const { operator, value } of matches) {\n customMatchers.push(`${attribute}${operator}${value}`);\n }\n }\n return customMatchers;\n}\n"],"names":["AttributeField","FieldExpression","FieldOp","IntrinsicField","Static","parser","traceQLToFilter","query","matchers","parseQuery","serviceName","reverseStringMatcher","spanName","namespace","status","reverseIntrinsicMatcher","spanDuration","reverseDurationMatcher","traceDuration","customMatchers","reverseCustomMatcher","Set","attribute","operator","value","syntaxTree","parse","iterate","enter","node","type","id","slice","from","to","leave","getChild","newMatchers","push","unescape","q","replaceAll","matches","values","unescaped","split","duration","min","max","skipAttrs","Object","entries","has"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/components/filter/traceql_to_filter.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \\\"License\\\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { AttributeField, FieldExpression, FieldOp, IntrinsicField, Static, parser } from '@grafana/lezer-traceql';\nimport { DurationField, Filter } from './filter';\n\ninterface Matcher {\n operator: string;\n value: string;\n}\n\n/**\n * Construct a Filter from a TraceQL query.\n * 1. Parse the query (using Lezer library) and extract all matchers, e.g. 'some_attribute = \"some_value\"'\n * 2. Create the filter attribute values, a string array with a single value (for 'x = \"y\"') or multiple values (for 'x =~ \"y|z\"')\n * 3. Add the remaining matchers to the set of custom matchers.\n */\nexport function traceQLToFilter(query: string): Filter {\n const matchers = parseQuery(query);\n return {\n serviceName: reverseStringMatcher(matchers['resource.service.name']),\n spanName: reverseStringMatcher(matchers['name']),\n namespace: reverseStringMatcher(matchers['resource.k8s.namespace.name']),\n status: reverseIntrinsicMatcher(matchers['status']),\n spanDuration: reverseDurationMatcher(matchers['duration']),\n traceDuration: reverseDurationMatcher(matchers['traceDuration']),\n customMatchers: reverseCustomMatcher(\n matchers,\n new Set(['resource.service.name', 'name', 'resource.k8s.namespace.name', 'status', 'duration', 'traceDuration'])\n ),\n };\n}\n\nfunction parseQuery(query: string): Record<string, Matcher[]> {\n const matchers: Record<string, Matcher[]> = {};\n let attribute = '';\n let operator = '';\n let value = '';\n\n const syntaxTree = parser.parse(query);\n syntaxTree.iterate({\n enter(node) {\n switch (node.type.id) {\n case AttributeField:\n attribute = query.slice(node.from, node.to);\n return false;\n case IntrinsicField:\n attribute = query.slice(node.from, node.to);\n return false;\n case FieldOp:\n operator = query.slice(node.from, node.to);\n return false;\n case Static:\n value = query.slice(node.from, node.to);\n return false;\n }\n },\n leave(node) {\n if (node.type.id === FieldExpression && node.node.getChild(FieldOp)) {\n const newMatchers = matchers[attribute] ?? [];\n newMatchers.push({ operator, value });\n matchers[attribute] = newMatchers;\n }\n },\n });\n\n return matchers;\n}\n\nfunction unescape(q: string): string {\n return q.replaceAll('\\\\\"', '\"').replaceAll('\\\\\\\\', '\\\\');\n}\n\nfunction reverseStringMatcher(matches?: Matcher[]): string[] {\n const values: string[] = [];\n for (const { operator, value } of matches ?? []) {\n const unescaped = unescape(value.slice(1, -1));\n if (operator === '=') {\n values.push(unescaped);\n } else if (operator === '=~') {\n values.push(...unescaped.split('|'));\n }\n }\n return values;\n}\n\nfunction reverseIntrinsicMatcher(matches?: Matcher[]): string[] {\n const values: string[] = [];\n for (const { operator, value } of matches ?? []) {\n if (operator === '=') {\n values.push(value);\n }\n }\n return values;\n}\n\nfunction reverseDurationMatcher(matches?: Matcher[]): DurationField {\n const duration: DurationField = {};\n for (const { operator, value } of matches ?? []) {\n if (operator === '>=') {\n duration.min = value;\n } else if (operator === '<=') {\n duration.max = value;\n }\n }\n return duration;\n}\n\nfunction reverseCustomMatcher(matchers: Record<string, Matcher[]>, skipAttrs: Set<string>): string[] {\n const customMatchers: string[] = [];\n for (const [attribute, matches] of Object.entries(matchers)) {\n if (skipAttrs.has(attribute)) {\n continue;\n }\n\n for (const { operator, value } of matches) {\n customMatchers.push(`${attribute}${operator}${value}`);\n }\n }\n return customMatchers;\n}\n"],"names":["AttributeField","FieldExpression","FieldOp","IntrinsicField","Static","parser","traceQLToFilter","query","matchers","parseQuery","serviceName","reverseStringMatcher","spanName","namespace","status","reverseIntrinsicMatcher","spanDuration","reverseDurationMatcher","traceDuration","customMatchers","reverseCustomMatcher","Set","attribute","operator","value","syntaxTree","parse","iterate","enter","node","type","id","slice","from","to","leave","getChild","newMatchers","push","unescape","q","replaceAll","matches","values","unescaped","split","duration","min","max","skipAttrs","Object","entries","has"],"mappings":"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"}
@@ -5,6 +5,6 @@ interface LimitSelectProps {
5
5
  value: number;
6
6
  setValue: (x: number) => void;
7
7
  }
8
- export declare function LimitSelect(props: LimitSelectProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function LimitSelect(props: LimitSelectProps): ReactElement;
9
9
  export {};
10
10
  //# sourceMappingURL=TempoTraceQueryEditor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TempoTraceQueryEditor.d.ts","sourceRoot":"","sources":["../../../../src/plugins/tempo-trace-query/TempoTraceQueryEditor.tsx"],"names":[],"mappings":"AAsBA,OAAO,EAAE,YAAY,EAAyB,MAAM,OAAO,CAAC;AAU5D,OAAO,EAAE,qBAAqB,EAAiB,MAAM,sBAAsB,CAAC;AAE5E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,YAAY,CA+EhF;AASD,UAAU,gBAAgB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,2CAyBlD"}
1
+ {"version":3,"file":"TempoTraceQueryEditor.d.ts","sourceRoot":"","sources":["../../../../src/plugins/tempo-trace-query/TempoTraceQueryEditor.tsx"],"names":[],"mappings":"AAsBA,OAAO,EAAE,YAAY,EAAyB,MAAM,OAAO,CAAC;AAU5D,OAAO,EAAE,qBAAqB,EAAiB,MAAM,sBAAsB,CAAC;AAE5E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,YAAY,CA+EhF;AASD,UAAU,gBAAgB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,YAAY,CAyBjE"}
@@ -98,7 +98,7 @@ export function TempoTraceQueryEditor(props) {
98
98
  }
99
99
  function isSimpleTraceQLQuery(query) {
100
100
  // if a query can be transformed to a filter and back to the original query, we can show the attribute filter toolbar
101
- return query == '' || filterToTraceQL(traceQLToFilter(query)) === query;
101
+ return query === '' || filterToTraceQL(traceQLToFilter(query)) === query;
102
102
  }
103
103
  const limitOptions = [
104
104
  20,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/plugins/tempo-trace-query/TempoTraceQueryEditor.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { 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
+ {"version":3,"sources":["../../../../src/plugins/tempo-trace-query/TempoTraceQueryEditor.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { 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): void => {\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): boolean {\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): ReactElement {\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,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"}
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,EAGL,mBAAmB,EAMpB,MAAM,aAAa,CAAC;AAErB,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"}
@@ -13,8 +13,7 @@
13
13
  import { isValidTraceId } from '@perses-dev/core';
14
14
  import { datasourceSelectValueToSelector } from '@perses-dev/plugin-system';
15
15
  import { getUnixTime } from 'date-fns';
16
- import { TEMPO_DATASOURCE_KIND } from '../../model';
17
- import { DEFAULT_SEARCH_LIMIT } from '../../model/api-types';
16
+ import { TEMPO_DATASOURCE_KIND, DEFAULT_SEARCH_LIMIT } from '../../model';
18
17
  export function getUnixTimeRange(timeRange) {
19
18
  const { start, end } = timeRange;
20
19
  return {
@@ -97,20 +96,20 @@ function parseTraceResponse(response) {
97
96
  for (const resourceSpan of trace.resourceSpans){
98
97
  for (const scopeSpan of resourceSpan.scopeSpans){
99
98
  for (const span of scopeSpan.spans){
100
- if (span.traceId.length != 32) {
99
+ if (span.traceId.length !== 32) {
101
100
  span.traceId = base64ToHex(span.traceId);
102
101
  }
103
- if (span.spanId.length != 16) {
102
+ if (span.spanId.length !== 16) {
104
103
  span.spanId = base64ToHex(span.spanId);
105
104
  }
106
- if (span.parentSpanId && span.parentSpanId.length != 16) {
105
+ if (span.parentSpanId && span.parentSpanId.length !== 16) {
107
106
  span.parentSpanId = base64ToHex(span.parentSpanId);
108
107
  }
109
108
  for (const link of span.links ?? []){
110
- if (link.traceId.length != 32) {
109
+ if (link.traceId.length !== 32) {
111
110
  link.traceId = base64ToHex(link.traceId);
112
111
  }
113
- if (link.spanId.length != 16) {
112
+ if (link.spanId.length !== 16) {
114
113
  link.spanId = base64ToHex(link.spanId);
115
114
  }
116
115
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/plugins/tempo-trace-query/get-trace-data.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { 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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"}
1
+ {"version":3,"sources":["../../../../src/plugins/tempo-trace-query/get-trace-data.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { AbsoluteTimeRange, isValidTraceId, Notice, otlptracev1, TraceSearchResult } from '@perses-dev/core';\nimport { datasourceSelectValueToSelector, TraceQueryPlugin } from '@perses-dev/plugin-system';\nimport { getUnixTime } from 'date-fns';\nimport {\n TEMPO_DATASOURCE_KIND,\n TempoDatasourceSelector,\n TempoTraceQuerySpec,\n TempoClient,\n DEFAULT_SEARCH_LIMIT,\n QueryResponse,\n SearchRequestParameters,\n SearchResponse,\n} from '../../model';\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): 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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"}
package/mf-manifest.json CHANGED
@@ -5,11 +5,11 @@
5
5
  "name": "Tempo",
6
6
  "type": "app",
7
7
  "buildInfo": {
8
- "buildVersion": "0.57.0",
8
+ "buildVersion": "0.57.1",
9
9
  "buildName": "@perses-dev/tempo-plugin"
10
10
  },
11
11
  "remoteEntry": {
12
- "name": "__mf/js/Tempo.a15c7ca4.js",
12
+ "name": "__mf/js/Tempo.6c9a48e0.js",
13
13
  "path": "",
14
14
  "type": "global"
15
15
  },
@@ -87,14 +87,14 @@
87
87
  {
88
88
  "id": "Tempo:@perses-dev/components",
89
89
  "name": "@perses-dev/components",
90
- "version": "0.53.0",
90
+ "version": "0.53.1",
91
91
  "singleton": true,
92
- "requiredVersion": "^0.53.0",
92
+ "requiredVersion": "^0.53.1",
93
93
  "assets": {
94
94
  "js": {
95
95
  "async": [],
96
96
  "sync": [
97
- "__mf/js/async/7958.4ba5d596.js"
97
+ "__mf/js/async/9811.b4b6d8ee.js"
98
98
  ]
99
99
  },
100
100
  "css": {
@@ -106,14 +106,14 @@
106
106
  {
107
107
  "id": "Tempo:@perses-dev/dashboards",
108
108
  "name": "@perses-dev/dashboards",
109
- "version": "0.53.0",
109
+ "version": "0.53.1",
110
110
  "singleton": true,
111
- "requiredVersion": "^0.53.0",
111
+ "requiredVersion": "^0.53.1",
112
112
  "assets": {
113
113
  "js": {
114
114
  "async": [],
115
115
  "sync": [
116
- "__mf/js/async/54.812deb71.js"
116
+ "__mf/js/async/54.0f34f4f8.js"
117
117
  ]
118
118
  },
119
119
  "css": {
@@ -125,14 +125,14 @@
125
125
  {
126
126
  "id": "Tempo:@perses-dev/explore",
127
127
  "name": "@perses-dev/explore",
128
- "version": "0.53.0",
128
+ "version": "0.53.1",
129
129
  "singleton": true,
130
- "requiredVersion": "^0.53.0",
130
+ "requiredVersion": "^0.53.1",
131
131
  "assets": {
132
132
  "js": {
133
133
  "async": [],
134
134
  "sync": [
135
- "__mf/js/async/1728.988e2b29.js"
135
+ "__mf/js/async/1728.67c7a01e.js"
136
136
  ]
137
137
  },
138
138
  "css": {
@@ -144,14 +144,14 @@
144
144
  {
145
145
  "id": "Tempo:@perses-dev/plugin-system",
146
146
  "name": "@perses-dev/plugin-system",
147
- "version": "0.53.0",
147
+ "version": "0.53.1",
148
148
  "singleton": true,
149
- "requiredVersion": "^0.53.0",
149
+ "requiredVersion": "^0.53.1",
150
150
  "assets": {
151
151
  "js": {
152
152
  "async": [],
153
153
  "sync": [
154
- "__mf/js/async/1905.d3c01a20.js"
154
+ "__mf/js/async/3.6db4a205.js"
155
155
  ]
156
156
  },
157
157
  "css": {
@@ -321,7 +321,7 @@
321
321
  "assets": {
322
322
  "js": {
323
323
  "sync": [
324
- "__mf/js/async/__federation_expose_TempoDatasource.1f9ab43f.js"
324
+ "__mf/js/async/__federation_expose_TempoDatasource.a723b8ee.js"
325
325
  ],
326
326
  "async": [
327
327
  "__mf/js/async/lib-router.66abf9e6.js",
@@ -329,12 +329,12 @@
329
329
  "__mf/js/async/8580.fc8466c9.js",
330
330
  "__mf/js/async/3617.32db58a8.js",
331
331
  "__mf/js/async/8988.c5f79a01.js",
332
- "__mf/js/async/2545.d42b194b.js",
333
- "__mf/js/async/__federation_expose_TempoTraceQuery.eff34861.js",
332
+ "__mf/js/async/3208.47804c05.js",
333
+ "__mf/js/async/__federation_expose_TempoTraceQuery.629ec38d.js",
334
334
  "__mf/js/async/3064.2462a755.js",
335
335
  "__mf/js/async/9836.be31231c.js",
336
336
  "__mf/js/async/4793.4fc513d0.js",
337
- "__mf/js/async/__federation_expose_TempoExplorer.003c9970.js",
337
+ "__mf/js/async/__federation_expose_TempoExplorer.8d4424e2.js",
338
338
  "__mf/js/async/7902.57efc83f.js",
339
339
  "__mf/js/async/9184.a0c2523b.js",
340
340
  "__mf/js/async/9877.d18186e5.js",
@@ -366,8 +366,8 @@
366
366
  "__mf/js/async/8580.fc8466c9.js",
367
367
  "__mf/js/async/3617.32db58a8.js",
368
368
  "__mf/js/async/8988.c5f79a01.js",
369
- "__mf/js/async/2545.d42b194b.js",
370
- "__mf/js/async/__federation_expose_TempoTraceQuery.eff34861.js"
369
+ "__mf/js/async/3208.47804c05.js",
370
+ "__mf/js/async/__federation_expose_TempoTraceQuery.629ec38d.js"
371
371
  ],
372
372
  "async": [
373
373
  "__mf/js/async/9588.aa754dda.js",
@@ -379,7 +379,7 @@
379
379
  "__mf/js/async/9184.a0c2523b.js",
380
380
  "__mf/js/async/3617.32db58a8.js",
381
381
  "__mf/js/async/4793.4fc513d0.js",
382
- "__mf/js/async/__federation_expose_TempoExplorer.003c9970.js",
382
+ "__mf/js/async/__federation_expose_TempoExplorer.8d4424e2.js",
383
383
  "__mf/js/async/9877.d18186e5.js",
384
384
  "__mf/js/async/2043.5826341c.js",
385
385
  "__mf/js/async/6110.f6b3b766.js",
@@ -407,15 +407,15 @@
407
407
  "sync": [
408
408
  "__mf/js/async/3617.32db58a8.js",
409
409
  "__mf/js/async/4793.4fc513d0.js",
410
- "__mf/js/async/__federation_expose_TempoExplorer.003c9970.js"
410
+ "__mf/js/async/__federation_expose_TempoExplorer.8d4424e2.js"
411
411
  ],
412
412
  "async": [
413
413
  "__mf/js/async/8580.fc8466c9.js",
414
414
  "__mf/js/async/501.3a82cccb.js",
415
415
  "__mf/js/async/3617.32db58a8.js",
416
416
  "__mf/js/async/8988.c5f79a01.js",
417
- "__mf/js/async/2545.d42b194b.js",
418
- "__mf/js/async/__federation_expose_TempoTraceQuery.eff34861.js",
417
+ "__mf/js/async/3208.47804c05.js",
418
+ "__mf/js/async/__federation_expose_TempoTraceQuery.629ec38d.js",
419
419
  "__mf/js/async/9836.be31231c.js",
420
420
  "__mf/js/async/9184.a0c2523b.js",
421
421
  "__mf/js/async/7177.31d891f2.js",