@perses-dev/tempo-plugin 0.48.0 → 0.49.0-rc.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 (53) hide show
  1. package/dist/cjs/components/TraceQLEditor.js +57 -16
  2. package/dist/cjs/components/complete.js +27 -8
  3. package/dist/cjs/index.js +1 -2
  4. package/dist/cjs/model/index.js +1 -1
  5. package/dist/cjs/plugins/tempo-trace-query/TempoTraceQuery.js +1 -0
  6. package/dist/cjs/plugins/tempo-trace-query/TempoTraceQueryEditor.js +48 -9
  7. package/dist/cjs/plugins/tempo-trace-query/get-trace-data.js +12 -12
  8. package/dist/cjs/plugins/tempo-trace-query/query-editor-model.js +44 -3
  9. package/dist/cjs/test/mock-data.js +160 -138
  10. package/dist/components/TraceQLEditor.d.ts.map +1 -1
  11. package/dist/components/TraceQLEditor.js +59 -18
  12. package/dist/components/TraceQLEditor.js.map +1 -1
  13. package/dist/components/complete.d.ts +0 -1
  14. package/dist/components/complete.d.ts.map +1 -1
  15. package/dist/components/complete.js +27 -8
  16. package/dist/components/complete.js.map +1 -1
  17. package/dist/index.d.ts +1 -2
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/model/api-types.d.ts +4 -0
  22. package/dist/model/api-types.d.ts.map +1 -1
  23. package/dist/model/api-types.js.map +1 -1
  24. package/dist/model/index.d.ts +5 -0
  25. package/dist/model/index.d.ts.map +1 -0
  26. package/dist/model/index.js +1 -1
  27. package/dist/model/index.js.map +1 -1
  28. package/dist/model/trace-query-model.d.ts +1 -0
  29. package/dist/model/trace-query-model.d.ts.map +1 -1
  30. package/dist/model/trace-query-model.js.map +1 -1
  31. package/dist/plugins/tempo-trace-query/TempoTraceQuery.d.ts +2 -1
  32. package/dist/plugins/tempo-trace-query/TempoTraceQuery.d.ts.map +1 -1
  33. package/dist/plugins/tempo-trace-query/TempoTraceQuery.js +1 -0
  34. package/dist/plugins/tempo-trace-query/TempoTraceQuery.js.map +1 -1
  35. package/dist/plugins/tempo-trace-query/TempoTraceQueryEditor.d.ts.map +1 -1
  36. package/dist/plugins/tempo-trace-query/TempoTraceQueryEditor.js +52 -13
  37. package/dist/plugins/tempo-trace-query/TempoTraceQueryEditor.js.map +1 -1
  38. package/dist/plugins/tempo-trace-query/get-trace-data.d.ts.map +1 -1
  39. package/dist/plugins/tempo-trace-query/get-trace-data.js +12 -12
  40. package/dist/plugins/tempo-trace-query/get-trace-data.js.map +1 -1
  41. package/dist/plugins/tempo-trace-query/query-editor-model.d.ts +9 -0
  42. package/dist/plugins/tempo-trace-query/query-editor-model.d.ts.map +1 -1
  43. package/dist/plugins/tempo-trace-query/query-editor-model.js +35 -0
  44. package/dist/plugins/tempo-trace-query/query-editor-model.js.map +1 -1
  45. package/dist/test/mock-data.d.ts.map +1 -1
  46. package/dist/test/mock-data.js +160 -138
  47. package/dist/test/mock-data.js.map +1 -1
  48. package/package.json +4 -4
  49. package/dist/cjs/plugins/tempo-trace-query/DashboardTempoTraceQueryEditor.js +0 -61
  50. package/dist/plugins/tempo-trace-query/DashboardTempoTraceQueryEditor.d.ts +0 -13
  51. package/dist/plugins/tempo-trace-query/DashboardTempoTraceQueryEditor.d.ts.map +0 -1
  52. package/dist/plugins/tempo-trace-query/DashboardTempoTraceQueryEditor.js +0 -53
  53. package/dist/plugins/tempo-trace-query/DashboardTempoTraceQueryEditor.js.map +0 -1
@@ -43,6 +43,12 @@ _export(exports, {
43
43
  return MOCK_TRACE_RESPONSE_SMALL;
44
44
  }
45
45
  });
46
+ function addParentReferences(span) {
47
+ for (const child of span.childSpans){
48
+ child.parentSpan = span;
49
+ addParentReferences(child);
50
+ }
51
+ }
46
52
  const MOCK_TRACE_RESPONSE = {
47
53
  batches: [
48
54
  {
@@ -2452,159 +2458,175 @@ const MOCK_TRACE_DATA_SEARCHRESULT = {
2452
2458
  executedQueryString: 'duration > 900ms'
2453
2459
  }
2454
2460
  };
2455
- const shopBackendResource = {
2456
- serviceName: 'shop-backend',
2457
- attributes: [
2458
- {
2459
- key: 'service.name',
2460
- value: {
2461
- stringValue: 'shop-backend'
2462
- }
2463
- }
2464
- ]
2465
- };
2466
- const authServiceResource = {
2467
- serviceName: 'auth-service',
2468
- attributes: [
2469
- {
2470
- key: 'service.name',
2471
- value: {
2472
- stringValue: 'auth-service'
2473
- }
2474
- }
2475
- ]
2476
- };
2477
- const k6scope = {
2478
- name: 'k6'
2479
- };
2480
- const span4 = {
2481
- resource: authServiceResource,
2482
- scope: k6scope,
2483
- childSpans: [],
2484
- traceId: '+9N4RSCdQ83M1BjcX5/wIQ==',
2485
- spanId: 'AYBIFdTlycc=',
2486
- parentSpanId: 'hGe8oRN3wWY=',
2487
- name: 'authenticate',
2488
- kind: 'SPAN_KIND_SERVER',
2489
- startTimeUnixMs: 1718122135970.602,
2490
- endTimeUnixMs: 1718122136107.7405,
2491
- attributes: [],
2492
- events: [],
2493
- status: {
2494
- message: 'Forbidden',
2495
- code: 'STATUS_CODE_ERROR'
2496
- }
2497
- };
2498
- const span3 = {
2499
- resource: shopBackendResource,
2500
- scope: k6scope,
2501
- childSpans: [],
2502
- traceId: '+9N4RSCdQ83M1BjcX5/wIQ==',
2503
- spanId: 'r2NxHHPjciM=',
2504
- parentSpanId: 'nCLrd8tcFMc=',
2505
- name: 'get-article',
2506
- kind: 'SPAN_KIND_CLIENT',
2507
- startTimeUnixMs: 1718122135965.2107,
2508
- endTimeUnixMs: 1718122136520.158,
2509
- attributes: [
2510
- {
2511
- key: 'http.method',
2512
- value: {
2513
- stringValue: 'DELETE'
2514
- }
2515
- }
2516
- ],
2517
- events: [],
2518
- status: {}
2519
- };
2520
- const span2 = {
2521
- resource: shopBackendResource,
2522
- scope: k6scope,
2523
- childSpans: [
2524
- span4
2525
- ],
2526
- traceId: '+9N4RSCdQ83M1BjcX5/wIQ==',
2527
- spanId: 'hGe8oRN3wWY=',
2528
- parentSpanId: 'nCLrd8tcFMc=',
2529
- name: 'authenticate',
2530
- kind: 'SPAN_KIND_CLIENT',
2531
- startTimeUnixMs: 1718122135954.7656,
2532
- endTimeUnixMs: 1718122136154.2273,
2533
- attributes: [
2534
- {
2535
- key: 'net.transport',
2536
- value: {
2537
- stringValue: 'ip_tcp'
2538
- }
2539
- }
2540
- ],
2541
- events: [
2542
- {
2543
- timeUnixMs: 1718122136068.6138,
2544
- name: 'event_k6.7W272ywYih',
2461
+ const MOCK_TRACE_DATA_TRACE = {
2462
+ trace: {
2463
+ rootSpan: {
2464
+ resource: {
2465
+ serviceName: 'shop-backend',
2466
+ attributes: [
2467
+ {
2468
+ key: 'service.name',
2469
+ value: {
2470
+ stringValue: 'shop-backend'
2471
+ }
2472
+ }
2473
+ ]
2474
+ },
2475
+ scope: {
2476
+ name: 'k6'
2477
+ },
2478
+ traceId: '+9N4RSCdQ83M1BjcX5/wIQ==',
2479
+ spanId: 'nCLrd8tcFMc=',
2480
+ name: 'article-to-cart',
2481
+ kind: 'SPAN_KIND_SERVER',
2482
+ startTimeUnixMs: 1718122135898.4426,
2483
+ endTimeUnixMs: 1718122136696.6519,
2545
2484
  attributes: [
2546
2485
  {
2547
- key: 'k6.sJekvnAr5h7vJfK',
2486
+ key: 'http.url',
2548
2487
  value: {
2549
- stringValue: 'SZ9vwpLkAzAm2Bju1VJroUlGD8u3pS'
2488
+ stringValue: 'https://shop-backend.local:8523/article-to-cart'
2550
2489
  }
2551
2490
  },
2552
2491
  {
2553
- key: 'k6.81JLO5NlT1lAeF1',
2492
+ key: 'http.status_code',
2554
2493
  value: {
2555
- stringValue: '4AzrPTOML11aIN3dYgbKSaAe9HErnZ'
2494
+ intValue: '202'
2556
2495
  }
2496
+ }
2497
+ ],
2498
+ events: [],
2499
+ status: {},
2500
+ childSpans: [
2501
+ {
2502
+ resource: {
2503
+ serviceName: 'shop-backend',
2504
+ attributes: [
2505
+ {
2506
+ key: 'service.name',
2507
+ value: {
2508
+ stringValue: 'shop-backend'
2509
+ }
2510
+ }
2511
+ ]
2512
+ },
2513
+ scope: {
2514
+ name: 'k6'
2515
+ },
2516
+ childSpans: [
2517
+ {
2518
+ resource: {
2519
+ serviceName: 'auth-service',
2520
+ attributes: [
2521
+ {
2522
+ key: 'service.name',
2523
+ value: {
2524
+ stringValue: 'auth-service'
2525
+ }
2526
+ }
2527
+ ]
2528
+ },
2529
+ scope: {
2530
+ name: 'k6'
2531
+ },
2532
+ childSpans: [],
2533
+ traceId: '+9N4RSCdQ83M1BjcX5/wIQ==',
2534
+ spanId: 'AYBIFdTlycc=',
2535
+ parentSpanId: 'hGe8oRN3wWY=',
2536
+ name: 'authenticate',
2537
+ kind: 'SPAN_KIND_SERVER',
2538
+ startTimeUnixMs: 1718122135970.602,
2539
+ endTimeUnixMs: 1718122136107.7405,
2540
+ attributes: [],
2541
+ events: [],
2542
+ status: {
2543
+ message: 'Forbidden',
2544
+ code: 'STATUS_CODE_ERROR'
2545
+ }
2546
+ }
2547
+ ],
2548
+ traceId: '+9N4RSCdQ83M1BjcX5/wIQ==',
2549
+ spanId: 'hGe8oRN3wWY=',
2550
+ parentSpanId: 'nCLrd8tcFMc=',
2551
+ name: 'authenticate',
2552
+ kind: 'SPAN_KIND_CLIENT',
2553
+ startTimeUnixMs: 1718122135954.7656,
2554
+ endTimeUnixMs: 1718122136154.2273,
2555
+ attributes: [
2556
+ {
2557
+ key: 'net.transport',
2558
+ value: {
2559
+ stringValue: 'ip_tcp'
2560
+ }
2561
+ }
2562
+ ],
2563
+ events: [
2564
+ {
2565
+ timeUnixMs: 1718122136068.6138,
2566
+ name: 'event_k6.7W272ywYih',
2567
+ attributes: [
2568
+ {
2569
+ key: 'k6.sJekvnAr5h7vJfK',
2570
+ value: {
2571
+ stringValue: 'SZ9vwpLkAzAm2Bju1VJroUlGD8u3pS'
2572
+ }
2573
+ },
2574
+ {
2575
+ key: 'k6.81JLO5NlT1lAeF1',
2576
+ value: {
2577
+ stringValue: '4AzrPTOML11aIN3dYgbKSaAe9HErnZ'
2578
+ }
2579
+ },
2580
+ {
2581
+ key: 'k6.tdj0bfOxLndyJuN',
2582
+ value: {
2583
+ stringValue: 'PeMAsdQ5469IjQgGtifBA7OgfFdoMb'
2584
+ }
2585
+ }
2586
+ ]
2587
+ }
2588
+ ],
2589
+ status: {}
2557
2590
  },
2558
2591
  {
2559
- key: 'k6.tdj0bfOxLndyJuN',
2560
- value: {
2561
- stringValue: 'PeMAsdQ5469IjQgGtifBA7OgfFdoMb'
2562
- }
2592
+ resource: {
2593
+ serviceName: 'shop-backend',
2594
+ attributes: [
2595
+ {
2596
+ key: 'service.name',
2597
+ value: {
2598
+ stringValue: 'shop-backend'
2599
+ }
2600
+ }
2601
+ ]
2602
+ },
2603
+ scope: {
2604
+ name: 'k6'
2605
+ },
2606
+ childSpans: [],
2607
+ traceId: '+9N4RSCdQ83M1BjcX5/wIQ==',
2608
+ spanId: 'r2NxHHPjciM=',
2609
+ parentSpanId: 'nCLrd8tcFMc=',
2610
+ name: 'get-article',
2611
+ kind: 'SPAN_KIND_CLIENT',
2612
+ startTimeUnixMs: 1718122135965.2107,
2613
+ endTimeUnixMs: 1718122136520.158,
2614
+ attributes: [
2615
+ {
2616
+ key: 'http.method',
2617
+ value: {
2618
+ stringValue: 'DELETE'
2619
+ }
2620
+ }
2621
+ ],
2622
+ events: [],
2623
+ status: {}
2563
2624
  }
2564
2625
  ]
2565
2626
  }
2566
- ],
2567
- status: {}
2568
- };
2569
- const span1 = {
2570
- resource: shopBackendResource,
2571
- scope: k6scope,
2572
- childSpans: [
2573
- span2,
2574
- span3
2575
- ],
2576
- traceId: '+9N4RSCdQ83M1BjcX5/wIQ==',
2577
- spanId: 'nCLrd8tcFMc=',
2578
- parentSpanId: undefined,
2579
- name: 'article-to-cart',
2580
- kind: 'SPAN_KIND_SERVER',
2581
- startTimeUnixMs: 1718122135898.4426,
2582
- endTimeUnixMs: 1718122136696.6519,
2583
- attributes: [
2584
- {
2585
- key: 'http.url',
2586
- value: {
2587
- stringValue: 'https://shop-backend.local:8523/article-to-cart'
2588
- }
2589
- },
2590
- {
2591
- key: 'http.status_code',
2592
- value: {
2593
- intValue: '202'
2594
- }
2595
- }
2596
- ],
2597
- events: [],
2598
- status: {}
2599
- };
2600
- span4.parentSpan = span2;
2601
- span2.parentSpan = span1;
2602
- span3.parentSpan = span1;
2603
- const MOCK_TRACE_DATA_TRACE = {
2604
- trace: {
2605
- rootSpan: span1
2606
2627
  },
2607
2628
  metadata: {
2608
2629
  executedQueryString: '61a1487c461d9e08'
2609
2630
  }
2610
2631
  };
2632
+ addParentReferences(MOCK_TRACE_DATA_TRACE.trace.rootSpan);
@@ -1 +1 @@
1
- {"version":3,"file":"TraceQLEditor.d.ts","sourceRoot":"","sources":["../../src/components/TraceQLEditor.tsx"],"names":[],"mappings":"AAeA,OAAmB,EAAc,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAErF,OAAO,EAAE,gBAAgB,EAAoB,MAAM,oBAAoB,CAAC;AAExE,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,YAAY,CAAC;IAC5F,cAAc,EAAE,gBAAgB,CAAC;CAClC;AAED,wBAAgB,aAAa,CAAC,EAAE,cAAc,EAAE,GAAG,IAAI,EAAE,EAAE,kBAAkB,2CAwB5E"}
1
+ {"version":3,"file":"TraceQLEditor.d.ts","sourceRoot":"","sources":["../../src/components/TraceQLEditor.tsx"],"names":[],"mappings":"AAeA,OAAmB,EAAc,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAErF,OAAO,EAAE,gBAAgB,EAAoB,MAAM,oBAAoB,CAAC;AAExE,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,YAAY,CAAC;IAC5F,cAAc,EAAE,gBAAgB,CAAC;CAClC;AAED,wBAAgB,aAAa,CAAC,EAAE,cAAc,EAAE,GAAG,IAAI,EAAE,EAAE,kBAAkB,2CA4D5E"}
@@ -10,9 +10,9 @@
10
10
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
- import { jsx as _jsx } from "react/jsx-runtime";
13
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
14
  import { useMemo } from 'react';
15
- import { useTheme } from '@mui/material';
15
+ import { InputLabel, Stack, useTheme } from '@mui/material';
16
16
  import CodeMirror, { EditorView } from '@uiw/react-codemirror';
17
17
  import { isValidTraceId } from '@perses-dev/core';
18
18
  import { TraceQLExtension } from './TraceQLExtension';
@@ -24,24 +24,65 @@ export function TraceQLEditor({ completeConfig, ...rest }) {
24
24
  }, [
25
25
  completeConfig
26
26
  ]);
27
+ const codemirrorTheme = useMemo(()=>{
28
+ // https://github.com/mui/material-ui/blob/v5.16.7/packages/mui-material/src/OutlinedInput/OutlinedInput.js#L43
29
+ const borderColor = theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)';
30
+ return EditorView.theme({
31
+ '&': {
32
+ backgroundColor: 'transparent !important',
33
+ border: `1px solid ${borderColor}`,
34
+ borderRadius: `${theme.shape.borderRadius}px`
35
+ },
36
+ '&.cm-focused.cm-editor': {
37
+ outline: 'none'
38
+ },
39
+ '.cm-content': {
40
+ padding: '8px'
41
+ }
42
+ });
43
+ }, [
44
+ theme
45
+ ]);
27
46
  var _rest_value;
28
- return /*#__PURE__*/ _jsx(CodeMirror, {
29
- ...rest,
30
- style: {
31
- border: `1px solid ${theme.palette.divider}`
32
- },
33
- theme: isDarkMode ? 'dark' : 'light',
34
- basicSetup: {
35
- highlightActiveLine: false,
36
- highlightActiveLineGutter: false,
37
- foldGutter: false,
38
- // The explore view accepts either a TraceQL query or a Trace ID as input. The lezer grammar marks Trace IDs as invalid,
39
- // therefore let's disable syntax highlighting if the input is a Trace ID.
40
- syntaxHighlighting: !isValidTraceId((_rest_value = rest.value) !== null && _rest_value !== void 0 ? _rest_value : '')
47
+ return /*#__PURE__*/ _jsxs(Stack, {
48
+ position: "relative",
49
+ sx: {
50
+ flexGrow: 1
41
51
  },
42
- extensions: [
43
- EditorView.lineWrapping,
44
- traceQLExtension
52
+ children: [
53
+ /*#__PURE__*/ _jsx(InputLabel // reproduce the same kind of input label that regular MUI TextFields have
54
+ , {
55
+ shrink: true,
56
+ sx: {
57
+ position: 'absolute',
58
+ top: '-6px',
59
+ left: '10px',
60
+ padding: '0 4px',
61
+ color: theme.palette.text.primary,
62
+ backgroundColor: theme.palette.background.default,
63
+ zIndex: 1
64
+ },
65
+ children: "TraceQL Expression"
66
+ }),
67
+ /*#__PURE__*/ _jsx(CodeMirror, {
68
+ ...rest,
69
+ theme: isDarkMode ? 'dark' : 'light',
70
+ basicSetup: {
71
+ lineNumbers: false,
72
+ highlightActiveLine: false,
73
+ highlightActiveLineGutter: false,
74
+ foldGutter: false,
75
+ // The explore view accepts either a TraceQL query or a Trace ID as input. The lezer grammar marks Trace IDs as invalid,
76
+ // therefore let's disable syntax highlighting if the input is a Trace ID.
77
+ syntaxHighlighting: !isValidTraceId((_rest_value = rest.value) !== null && _rest_value !== void 0 ? _rest_value : '')
78
+ },
79
+ extensions: [
80
+ EditorView.lineWrapping,
81
+ traceQLExtension,
82
+ codemirrorTheme
83
+ ],
84
+ placeholder: 'Example: {span.http.method = "GET"}'
85
+ })
45
86
  ]
46
87
  });
47
88
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/TraceQLEditor.tsx"],"sourcesContent":["// Copyright 2023 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 { useMemo } from 'react';\nimport { useTheme } from '@mui/material';\nimport CodeMirror, { EditorView, ReactCodeMirrorProps } from '@uiw/react-codemirror';\nimport { isValidTraceId } from '@perses-dev/core';\nimport { CompletionConfig, TraceQLExtension } from './TraceQLExtension';\n\nexport interface TraceQLEditorProps extends Omit<ReactCodeMirrorProps, 'theme' | 'extensions'> {\n completeConfig: CompletionConfig;\n}\n\nexport function TraceQLEditor({ completeConfig, ...rest }: TraceQLEditorProps) {\n const theme = useTheme();\n const isDarkMode = theme.palette.mode === 'dark';\n\n const traceQLExtension = useMemo(() => {\n return TraceQLExtension(completeConfig);\n }, [completeConfig]);\n\n return (\n <CodeMirror\n {...rest}\n style={{ border: `1px solid ${theme.palette.divider}` }}\n theme={isDarkMode ? 'dark' : 'light'}\n basicSetup={{\n highlightActiveLine: false,\n highlightActiveLineGutter: false,\n foldGutter: false,\n // The explore view accepts either a TraceQL query or a Trace ID as input. The lezer grammar marks Trace IDs as invalid,\n // therefore let's disable syntax highlighting if the input is a Trace ID.\n syntaxHighlighting: !isValidTraceId(rest.value ?? ''),\n }}\n extensions={[EditorView.lineWrapping, traceQLExtension]}\n />\n );\n}\n"],"names":["useMemo","useTheme","CodeMirror","EditorView","isValidTraceId","TraceQLExtension","TraceQLEditor","completeConfig","rest","theme","isDarkMode","palette","mode","traceQLExtension","style","border","divider","basicSetup","highlightActiveLine","highlightActiveLineGutter","foldGutter","syntaxHighlighting","value","extensions","lineWrapping"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAASA,OAAO,QAAQ,QAAQ;AAChC,SAASC,QAAQ,QAAQ,gBAAgB;AACzC,OAAOC,cAAcC,UAAU,QAA8B,wBAAwB;AACrF,SAASC,cAAc,QAAQ,mBAAmB;AAClD,SAA2BC,gBAAgB,QAAQ,qBAAqB;AAMxE,OAAO,SAASC,cAAc,EAAEC,cAAc,EAAE,GAAGC,MAA0B;IAC3E,MAAMC,QAAQR;IACd,MAAMS,aAAaD,MAAME,OAAO,CAACC,IAAI,KAAK;IAE1C,MAAMC,mBAAmBb,QAAQ;QAC/B,OAAOK,iBAAiBE;IAC1B,GAAG;QAACA;KAAe;QAauBC;IAX1C,qBACE,KAACN;QACE,GAAGM,IAAI;QACRM,OAAO;YAAEC,QAAQ,CAAC,UAAU,EAAEN,MAAME,OAAO,CAACK,OAAO,CAAC,CAAC;QAAC;QACtDP,OAAOC,aAAa,SAAS;QAC7BO,YAAY;YACVC,qBAAqB;YACrBC,2BAA2B;YAC3BC,YAAY;YACZ,wHAAwH;YACxH,0EAA0E;YAC1EC,oBAAoB,CAACjB,eAAeI,CAAAA,cAAAA,KAAKc,KAAK,cAAVd,yBAAAA,cAAc;QACpD;QACAe,YAAY;YAACpB,WAAWqB,YAAY;YAAEX;SAAiB;;AAG7D"}
1
+ {"version":3,"sources":["../../src/components/TraceQLEditor.tsx"],"sourcesContent":["// Copyright 2023 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 { useMemo } from 'react';\nimport { InputLabel, Stack, useTheme } from '@mui/material';\nimport CodeMirror, { EditorView, ReactCodeMirrorProps } from '@uiw/react-codemirror';\nimport { isValidTraceId } from '@perses-dev/core';\nimport { CompletionConfig, TraceQLExtension } from './TraceQLExtension';\n\nexport interface TraceQLEditorProps extends Omit<ReactCodeMirrorProps, 'theme' | 'extensions'> {\n completeConfig: CompletionConfig;\n}\n\nexport function TraceQLEditor({ completeConfig, ...rest }: TraceQLEditorProps) {\n const theme = useTheme();\n const isDarkMode = theme.palette.mode === 'dark';\n\n const traceQLExtension = useMemo(() => {\n return TraceQLExtension(completeConfig);\n }, [completeConfig]);\n\n const codemirrorTheme = useMemo(() => {\n // https://github.com/mui/material-ui/blob/v5.16.7/packages/mui-material/src/OutlinedInput/OutlinedInput.js#L43\n const borderColor = theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)';\n\n return EditorView.theme({\n '&': {\n backgroundColor: 'transparent !important', // required for dark mode\n border: `1px solid ${borderColor}`,\n borderRadius: `${theme.shape.borderRadius}px`,\n },\n '&.cm-focused.cm-editor': {\n outline: 'none', // remove dotted outline on focus\n },\n '.cm-content': {\n padding: '8px',\n },\n });\n }, [theme]);\n\n return (\n <Stack position=\"relative\" sx={{ flexGrow: 1 }}>\n <InputLabel // reproduce the same kind of input label that regular MUI TextFields have\n shrink\n sx={{\n position: 'absolute',\n top: '-6px',\n left: '10px',\n padding: '0 4px',\n color: theme.palette.text.primary,\n backgroundColor: theme.palette.background.default,\n zIndex: 1,\n }}\n >\n TraceQL Expression\n </InputLabel>\n <CodeMirror\n {...rest}\n theme={isDarkMode ? 'dark' : 'light'}\n basicSetup={{\n lineNumbers: false,\n highlightActiveLine: false,\n highlightActiveLineGutter: false,\n foldGutter: false,\n // The explore view accepts either a TraceQL query or a Trace ID as input. The lezer grammar marks Trace IDs as invalid,\n // therefore let's disable syntax highlighting if the input is a Trace ID.\n syntaxHighlighting: !isValidTraceId(rest.value ?? ''),\n }}\n extensions={[EditorView.lineWrapping, traceQLExtension, codemirrorTheme]}\n placeholder='Example: {span.http.method = \"GET\"}'\n />\n </Stack>\n );\n}\n"],"names":["useMemo","InputLabel","Stack","useTheme","CodeMirror","EditorView","isValidTraceId","TraceQLExtension","TraceQLEditor","completeConfig","rest","theme","isDarkMode","palette","mode","traceQLExtension","codemirrorTheme","borderColor","backgroundColor","border","borderRadius","shape","outline","padding","position","sx","flexGrow","shrink","top","left","color","text","primary","background","default","zIndex","basicSetup","lineNumbers","highlightActiveLine","highlightActiveLineGutter","foldGutter","syntaxHighlighting","value","extensions","lineWrapping","placeholder"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAASA,OAAO,QAAQ,QAAQ;AAChC,SAASC,UAAU,EAAEC,KAAK,EAAEC,QAAQ,QAAQ,gBAAgB;AAC5D,OAAOC,cAAcC,UAAU,QAA8B,wBAAwB;AACrF,SAASC,cAAc,QAAQ,mBAAmB;AAClD,SAA2BC,gBAAgB,QAAQ,qBAAqB;AAMxE,OAAO,SAASC,cAAc,EAAEC,cAAc,EAAE,GAAGC,MAA0B;IAC3E,MAAMC,QAAQR;IACd,MAAMS,aAAaD,MAAME,OAAO,CAACC,IAAI,KAAK;IAE1C,MAAMC,mBAAmBf,QAAQ;QAC/B,OAAOO,iBAAiBE;IAC1B,GAAG;QAACA;KAAe;IAEnB,MAAMO,kBAAkBhB,QAAQ;QAC9B,+GAA+G;QAC/G,MAAMiB,cAAcN,MAAME,OAAO,CAACC,IAAI,KAAK,UAAU,wBAAwB;QAE7E,OAAOT,WAAWM,KAAK,CAAC;YACtB,KAAK;gBACHO,iBAAiB;gBACjBC,QAAQ,CAAC,UAAU,EAAEF,YAAY,CAAC;gBAClCG,cAAc,CAAC,EAAET,MAAMU,KAAK,CAACD,YAAY,CAAC,EAAE,CAAC;YAC/C;YACA,0BAA0B;gBACxBE,SAAS;YACX;YACA,eAAe;gBACbC,SAAS;YACX;QACF;IACF,GAAG;QAACZ;KAAM;QA4BkCD;IA1B5C,qBACE,MAACR;QAAMsB,UAAS;QAAWC,IAAI;YAAEC,UAAU;QAAE;;0BAC3C,KAACzB,WAAW,0EAA0E;;gBACpF0B,MAAM;gBACNF,IAAI;oBACFD,UAAU;oBACVI,KAAK;oBACLC,MAAM;oBACNN,SAAS;oBACTO,OAAOnB,MAAME,OAAO,CAACkB,IAAI,CAACC,OAAO;oBACjCd,iBAAiBP,MAAME,OAAO,CAACoB,UAAU,CAACC,OAAO;oBACjDC,QAAQ;gBACV;0BACD;;0BAGD,KAAC/B;gBACE,GAAGM,IAAI;gBACRC,OAAOC,aAAa,SAAS;gBAC7BwB,YAAY;oBACVC,aAAa;oBACbC,qBAAqB;oBACrBC,2BAA2B;oBAC3BC,YAAY;oBACZ,wHAAwH;oBACxH,0EAA0E;oBAC1EC,oBAAoB,CAACnC,eAAeI,CAAAA,cAAAA,KAAKgC,KAAK,cAAVhC,yBAAAA,cAAc;gBACpD;gBACAiC,YAAY;oBAACtC,WAAWuC,YAAY;oBAAE7B;oBAAkBC;iBAAgB;gBACxE6B,aAAY;;;;AAIpB"}
@@ -11,7 +11,6 @@ type CompletionScope = {
11
11
  } | {
12
12
  kind: 'TagValue';
13
13
  tag: string;
14
- quotes?: boolean;
15
14
  };
16
15
  /**
17
16
  * Completions specifies the identified scopes and position of the completion in the current editor text.
@@ -1 +1 @@
1
- {"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../src/components/complete.ts"],"names":[],"mappings":"AAaA,OAAO,EAAc,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE3F,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAWrC,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,uGAAuG;AACvG,KAAK,eAAe,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,WAAW,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,QAAQ,CAC5B,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,iBAAiB,EACjC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAWlC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,WAAW,GAAG,SAAS,CAsHxG"}
1
+ {"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../src/components/complete.ts"],"names":[],"mappings":"AAaA,OAAO,EAAc,iBAAiB,EAAE,gBAAgB,EAAwB,MAAM,0BAA0B,CAAC;AAEjH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAYrC,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,uGAAuG;AACvG,KAAK,eAAe,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,WAAW,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,QAAQ,CAC5B,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,iBAAiB,EACjC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAWlC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,WAAW,GAAG,SAAS,CA4HxG"}
@@ -10,6 +10,7 @@
10
10
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
+ import { insertCompletionText } from '@codemirror/autocomplete';
13
14
  import { syntaxTree } from '@codemirror/language';
14
15
  import { String as StringType, FieldExpression, AttributeField, Resource, Identifier, Span, SpansetFilter, FieldOp } from '@grafana/lezer-traceql';
15
16
  export async function complete({ state, pos }, client) {
@@ -185,8 +186,7 @@ export async function complete({ state, pos }, client) {
185
186
  scopes: [
186
187
  {
187
188
  kind: 'TagValue',
188
- tag: attribute,
189
- quotes: true
189
+ tag: attribute
190
190
  }
191
191
  ],
192
192
  from: pos
@@ -196,7 +196,8 @@ export async function complete({ state, pos }, client) {
196
196
  case StringType:
197
197
  var _node_parent_parent_parent_firstChild, _node_parent_parent_parent, _node_parent_parent, _node_parent5;
198
198
  // autocomplete { resource.service.name="
199
- if (((_node_parent5 = node.parent) === null || _node_parent5 === void 0 ? void 0 : (_node_parent_parent = _node_parent5.parent) === null || _node_parent_parent === void 0 ? void 0 : (_node_parent_parent_parent = _node_parent_parent.parent) === null || _node_parent_parent_parent === void 0 ? void 0 : (_node_parent_parent_parent_firstChild = _node_parent_parent_parent.firstChild) === null || _node_parent_parent_parent_firstChild === void 0 ? void 0 : _node_parent_parent_parent_firstChild.type.id) === FieldExpression) {
199
+ // do not autocomplete if cursor is after closing quotes { resource.service.name=""
200
+ if (((_node_parent5 = node.parent) === null || _node_parent5 === void 0 ? void 0 : (_node_parent_parent = _node_parent5.parent) === null || _node_parent_parent === void 0 ? void 0 : (_node_parent_parent_parent = _node_parent_parent.parent) === null || _node_parent_parent_parent === void 0 ? void 0 : (_node_parent_parent_parent_firstChild = _node_parent_parent_parent.firstChild) === null || _node_parent_parent_parent_firstChild === void 0 ? void 0 : _node_parent_parent_parent_firstChild.type.id) === FieldExpression && !/^".*"$/.test(state.sliceDoc(node.from, pos))) {
200
201
  const fieldExpr = node.parent.parent.parent.firstChild;
201
202
  const attribute = state.sliceDoc(fieldExpr.from, fieldExpr.to);
202
203
  return {
@@ -216,6 +217,8 @@ export async function complete({ state, pos }, client) {
216
217
  if (((_node_prevSibling = node.prevSibling) === null || _node_prevSibling === void 0 ? void 0 : _node_prevSibling.type.id) === FieldOp && ((_node_parent6 = node.parent) === null || _node_parent6 === void 0 ? void 0 : (_node_parent_firstChild4 = _node_parent6.firstChild) === null || _node_parent_firstChild4 === void 0 ? void 0 : _node_parent_firstChild4.type.id) === FieldExpression) {
217
218
  const fieldExpr = node.parent.firstChild;
218
219
  const attribute = state.sliceDoc(fieldExpr.from, fieldExpr.to);
220
+ // ignore leading " in { name="HT
221
+ const from = state.sliceDoc(node.from, node.from + 1) === '"' ? node.from + 1 : node.from;
219
222
  return {
220
223
  scopes: [
221
224
  {
@@ -223,7 +226,7 @@ export async function complete({ state, pos }, client) {
223
226
  tag: attribute
224
227
  }
225
228
  ],
226
- from: node.from
229
+ from
227
230
  };
228
231
  }
229
232
  // autocomplete { s
@@ -268,7 +271,7 @@ export async function complete({ state, pos }, client) {
268
271
  break;
269
272
  case 'TagValue':
270
273
  if (client) {
271
- results.push(completeTagValue(client, completion.tag, completion.quotes));
274
+ results.push(completeTagValue(client, completion.tag));
272
275
  }
273
276
  break;
274
277
  }
@@ -286,7 +289,23 @@ async function completeTagName(client, scope) {
286
289
  label: tag
287
290
  }));
288
291
  }
289
- async function completeTagValue(client, tag, quotes) {
292
+ /**
293
+ * Add quotes to the completion text in case quotes are not present already.
294
+ * This handles the following cases:
295
+ * { name=HTTP
296
+ * { name="x
297
+ * { name="x" where cursor is after the 'x'
298
+ */ function applyQuotedCompletion(view, completion, from, to) {
299
+ let insertText = completion.label;
300
+ if (view.state.sliceDoc(from - 1, from) !== '"') {
301
+ insertText = '"' + insertText;
302
+ }
303
+ if (view.state.sliceDoc(to, to + 1) !== '"') {
304
+ insertText = insertText + '"';
305
+ }
306
+ view.dispatch(insertCompletionText(view.state, insertText, from, to));
307
+ }
308
+ async function completeTagValue(client, tag) {
290
309
  const response = await client.searchTagValues({
291
310
  tag
292
311
  });
@@ -295,8 +314,8 @@ async function completeTagValue(client, tag, quotes) {
295
314
  switch(type){
296
315
  case 'string':
297
316
  completions.push({
298
- displayLabel: value,
299
- label: quotes ? `"${value}"` : value
317
+ label: value,
318
+ apply: applyQuotedCompletion
300
319
  });
301
320
  break;
302
321
  case 'keyword':
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/complete.ts"],"sourcesContent":["// Copyright 2024 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Completion, CompletionContext, CompletionResult } 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 { TempoClient } from '../model/tempo-client';\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; quotes?: boolean };\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\nexport async function complete(\n { state, pos }: CompletionContext,\n client?: TempoClient\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(completions.scopes, client);\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, quotes: true }], from: pos };\n }\n break;\n\n case StringType:\n // autocomplete { resource.service.name=\"\n if (node.parent?.parent?.parent?.firstChild?.type.id === FieldExpression) {\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 return { scopes: [{ kind: 'TagValue', tag: attribute }], from: node.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(completions: CompletionScope[], client?: TempoClient): 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 if (client) {\n results.push(completeTagName(client, completion.scope));\n }\n break;\n\n case 'TagValue':\n if (client) {\n results.push(completeTagValue(client, completion.tag, completion.quotes));\n }\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(client: TempoClient, scope: 'resource' | 'span' | 'intrinsic'): Promise<Completion[]> {\n const response = await client.searchTags({ scope });\n return response.scopes.flatMap((scope) => scope.tags).map((tag) => ({ label: tag }));\n}\n\nasync function completeTagValue(client: TempoClient, tag: string, quotes?: boolean): Promise<Completion[]> {\n const response = await client.searchTagValues({ tag });\n const completions: Completion[] = [];\n for (const { type, value } of response.tagValues) {\n switch (type) {\n case 'string':\n completions.push({ displayLabel: value, label: quotes ? `\"${value}\"` : value });\n break;\n\n case 'keyword':\n case 'int':\n completions.push({ label: value });\n break;\n }\n }\n return completions;\n}\n"],"names":["syntaxTree","String","StringType","FieldExpression","AttributeField","Resource","Identifier","Span","SpansetFilter","FieldOp","complete","state","pos","client","completions","identifyCompletions","options","retrieveOptions","scopes","from","to","tree","node","resolveInner","type","id","firstChild","sliceDoc","includes","kind","scope","parent","text","fieldExpr","attribute","tag","quotes","prevSibling","results","completion","push","Promise","resolve","label","completeTagName","completeTagValue","all","flat","response","searchTags","flatMap","tags","map","searchTagValues","value","tagValues","displayLabel"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/components/complete.ts"],"sourcesContent":["// Copyright 2024 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Completion, CompletionContext, CompletionResult, insertCompletionText } from '@codemirror/autocomplete';\nimport { syntaxTree } from '@codemirror/language';\nimport { EditorState } from '@codemirror/state';\nimport { Tree } from '@lezer/common';\nimport {\n String as StringType,\n FieldExpression,\n AttributeField,\n Resource,\n Identifier,\n Span,\n SpansetFilter,\n FieldOp,\n} from '@grafana/lezer-traceql';\nimport { EditorView } from '@uiw/react-codemirror';\nimport { TempoClient } from '../model/tempo-client';\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\nexport async function complete(\n { state, pos }: CompletionContext,\n client?: TempoClient\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(completions.scopes, client);\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 = 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(completions: CompletionScope[], client?: TempoClient): 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 if (client) {\n results.push(completeTagName(client, completion.scope));\n }\n break;\n\n case 'TagValue':\n if (client) {\n results.push(completeTagValue(client, completion.tag));\n }\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(client: TempoClient, scope: 'resource' | 'span' | 'intrinsic'): Promise<Completion[]> {\n const response = await client.searchTags({ scope });\n return response.scopes.flatMap((scope) => scope.tags).map((tag) => ({ label: tag }));\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 */\nfunction applyQuotedCompletion(view: EditorView, completion: Completion, from: number, to: number) {\n let insertText = completion.label;\n if (view.state.sliceDoc(from - 1, from) !== '\"') {\n insertText = '\"' + insertText;\n }\n if (view.state.sliceDoc(to, to + 1) !== '\"') {\n insertText = insertText + '\"';\n }\n view.dispatch(insertCompletionText(view.state, insertText, from, to));\n}\n\nasync function completeTagValue(client: TempoClient, tag: string): Promise<Completion[]> {\n const response = await client.searchTagValues({ tag });\n const completions: Completion[] = [];\n for (const { type, value } of response.tagValues) {\n switch (type) {\n case 'string':\n completions.push({ label: value, apply: applyQuotedCompletion });\n break;\n\n case 'keyword':\n case 'int':\n completions.push({ label: value });\n break;\n }\n }\n return completions;\n}\n"],"names":["insertCompletionText","syntaxTree","String","StringType","FieldExpression","AttributeField","Resource","Identifier","Span","SpansetFilter","FieldOp","complete","state","pos","client","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","response","searchTags","flatMap","tags","map","applyQuotedCompletion","view","insertText","dispatch","searchTagValues","value","tagValues","apply"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { TempoDatasource } from './plugins/tempo-datasource';
2
2
  import { TempoTraceQuery } from './plugins/tempo-trace-query/TempoTraceQuery';
3
3
  export { TempoTraceQuery, TempoDatasource };
4
- export * from './model/tempo-client';
5
- export * from './model/tempo-selectors';
4
+ export * from './model';
6
5
  export * from './components/TraceQLExtension';
7
6
  //# sourceMappingURL=index.d.ts.map