@perses-dev/loki-plugin 0.3.0 → 0.5.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/__mf/js/Loki.b64c7408.js +6 -0
  2. package/__mf/js/async/1238.71fd7843.js +1 -0
  3. package/__mf/js/async/1490.0d8dcc42.js +22 -0
  4. package/__mf/js/async/1501.eefd56b9.js +1 -0
  5. package/__mf/js/async/1616.60c9a082.js +1 -0
  6. package/__mf/js/async/1728.21a8f690.js +1 -0
  7. package/__mf/js/async/1811.a291a38b.js +28 -0
  8. package/__mf/js/async/1825.5005b3af.js +1 -0
  9. package/__mf/js/async/1969.53d223ca.js +1 -0
  10. package/__mf/js/async/2043.eb7e1c61.js +2 -0
  11. package/__mf/js/async/2386.a3cfef97.js +2 -0
  12. package/__mf/js/async/3059.cb101ca2.js +1 -0
  13. package/__mf/js/async/3181.d2b90b95.js +2 -0
  14. package/__mf/js/async/3849.85df5535.js +7 -0
  15. package/__mf/js/async/392.c0f9d49a.js +2 -0
  16. package/__mf/js/async/{1964.7b2e7223.js → 4121.328a1e93.js} +2 -2
  17. package/__mf/js/async/4466.21ddc88c.js +74 -0
  18. package/__mf/js/async/{2651.ef335482.js → 5002.29685f8e.js} +1 -1
  19. package/__mf/js/async/5071.a03a64fd.js +1 -0
  20. package/__mf/js/async/5440.3fedd5ea.js +2 -0
  21. package/__mf/js/async/5501.01af8b43.js +2 -0
  22. package/__mf/js/async/{5214.fee648bb.js → 5587.55dbc663.js} +1 -1
  23. package/__mf/js/async/6100.e2898f9c.js +1 -0
  24. package/__mf/js/async/6274.293b47c4.js +2 -0
  25. package/__mf/js/async/6283.78af4bc8.js +2 -0
  26. package/__mf/js/async/6498.903f2a94.js +2 -0
  27. package/__mf/js/async/7177.b50a1c64.js +1 -0
  28. package/__mf/js/async/7192.4dea1fd0.js +1 -0
  29. package/__mf/js/async/7370.0ddd349a.js +2 -0
  30. package/__mf/js/async/7968.ec040694.js +1 -0
  31. package/__mf/js/async/7978.38078276.js +1 -0
  32. package/__mf/js/async/8035.8dab4893.js +38 -0
  33. package/__mf/js/async/8356.5635696c.js +1 -0
  34. package/__mf/js/async/8470.c67049a2.js +2 -0
  35. package/__mf/js/async/8482.07caae1a.js +1 -0
  36. package/__mf/js/async/873.02aa55af.js +1 -0
  37. package/__mf/js/async/8988.1c565f12.js +1 -0
  38. package/__mf/js/async/9071.ed72bdac.js +2 -0
  39. package/__mf/js/async/9235.f2e0e95c.js +1 -0
  40. package/__mf/js/async/9389.a8ea42a0.js +2 -0
  41. package/__mf/js/async/941.0bce16fe.js +2 -0
  42. package/__mf/js/async/9588.2d82f477.js +1 -0
  43. package/__mf/js/async/9754.5d7b21c2.js +10 -0
  44. package/__mf/js/async/9836.de786d07.js +1 -0
  45. package/__mf/js/async/__federation_expose_LokiDatasource.3da46ee2.js +2 -0
  46. package/__mf/js/async/__federation_expose_LokiLogQuery.c1be0273.js +1 -0
  47. package/__mf/js/async/__federation_expose_LokiTimeSeriesQuery.cf876f4b.js +1 -0
  48. package/__mf/js/main.de30f7e6.js +6 -0
  49. package/lib/bootstrap.js +3 -3
  50. package/lib/bootstrap.js.map +1 -1
  51. package/lib/cjs/bootstrap.js +1 -1
  52. package/lib/cjs/components/complete.js +258 -0
  53. package/lib/cjs/components/logql-editor.js +6 -3
  54. package/lib/cjs/components/logql-extension.js +15 -1
  55. package/lib/cjs/model/index.js +1 -0
  56. package/lib/cjs/model/loki-client.js +10 -10
  57. package/lib/cjs/model/loki-selectors.js +5 -5
  58. package/lib/cjs/queries/constants.js +3 -3
  59. package/lib/cjs/queries/loki-log-query/LokiLogQueryEditor.js +21 -17
  60. package/lib/cjs/queries/loki-time-series-query/LokiTimeSeriesQueryEditor.js +5 -16
  61. package/lib/components/complete.d.ts +37 -0
  62. package/lib/components/complete.d.ts.map +1 -0
  63. package/lib/components/complete.js +249 -0
  64. package/lib/components/complete.js.map +1 -0
  65. package/lib/components/logql-editor.d.ts +4 -1
  66. package/lib/components/logql-editor.d.ts.map +1 -1
  67. package/lib/components/logql-editor.js +7 -4
  68. package/lib/components/logql-editor.js.map +1 -1
  69. package/lib/components/logql-extension.d.ts +9 -1
  70. package/lib/components/logql-extension.d.ts.map +1 -1
  71. package/lib/components/logql-extension.js +15 -1
  72. package/lib/components/logql-extension.js.map +1 -1
  73. package/lib/datasources/loki-datasource/LokiDatasourceEditor.js +1 -1
  74. package/lib/datasources/loki-datasource/LokiDatasourceEditor.js.map +1 -1
  75. package/lib/model/index.d.ts +1 -0
  76. package/lib/model/index.d.ts.map +1 -1
  77. package/lib/model/index.js +1 -0
  78. package/lib/model/index.js.map +1 -1
  79. package/lib/queries/loki-log-query/LokiLogQueryEditor.d.ts.map +1 -1
  80. package/lib/queries/loki-log-query/LokiLogQueryEditor.js +23 -19
  81. package/lib/queries/loki-log-query/LokiLogQueryEditor.js.map +1 -1
  82. package/lib/queries/loki-log-query/get-loki-log-data.js.map +1 -1
  83. package/lib/queries/loki-log-query/log-query-plugin-interface.d.ts +0 -1
  84. package/lib/queries/loki-log-query/log-query-plugin-interface.d.ts.map +1 -1
  85. package/lib/queries/loki-log-query/log-query-plugin-interface.js.map +1 -1
  86. package/lib/queries/loki-time-series-query/LokiTimeSeriesQueryEditor.d.ts.map +1 -1
  87. package/lib/queries/loki-time-series-query/LokiTimeSeriesQueryEditor.js +5 -16
  88. package/lib/queries/loki-time-series-query/LokiTimeSeriesQueryEditor.js.map +1 -1
  89. package/lib/queries/loki-time-series-query/get-loki-time-series-data.d.ts +1 -4
  90. package/lib/queries/loki-time-series-query/get-loki-time-series-data.d.ts.map +1 -1
  91. package/lib/queries/loki-time-series-query/get-loki-time-series-data.js.map +1 -1
  92. package/mf-manifest.json +107 -102
  93. package/mf-stats.json +107 -102
  94. package/package.json +7 -6
  95. package/__mf/js/Loki.2f631825.js +0 -5
  96. package/__mf/js/async/1360.2348e2a7.js +0 -10
  97. package/__mf/js/async/1540.6b797827.js +0 -74
  98. package/__mf/js/async/1580.c7d3c3f1.js +0 -2
  99. package/__mf/js/async/2178.c22bac1c.js +0 -2
  100. package/__mf/js/async/2226.a056d1a3.js +0 -1
  101. package/__mf/js/async/2292.35c2eeec.js +0 -2
  102. package/__mf/js/async/2472.75bb97e0.js +0 -22
  103. package/__mf/js/async/2652.7b7038d2.js +0 -28
  104. package/__mf/js/async/2708.9651e2da.js +0 -1
  105. package/__mf/js/async/282.6c4c5a94.js +0 -1
  106. package/__mf/js/async/3224.b1170acc.js +0 -1
  107. package/__mf/js/async/3431.2270637c.js +0 -1
  108. package/__mf/js/async/3863.16343b76.js +0 -2
  109. package/__mf/js/async/3960.6091bb00.js +0 -2
  110. package/__mf/js/async/3980.08ab4aef.js +0 -2
  111. package/__mf/js/async/4075.19dee570.js +0 -1
  112. package/__mf/js/async/4238.155e3b8a.js +0 -1
  113. package/__mf/js/async/4269.b4d0f49d.js +0 -2
  114. package/__mf/js/async/4310.b96a5c66.js +0 -7
  115. package/__mf/js/async/4421.5adcbc2d.js +0 -1
  116. package/__mf/js/async/529.f12e49de.js +0 -2
  117. package/__mf/js/async/5409.ff95cf63.js +0 -1
  118. package/__mf/js/async/5780.d837c3cd.js +0 -1
  119. package/__mf/js/async/5981.a46c5157.js +0 -2
  120. package/__mf/js/async/6134.f7ee513c.js +0 -38
  121. package/__mf/js/async/6292.9997ca36.js +0 -1
  122. package/__mf/js/async/6329.9c3a3698.js +0 -2
  123. package/__mf/js/async/6333.01fb6457.js +0 -2
  124. package/__mf/js/async/6377.9f308c7f.js +0 -2
  125. package/__mf/js/async/6770.ba5a38f3.js +0 -1
  126. package/__mf/js/async/694.c25a1f84.js +0 -1
  127. package/__mf/js/async/7376.0459aaf7.js +0 -1
  128. package/__mf/js/async/738.a16c93b6.js +0 -1
  129. package/__mf/js/async/7740.6f193fac.js +0 -1
  130. package/__mf/js/async/8216.d9cc6234.js +0 -1
  131. package/__mf/js/async/8488.5b4b7170.js +0 -1
  132. package/__mf/js/async/8537.dc791586.js +0 -1
  133. package/__mf/js/async/9173.75bbe78a.js +0 -2
  134. package/__mf/js/async/9563.0375701c.js +0 -2
  135. package/__mf/js/async/__federation_expose_LokiDatasource.a9871645.js +0 -2
  136. package/__mf/js/async/__federation_expose_LokiLogQuery.9b430d01.js +0 -1
  137. package/__mf/js/async/__federation_expose_LokiTimeSeriesQuery.61feff51.js +0 -1
  138. package/__mf/js/main.174be1bc.js +0 -5
  139. /package/__mf/css/async/{1580.d3010b86.css → 3061.d3010b86.css} +0 -0
  140. /package/__mf/css/async/{2341.d3010b86.css → 5442.d3010b86.css} +0 -0
  141. /package/__mf/css/async/{6759.d3010b86.css → 7370.d3010b86.css} +0 -0
  142. /package/__mf/js/async/{2472.75bb97e0.js.LICENSE.txt → 1490.0d8dcc42.js.LICENSE.txt} +0 -0
  143. /package/__mf/js/async/{2292.35c2eeec.js.LICENSE.txt → 2043.eb7e1c61.js.LICENSE.txt} +0 -0
  144. /package/__mf/js/async/{1580.c7d3c3f1.js.LICENSE.txt → 2386.a3cfef97.js.LICENSE.txt} +0 -0
  145. /package/__mf/js/async/{3863.16343b76.js.LICENSE.txt → 3181.d2b90b95.js.LICENSE.txt} +0 -0
  146. /package/__mf/js/async/{4310.b96a5c66.js.LICENSE.txt → 3849.85df5535.js.LICENSE.txt} +0 -0
  147. /package/__mf/js/async/{5981.a46c5157.js.LICENSE.txt → 392.c0f9d49a.js.LICENSE.txt} +0 -0
  148. /package/__mf/js/async/{1964.7b2e7223.js.LICENSE.txt → 4121.328a1e93.js.LICENSE.txt} +0 -0
  149. /package/__mf/js/async/{6377.9f308c7f.js.LICENSE.txt → 5440.3fedd5ea.js.LICENSE.txt} +0 -0
  150. /package/__mf/js/async/{2178.c22bac1c.js.LICENSE.txt → 5501.01af8b43.js.LICENSE.txt} +0 -0
  151. /package/__mf/js/async/{3960.6091bb00.js.LICENSE.txt → 6274.293b47c4.js.LICENSE.txt} +0 -0
  152. /package/__mf/js/async/{3980.08ab4aef.js.LICENSE.txt → 6283.78af4bc8.js.LICENSE.txt} +0 -0
  153. /package/__mf/js/async/{529.f12e49de.js.LICENSE.txt → 6498.903f2a94.js.LICENSE.txt} +0 -0
  154. /package/__mf/js/async/{4269.b4d0f49d.js.LICENSE.txt → 7370.0ddd349a.js.LICENSE.txt} +0 -0
  155. /package/__mf/js/async/{9173.75bbe78a.js.LICENSE.txt → 8470.c67049a2.js.LICENSE.txt} +0 -0
  156. /package/__mf/js/async/{6329.9c3a3698.js.LICENSE.txt → 9071.ed72bdac.js.LICENSE.txt} +0 -0
  157. /package/__mf/js/async/{6333.01fb6457.js.LICENSE.txt → 9389.a8ea42a0.js.LICENSE.txt} +0 -0
  158. /package/__mf/js/async/{9563.0375701c.js.LICENSE.txt → 941.0bce16fe.js.LICENSE.txt} +0 -0
  159. /package/__mf/js/async/{1360.2348e2a7.js.LICENSE.txt → 9754.5d7b21c2.js.LICENSE.txt} +0 -0
  160. /package/__mf/js/async/{__federation_expose_LokiDatasource.a9871645.js.LICENSE.txt → __federation_expose_LokiDatasource.3da46ee2.js.LICENSE.txt} +0 -0
@@ -17,35 +17,35 @@ Object.defineProperty(exports, "__esModule", {
17
17
  function _export(target, all) {
18
18
  for(var name in all)Object.defineProperty(target, name, {
19
19
  enumerable: true,
20
- get: all[name]
20
+ get: Object.getOwnPropertyDescriptor(all, name).get
21
21
  });
22
22
  }
23
23
  _export(exports, {
24
- indexStats: function() {
24
+ get indexStats () {
25
25
  return indexStats;
26
26
  },
27
- labelValues: function() {
27
+ get labelValues () {
28
28
  return labelValues;
29
29
  },
30
- labels: function() {
30
+ get labels () {
31
31
  return labels;
32
32
  },
33
- query: function() {
33
+ get query () {
34
34
  return query;
35
35
  },
36
- queryRange: function() {
36
+ get queryRange () {
37
37
  return queryRange;
38
38
  },
39
- series: function() {
39
+ get series () {
40
40
  return series;
41
41
  },
42
- toUnixSeconds: function() {
42
+ get toUnixSeconds () {
43
43
  return toUnixSeconds;
44
44
  },
45
- volume: function() {
45
+ get volume () {
46
46
  return volume;
47
47
  },
48
- volumeRange: function() {
48
+ get volumeRange () {
49
49
  return volumeRange;
50
50
  }
51
51
  });
@@ -17,20 +17,20 @@ Object.defineProperty(exports, "__esModule", {
17
17
  function _export(target, all) {
18
18
  for(var name in all)Object.defineProperty(target, name, {
19
19
  enumerable: true,
20
- get: all[name]
20
+ get: Object.getOwnPropertyDescriptor(all, name).get
21
21
  });
22
22
  }
23
23
  _export(exports, {
24
- DEFAULT_LOKI: function() {
24
+ get DEFAULT_LOKI () {
25
25
  return DEFAULT_LOKI;
26
26
  },
27
- LOKI_DATASOURCE_KIND: function() {
27
+ get LOKI_DATASOURCE_KIND () {
28
28
  return LOKI_DATASOURCE_KIND;
29
29
  },
30
- isDefaultLokiSelector: function() {
30
+ get isDefaultLokiSelector () {
31
31
  return isDefaultLokiSelector;
32
32
  },
33
- isLokiDatasourceSelector: function() {
33
+ get isLokiDatasourceSelector () {
34
34
  return isLokiDatasourceSelector;
35
35
  }
36
36
  });
@@ -5,14 +5,14 @@ Object.defineProperty(exports, "__esModule", {
5
5
  function _export(target, all) {
6
6
  for(var name in all)Object.defineProperty(target, name, {
7
7
  enumerable: true,
8
- get: all[name]
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
9
  });
10
10
  }
11
11
  _export(exports, {
12
- DATASOURCE_KIND: function() {
12
+ get DATASOURCE_KIND () {
13
13
  return DATASOURCE_KIND;
14
14
  },
15
- DEFAULT_DATASOURCE: function() {
15
+ get DEFAULT_DATASOURCE () {
16
16
  return DEFAULT_DATASOURCE;
17
17
  }
18
18
  });
@@ -26,16 +26,30 @@ const _material = require("@mui/material");
26
26
  const _react = require("react");
27
27
  const _immer = require("immer");
28
28
  const _components = require("@perses-dev/components");
29
- const _logqleditor = require("../../components/logql-editor");
29
+ const _components1 = require("../../components");
30
30
  const _model = require("../../model");
31
31
  const _constants = require("../constants");
32
32
  const _queryeditormodel = require("../query-editor-model");
33
33
  function LokiLogQueryEditor(props) {
34
- const { onChange, value, queryHandlerSettings } = props;
34
+ const { onChange, value } = props;
35
35
  const { datasource } = value;
36
36
  const datasourceSelectValue = datasource ?? _constants.DEFAULT_DATASOURCE;
37
37
  const selectedDatasource = (0, _pluginsystem.useDatasourceSelectValueToSelector)(datasourceSelectValue, _model.LOKI_DATASOURCE_KIND);
38
38
  const { query, handleQueryChange, handleQueryBlur } = (0, _queryeditormodel.useQueryState)(props);
39
+ // Get client and time range for autocompletion
40
+ const { data: client } = (0, _pluginsystem.useDatasourceClient)(selectedDatasource);
41
+ const { absoluteTimeRange } = (0, _pluginsystem.useTimeRange)();
42
+ // Create completion config for autocompletion
43
+ const completionConfig = (0, _react.useMemo)(()=>{
44
+ if (!client) return undefined;
45
+ return {
46
+ client,
47
+ timeRange: absoluteTimeRange
48
+ };
49
+ }, [
50
+ client,
51
+ absoluteTimeRange
52
+ ]);
39
53
  const handleDatasourceChange = (newDatasourceSelection)=>{
40
54
  if (!(0, _pluginsystem.isVariableDatasource)(newDatasourceSelection) && newDatasourceSelection.kind === _constants.DATASOURCE_KIND) {
41
55
  onChange((0, _immer.produce)(value, (draft)=>{
@@ -43,10 +57,6 @@ function LokiLogQueryEditor(props) {
43
57
  const nextDatasource = (0, _model.isDefaultLokiSelector)(newDatasourceSelection) ? undefined : newDatasourceSelection;
44
58
  draft.datasource = nextDatasource;
45
59
  }));
46
- if (queryHandlerSettings?.setWatchOtherSpecs) queryHandlerSettings.setWatchOtherSpecs({
47
- ...value,
48
- datasource: newDatasourceSelection
49
- });
50
60
  return;
51
61
  }
52
62
  throw new Error('Got unexpected non LokiQuery datasource selection');
@@ -56,21 +66,14 @@ function LokiLogQueryEditor(props) {
56
66
  }));
57
67
  // Immediate query execution on Enter or blur
58
68
  const handleQueryExecute = (query)=>{
59
- if (queryHandlerSettings?.watchQueryChanges) {
60
- queryHandlerSettings.watchQueryChanges(query);
61
- }
62
69
  onChange((0, _immer.produce)(value, (draft)=>{
63
70
  draft.query = query;
64
71
  }));
65
72
  };
66
73
  const handleLogsQueryChange = (0, _react.useCallback)((e)=>{
67
74
  handleQueryChange(e);
68
- if (queryHandlerSettings?.watchQueryChanges) {
69
- queryHandlerSettings.watchQueryChanges(e);
70
- }
71
75
  }, [
72
- handleQueryChange,
73
- queryHandlerSettings
76
+ handleQueryChange
74
77
  ]);
75
78
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
76
79
  spacing: 1.5,
@@ -105,17 +108,18 @@ function LokiLogQueryEditor(props) {
105
108
  },
106
109
  children: "LogQL Query"
107
110
  }),
108
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_logqleditor.LogQLEditor, {
111
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_components1.LogQLEditor, {
109
112
  value: query,
110
113
  onChange: handleLogsQueryChange,
111
- onBlur: queryHandlerSettings?.runWithOnBlur ? handleQueryBlur : undefined,
114
+ onBlur: handleQueryBlur,
112
115
  onKeyDown: (event)=>{
113
116
  if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {
114
117
  event.preventDefault();
115
118
  handleQueryExecute(query);
116
119
  }
117
120
  },
118
- placeholder: 'Enter LogQL query (e.g. {job="mysql"} |= "error")'
121
+ placeholder: 'Enter LogQL query (e.g. {job="mysql"} |= "error")',
122
+ completionConfig: completionConfig
119
123
  })
120
124
  ]
121
125
  }),
@@ -25,12 +25,12 @@ const _pluginsystem = require("@perses-dev/plugin-system");
25
25
  const _material = require("@mui/material");
26
26
  const _react = require("react");
27
27
  const _immer = require("immer");
28
- const _logqleditor = require("../../components/logql-editor");
28
+ const _components = require("../../components");
29
29
  const _model = require("../../model");
30
30
  const _constants = require("../constants");
31
31
  const _queryeditormodel = require("../query-editor-model");
32
32
  function LokiQueryEditor(props) {
33
- const { onChange, value, queryHandlerSettings } = props;
33
+ const { onChange, value } = props;
34
34
  const { datasource } = value;
35
35
  const datasourceSelectValue = datasource ?? _constants.DEFAULT_DATASOURCE;
36
36
  const selectedDatasource = (0, _pluginsystem.useDatasourceSelectValueToSelector)(datasourceSelectValue, _model.LOKI_DATASOURCE_KIND);
@@ -40,31 +40,20 @@ function LokiQueryEditor(props) {
40
40
  onChange((0, _immer.produce)(value, (draft)=>{
41
41
  draft.datasource = newDatasourceSelection;
42
42
  }));
43
- if (queryHandlerSettings?.setWatchOtherSpecs) queryHandlerSettings.setWatchOtherSpecs({
44
- ...value,
45
- datasource: newDatasourceSelection
46
- });
47
43
  return;
48
44
  }
49
45
  throw new Error('Got unexpected non LokiQuery datasource selection');
50
46
  };
51
47
  // Immediate query execution on Enter or blur
52
48
  const handleQueryExecute = (query)=>{
53
- if (queryHandlerSettings?.watchQueryChanges) {
54
- queryHandlerSettings.watchQueryChanges(query);
55
- }
56
49
  onChange((0, _immer.produce)(value, (draft)=>{
57
50
  draft.query = query;
58
51
  }));
59
52
  };
60
53
  const handleLogsQueryChange = (0, _react.useCallback)((e)=>{
61
54
  handleQueryChange(e);
62
- if (queryHandlerSettings?.watchQueryChanges) {
63
- queryHandlerSettings.watchQueryChanges(e);
64
- }
65
55
  }, [
66
- handleQueryChange,
67
- queryHandlerSettings
56
+ handleQueryChange
68
57
  ]);
69
58
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.Stack, {
70
59
  spacing: 1.5,
@@ -99,10 +88,10 @@ function LokiQueryEditor(props) {
99
88
  },
100
89
  children: "LogQL Query"
101
90
  }),
102
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_logqleditor.LogQLEditor, {
91
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.LogQLEditor, {
103
92
  value: query,
104
93
  onChange: handleLogsQueryChange,
105
- onBlur: queryHandlerSettings?.runWithOnBlur ? handleQueryBlur : undefined,
94
+ onBlur: handleQueryBlur,
106
95
  onKeyDown: (event)=>{
107
96
  if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {
108
97
  event.preventDefault();
@@ -0,0 +1,37 @@
1
+ import { Completion, CompletionContext, CompletionResult } from '@codemirror/autocomplete';
2
+ import { EditorState } from '@codemirror/state';
3
+ import { Tree } from '@lezer/common';
4
+ import { EditorView } from '@uiw/react-codemirror';
5
+ import { CompletionConfig } from './logql-extension';
6
+ /** CompletionScope specifies the completion kind, e.g. whether to complete label names or values */
7
+ type CompletionScope = {
8
+ kind: 'LabelName';
9
+ } | {
10
+ kind: 'LabelValue';
11
+ label: string;
12
+ };
13
+ /**
14
+ * CompletionInfo specifies the identified scope and position of the completion in the current editor text.
15
+ */
16
+ export interface CompletionInfo {
17
+ scope: CompletionScope;
18
+ from: number;
19
+ to?: number;
20
+ }
21
+ export declare function complete(completionCfg: CompletionConfig, { state, pos }: CompletionContext): Promise<CompletionResult | null>;
22
+ /**
23
+ * Identify completion scope (e.g. LabelName, LabelValue) and position, based on the current node in the syntax tree.
24
+ *
25
+ * Function is exported for tests only.
26
+ */
27
+ export declare function identifyCompletion(state: EditorState, pos: number, tree: Tree): CompletionInfo | undefined;
28
+ /**
29
+ * Add quotes to the completion text in case quotes are not present already.
30
+ * This handles the following cases:
31
+ * { name=HTTP
32
+ * { name="x
33
+ * { name="x" where cursor is after the 'x'
34
+ */
35
+ export declare function applyQuotedCompletion(view: EditorView, completion: Completion, from: number, to: number): void;
36
+ export {};
37
+ //# sourceMappingURL=complete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../../src/components/complete.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,gBAAgB,EAAwB,MAAM,0BAA0B,CAAC;AAEjH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,oGAAoG;AACpG,KAAK,eAAe,GAAG;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAErF;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,eAAe,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAKD,wBAAsB,QAAQ,CAC5B,aAAa,EAAE,gBAAgB,EAC/B,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,iBAAiB,GAChC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAWlC;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,cAAc,GAAG,SAAS,CA6G1G;AAkDD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAmB9G"}
@@ -0,0 +1,249 @@
1
+ // Copyright 2025 The Perses Authors
2
+ // Licensed under the Apache License, Version 2.0 (the "License");
3
+ // you may not use this file except in compliance with the License.
4
+ // You may obtain a copy of the License at
5
+ //
6
+ // http://www.apache.org/licenses/LICENSE-2.0
7
+ //
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+ import { insertCompletionText } from '@codemirror/autocomplete';
14
+ import { syntaxTree } from '@codemirror/language';
15
+ import { Selector, Matchers, Matcher, Identifier, Eq, Neq, Re, Nre, String as StringType } from '@grafana/lezer-logql';
16
+ import { toUnixSeconds } from '../model/loki-client';
17
+ const quoteChars = [
18
+ '"',
19
+ '`'
20
+ ];
21
+ const defaultQuoteChar = '"';
22
+ export async function complete(completionCfg, { state, pos }) {
23
+ // First, identify the completion scope
24
+ const completion = identifyCompletion(state, pos, syntaxTree(state));
25
+ if (!completion) {
26
+ // No completion scope found for current cursor position.
27
+ return null;
28
+ }
29
+ // Then, retrieve completion options for the identified scope (from the Loki API).
30
+ const options = await retrieveOptions(completionCfg, completion.scope);
31
+ return {
32
+ options,
33
+ from: completion.from,
34
+ to: completion.to
35
+ };
36
+ }
37
+ /**
38
+ * Identify completion scope (e.g. LabelName, LabelValue) and position, based on the current node in the syntax tree.
39
+ *
40
+ * Function is exported for tests only.
41
+ */ export function identifyCompletion(state, pos, tree) {
42
+ const node = tree.resolveInner(pos, -1);
43
+ switch(node.type.id){
44
+ case Selector:
45
+ // Selector is the entire {label matchers} expression
46
+ // Autocomplete at start: {▯ or empty: {}
47
+ // Do not autocomplete if cursor is after closing brace: {job="mysql"}▯
48
+ if ((node.firstChild === null || node.firstChild?.type.id === 0) && !state.sliceDoc(node.from, pos).includes('}')) {
49
+ return {
50
+ scope: {
51
+ kind: 'LabelName'
52
+ },
53
+ from: pos
54
+ };
55
+ }
56
+ break;
57
+ case Matchers:
58
+ {
59
+ // Matchers node contains all label matchers inside {}
60
+ // Autocomplete after comma: { job="mysql",▯ or { job="mysql", ▯
61
+ const text = state.sliceDoc(node.from, pos);
62
+ if (text.endsWith(',') || text.endsWith(', ')) {
63
+ return {
64
+ scope: {
65
+ kind: 'LabelName'
66
+ },
67
+ from: pos
68
+ };
69
+ }
70
+ break;
71
+ }
72
+ case Matcher:
73
+ // Single matcher like job="mysql"
74
+ // Autocomplete when cursor is after a complete matcher: { job="mysql" ▯
75
+ if (node.parent?.type.id === Matchers) {
76
+ return {
77
+ scope: {
78
+ kind: 'LabelName'
79
+ },
80
+ from: pos
81
+ };
82
+ }
83
+ break;
84
+ case Identifier:
85
+ // Identifier is a label name being typed
86
+ // Autocomplete partial label names: { jo▯ or { job="mysql", na▯
87
+ if (node.parent?.type.id === Matcher) {
88
+ return {
89
+ scope: {
90
+ kind: 'LabelName'
91
+ },
92
+ from: node.from
93
+ };
94
+ }
95
+ break;
96
+ case Eq:
97
+ case Neq:
98
+ case Re:
99
+ case Nre:
100
+ // Operators for label matching: =, !=, =~, !~
101
+ // Autocomplete label values right after operator: { job=▯ or { job!=▯
102
+ if (node.parent?.type.id === Matcher) {
103
+ const labelNode = node.parent.firstChild;
104
+ if (labelNode?.type.id === Identifier) {
105
+ const label = state.sliceDoc(labelNode.from, labelNode.to);
106
+ return {
107
+ scope: {
108
+ kind: 'LabelValue',
109
+ label
110
+ },
111
+ from: pos
112
+ };
113
+ }
114
+ }
115
+ break;
116
+ case StringType:
117
+ // String value in a matcher: { job="▯
118
+ // Do not autocomplete if cursor is after closing quotes: { job=""▯
119
+ if (node.parent?.type.id === Matcher && !/^".*"$/.test(state.sliceDoc(node.from, pos))) {
120
+ const labelNode = node.parent.firstChild;
121
+ if (labelNode?.type.id === Identifier) {
122
+ const label = state.sliceDoc(labelNode.from, labelNode.to);
123
+ return {
124
+ scope: {
125
+ kind: 'LabelValue',
126
+ label
127
+ },
128
+ from: node.from + 1
129
+ }; // +1 to skip opening quote
130
+ }
131
+ }
132
+ break;
133
+ case 0 /* error node */ :
134
+ // Error nodes represent incomplete or malformed syntax
135
+ // Autocomplete incomplete value after operator: { job=mys▯ or { job="mys▯
136
+ if ((node.prevSibling?.type.id === Eq || node.prevSibling?.type.id === Neq || node.prevSibling?.type.id === Re || node.prevSibling?.type.id === Nre) && node.parent?.type.id === Matcher) {
137
+ const labelNode = node.parent.firstChild;
138
+ if (labelNode?.type.id === Identifier) {
139
+ const label = state.sliceDoc(labelNode.from, labelNode.to);
140
+ // Skip leading quote if present: { name="HT▯
141
+ const from = quoteChars.includes(state.sliceDoc(node.from, node.from + 1)) ? node.from + 1 : node.from;
142
+ return {
143
+ scope: {
144
+ kind: 'LabelValue',
145
+ label
146
+ },
147
+ from
148
+ };
149
+ }
150
+ }
151
+ // Autocomplete partial label name: { j▯ or { job="mysql", n▯
152
+ if (node.parent?.type.id === Selector || node.parent?.type.id === Matchers) {
153
+ return {
154
+ scope: {
155
+ kind: 'LabelName'
156
+ },
157
+ from: node.from
158
+ };
159
+ }
160
+ break;
161
+ }
162
+ }
163
+ /**
164
+ * Retrieve completion options based on the identified completion scope.
165
+ */ async function retrieveOptions(completionCfg, completion) {
166
+ switch(completion.kind){
167
+ case 'LabelName':
168
+ return completeLabelName(completionCfg);
169
+ case 'LabelValue':
170
+ return completeLabelValue(completionCfg, completion.label);
171
+ }
172
+ }
173
+ async function completeLabelName(completionCfg) {
174
+ if (!completionCfg.client) {
175
+ return [];
176
+ }
177
+ const start = completionCfg.timeRange?.start ? toUnixSeconds(new Date(completionCfg.timeRange.start).getTime()) : undefined;
178
+ const end = completionCfg.timeRange?.end ? toUnixSeconds(new Date(completionCfg.timeRange.end).getTime()) : undefined;
179
+ try {
180
+ const response = await completionCfg.client.labels(start, end);
181
+ if (response.status === 'success') {
182
+ return response.data.map((label)=>({
183
+ label
184
+ }));
185
+ }
186
+ return [];
187
+ } catch (error) {
188
+ console.error('Error fetching label names:', error);
189
+ return [];
190
+ }
191
+ }
192
+ function escapeString(input, quoteChar) {
193
+ // do not escape raw strings (when using backticks)
194
+ if (quoteChar === '`') {
195
+ return input;
196
+ }
197
+ let escaped = input;
198
+ // escape backslashes and quotes
199
+ escaped = escaped.replaceAll('\\', '\\\\');
200
+ escaped = escaped.replaceAll('"', '\\"');
201
+ return escaped;
202
+ }
203
+ /**
204
+ * Add quotes to the completion text in case quotes are not present already.
205
+ * This handles the following cases:
206
+ * { name=HTTP
207
+ * { name="x
208
+ * { name="x" where cursor is after the 'x'
209
+ */ export function applyQuotedCompletion(view, completion, from, to) {
210
+ let quoteChar = defaultQuoteChar;
211
+ if (quoteChars.includes(view.state.sliceDoc(from - 1, from))) {
212
+ quoteChar = view.state.sliceDoc(from - 1, from);
213
+ from--;
214
+ }
215
+ if (quoteChars.includes(view.state.sliceDoc(to, to + 1))) {
216
+ quoteChar = view.state.sliceDoc(to, to + 1);
217
+ to++;
218
+ }
219
+ // When using raw strings (`), we cannot escape a backtick.
220
+ // Therefore, switch the quote character.
221
+ if (completion.label.includes('`')) {
222
+ quoteChar = '"';
223
+ }
224
+ const insertText = `${quoteChar}${escapeString(completion.label, quoteChar)}${quoteChar}`;
225
+ view.dispatch(insertCompletionText(view.state, insertText, from, to));
226
+ }
227
+ async function completeLabelValue(completionCfg, label) {
228
+ if (!completionCfg.client) {
229
+ return [];
230
+ }
231
+ const start = completionCfg.timeRange?.start ? toUnixSeconds(new Date(completionCfg.timeRange.start).getTime()) : undefined;
232
+ const end = completionCfg.timeRange?.end ? toUnixSeconds(new Date(completionCfg.timeRange.end).getTime()) : undefined;
233
+ try {
234
+ const response = await completionCfg.client.labelValues(label, start, end);
235
+ if (response.status === 'success') {
236
+ return response.data.map((value)=>({
237
+ label: value ?? '',
238
+ displayLabel: value ?? '(empty string)',
239
+ apply: applyQuotedCompletion
240
+ }));
241
+ }
242
+ return [];
243
+ } catch (error) {
244
+ console.error(`Error fetching values for label ${label}:`, error);
245
+ return [];
246
+ }
247
+ }
248
+
249
+ //# sourceMappingURL=complete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/complete.ts"],"sourcesContent":["// Copyright 2025 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Completion, CompletionContext, CompletionResult, insertCompletionText } from '@codemirror/autocomplete';\nimport { syntaxTree } from '@codemirror/language';\nimport { EditorState } from '@codemirror/state';\nimport { Tree } from '@lezer/common';\nimport { Selector, Matchers, Matcher, Identifier, Eq, Neq, Re, Nre, String as StringType } from '@grafana/lezer-logql';\nimport { EditorView } from '@uiw/react-codemirror';\nimport { toUnixSeconds } from '../model/loki-client';\nimport { CompletionConfig } from './logql-extension';\n\n/** CompletionScope specifies the completion kind, e.g. whether to complete label names or values */\ntype CompletionScope = { kind: 'LabelName' } | { kind: 'LabelValue'; label: string };\n\n/**\n * CompletionInfo specifies the identified scope and position of the completion in the current editor text.\n */\nexport interface CompletionInfo {\n scope: 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 scope\n const completion = identifyCompletion(state, pos, syntaxTree(state));\n if (!completion) {\n // No completion scope found for current cursor position.\n return null;\n }\n\n // Then, retrieve completion options for the identified scope (from the Loki API).\n const options = await retrieveOptions(completionCfg, completion.scope);\n return { options, from: completion.from, to: completion.to };\n}\n\n/**\n * Identify completion scope (e.g. LabelName, LabelValue) and position, based on the current node in the syntax tree.\n *\n * Function is exported for tests only.\n */\nexport function identifyCompletion(state: EditorState, pos: number, tree: Tree): CompletionInfo | undefined {\n const node = tree.resolveInner(pos, -1);\n\n switch (node.type.id) {\n case Selector:\n // Selector is the entire {label matchers} expression\n // Autocomplete at start: {▯ or empty: {}\n // Do not autocomplete if cursor is after closing brace: {job=\"mysql\"}▯\n if (\n (node.firstChild === null || node.firstChild?.type.id === 0) &&\n !state.sliceDoc(node.from, pos).includes('}')\n ) {\n return {\n scope: { kind: 'LabelName' },\n from: pos,\n };\n }\n break;\n\n case Matchers: {\n // Matchers node contains all label matchers inside {}\n // Autocomplete after comma: { job=\"mysql\",▯ or { job=\"mysql\", ▯\n const text = state.sliceDoc(node.from, pos);\n if (text.endsWith(',') || text.endsWith(', ')) {\n return {\n scope: { kind: 'LabelName' },\n from: pos,\n };\n }\n break;\n }\n\n case Matcher:\n // Single matcher like job=\"mysql\"\n // Autocomplete when cursor is after a complete matcher: { job=\"mysql\" ▯\n if (node.parent?.type.id === Matchers) {\n return {\n scope: { kind: 'LabelName' },\n from: pos,\n };\n }\n break;\n\n case Identifier:\n // Identifier is a label name being typed\n // Autocomplete partial label names: { jo▯ or { job=\"mysql\", na▯\n if (node.parent?.type.id === Matcher) {\n return {\n scope: { kind: 'LabelName' },\n from: node.from,\n };\n }\n break;\n\n case Eq:\n case Neq:\n case Re:\n case Nre:\n // Operators for label matching: =, !=, =~, !~\n // Autocomplete label values right after operator: { job=▯ or { job!=▯\n if (node.parent?.type.id === Matcher) {\n const labelNode = node.parent.firstChild;\n if (labelNode?.type.id === Identifier) {\n const label = state.sliceDoc(labelNode.from, labelNode.to);\n return { scope: { kind: 'LabelValue', label }, from: pos };\n }\n }\n break;\n\n case StringType:\n // String value in a matcher: { job=\"▯\n // Do not autocomplete if cursor is after closing quotes: { job=\"\"▯\n if (node.parent?.type.id === Matcher && !/^\".*\"$/.test(state.sliceDoc(node.from, pos))) {\n const labelNode = node.parent.firstChild;\n if (labelNode?.type.id === Identifier) {\n const label = state.sliceDoc(labelNode.from, labelNode.to);\n return { scope: { kind: 'LabelValue', label }, from: node.from + 1 }; // +1 to skip opening quote\n }\n }\n break;\n\n case 0 /* error node */:\n // Error nodes represent incomplete or malformed syntax\n // Autocomplete incomplete value after operator: { job=mys▯ or { job=\"mys▯\n if (\n (node.prevSibling?.type.id === Eq ||\n node.prevSibling?.type.id === Neq ||\n node.prevSibling?.type.id === Re ||\n node.prevSibling?.type.id === Nre) &&\n node.parent?.type.id === Matcher\n ) {\n const labelNode = node.parent.firstChild;\n if (labelNode?.type.id === Identifier) {\n const label = state.sliceDoc(labelNode.from, labelNode.to);\n // Skip leading quote if present: { name=\"HT▯\n const from = quoteChars.includes(state.sliceDoc(node.from, node.from + 1)) ? node.from + 1 : node.from;\n return { scope: { kind: 'LabelValue', label }, from };\n }\n }\n\n // Autocomplete partial label name: { j▯ or { job=\"mysql\", n▯\n if (node.parent?.type.id === Selector || node.parent?.type.id === Matchers) {\n return {\n scope: { kind: 'LabelName' },\n from: node.from,\n };\n }\n break;\n }\n}\n\n/**\n * Retrieve completion options based on the identified completion scope.\n */\nasync function retrieveOptions(completionCfg: CompletionConfig, completion: CompletionScope): Promise<Completion[]> {\n switch (completion.kind) {\n case 'LabelName':\n return completeLabelName(completionCfg);\n\n case 'LabelValue':\n return completeLabelValue(completionCfg, completion.label);\n }\n}\n\nasync function completeLabelName(completionCfg: CompletionConfig): Promise<Completion[]> {\n if (!completionCfg.client) {\n return [];\n }\n\n const start = completionCfg.timeRange?.start\n ? toUnixSeconds(new Date(completionCfg.timeRange.start).getTime())\n : undefined;\n const end = completionCfg.timeRange?.end ? toUnixSeconds(new Date(completionCfg.timeRange.end).getTime()) : undefined;\n\n try {\n const response = await completionCfg.client.labels(start, end);\n if (response.status === 'success') {\n return response.data.map((label: string) => ({ label }));\n }\n return [];\n } catch (error) {\n console.error('Error fetching label names:', error);\n return [];\n }\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 backslashes and quotes\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 completeLabelValue(completionCfg: CompletionConfig, label: string): Promise<Completion[]> {\n if (!completionCfg.client) {\n return [];\n }\n\n const start = completionCfg.timeRange?.start\n ? toUnixSeconds(new Date(completionCfg.timeRange.start).getTime())\n : undefined;\n const end = completionCfg.timeRange?.end ? toUnixSeconds(new Date(completionCfg.timeRange.end).getTime()) : undefined;\n\n try {\n const response = await completionCfg.client.labelValues(label, start, end);\n if (response.status === 'success') {\n return response.data.map((value: string) => ({\n label: value ?? '',\n displayLabel: value ?? '(empty string)',\n apply: applyQuotedCompletion,\n }));\n }\n return [];\n } catch (error) {\n console.error(`Error fetching values for label ${label}:`, error);\n return [];\n }\n}\n"],"names":["insertCompletionText","syntaxTree","Selector","Matchers","Matcher","Identifier","Eq","Neq","Re","Nre","String","StringType","toUnixSeconds","quoteChars","defaultQuoteChar","complete","completionCfg","state","pos","completion","identifyCompletion","options","retrieveOptions","scope","from","to","tree","node","resolveInner","type","id","firstChild","sliceDoc","includes","kind","text","endsWith","parent","labelNode","label","test","prevSibling","completeLabelName","completeLabelValue","client","start","timeRange","Date","getTime","undefined","end","response","labels","status","data","map","error","console","escapeString","input","quoteChar","escaped","replaceAll","applyQuotedCompletion","view","insertText","dispatch","labelValues","value","displayLabel","apply"],"mappings":"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"}
@@ -1,5 +1,8 @@
1
1
  import { ReactElement } from 'react';
2
2
  import { ReactCodeMirrorProps } from '@uiw/react-codemirror';
3
- export type LogQLEditorProps = Omit<ReactCodeMirrorProps, 'theme' | 'extensions'>;
3
+ import { CompletionConfig } from './logql-extension';
4
+ export type LogQLEditorProps = Omit<ReactCodeMirrorProps, 'theme' | 'extensions'> & {
5
+ completionConfig?: CompletionConfig;
6
+ };
4
7
  export declare function LogQLEditor(props: LogQLEditorProps): ReactElement;
5
8
  //# sourceMappingURL=logql-editor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logql-editor.d.ts","sourceRoot":"","sources":["../../../src/components/logql-editor.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAW,MAAM,OAAO,CAAC;AAE9C,OAAmB,EAAc,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAGrF,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,YAAY,CAAC,CAAC;AAElF,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,YAAY,CAyCjE"}
1
+ {"version":3,"file":"logql-editor.d.ts","sourceRoot":"","sources":["../../../src/components/logql-editor.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAW,MAAM,OAAO,CAAC;AAE9C,OAAmB,EAAc,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACrF,OAAO,EAAkB,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErE,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,YAAY,CAAC,GAAG;IAClF,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC,CAAC;AAEF,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,YAAY,CA0CjE"}
@@ -1,3 +1,4 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
1
2
  // Copyright 2025 The Perses Authors
2
3
  // Licensed under the Apache License, Version 2.0 (the "License");
3
4
  // you may not use this file except in compliance with the License.
@@ -10,17 +11,19 @@
10
11
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
12
  // See the License for the specific language governing permissions and
12
13
  // limitations under the License.
13
- import { jsx as _jsx } from "react/jsx-runtime";
14
14
  import { useMemo } from 'react';
15
15
  import { useTheme } from '@mui/material';
16
16
  import CodeMirror, { EditorView } from '@uiw/react-codemirror';
17
17
  import { LogQLExtension } from './logql-extension';
18
18
  export function LogQLEditor(props) {
19
+ const { completionConfig, ...codemirrorProps } = props;
19
20
  const theme = useTheme();
20
21
  const isDarkMode = theme.palette.mode === 'dark';
21
22
  const logqlExtension = useMemo(()=>{
22
- return LogQLExtension();
23
- }, []);
23
+ return LogQLExtension(completionConfig);
24
+ }, [
25
+ completionConfig
26
+ ]);
24
27
  const codemirrorTheme = useMemo(()=>{
25
28
  const borderColor = theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)';
26
29
  return EditorView.theme({
@@ -40,7 +43,7 @@ export function LogQLEditor(props) {
40
43
  theme
41
44
  ]);
42
45
  return /*#__PURE__*/ _jsx(CodeMirror, {
43
- ...props,
46
+ ...codemirrorProps,
44
47
  theme: isDarkMode ? 'dark' : 'light',
45
48
  basicSetup: {
46
49
  lineNumbers: false,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/logql-editor.tsx"],"sourcesContent":["// Copyright 2025 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ReactElement, useMemo } from 'react';\nimport { useTheme } from '@mui/material';\nimport CodeMirror, { EditorView, ReactCodeMirrorProps } from '@uiw/react-codemirror';\nimport { LogQLExtension } from './logql-extension';\n\nexport type LogQLEditorProps = Omit<ReactCodeMirrorProps, 'theme' | 'extensions'>;\n\nexport function LogQLEditor(props: LogQLEditorProps): ReactElement {\n const theme = useTheme();\n const isDarkMode = theme.palette.mode === 'dark';\n\n const logqlExtension = useMemo(() => {\n return LogQLExtension();\n }, []);\n\n const codemirrorTheme = useMemo(() => {\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',\n },\n '.cm-content': {\n padding: '8px',\n },\n });\n }, [theme]);\n\n return (\n <CodeMirror\n {...props}\n theme={isDarkMode ? 'dark' : 'light'}\n basicSetup={{\n lineNumbers: false,\n highlightActiveLine: false,\n highlightActiveLineGutter: false,\n foldGutter: false,\n syntaxHighlighting: true,\n }}\n extensions={[EditorView.lineWrapping, logqlExtension, codemirrorTheme]}\n placeholder='Example: {job=\"my-service\"} |= \"error\"'\n />\n );\n}\n"],"names":["useMemo","useTheme","CodeMirror","EditorView","LogQLExtension","LogQLEditor","props","theme","isDarkMode","palette","mode","logqlExtension","codemirrorTheme","borderColor","backgroundColor","border","borderRadius","shape","outline","padding","basicSetup","lineNumbers","highlightActiveLine","highlightActiveLineGutter","foldGutter","syntaxHighlighting","extensions","lineWrapping","placeholder"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAAuBA,OAAO,QAAQ,QAAQ;AAC9C,SAASC,QAAQ,QAAQ,gBAAgB;AACzC,OAAOC,cAAcC,UAAU,QAA8B,wBAAwB;AACrF,SAASC,cAAc,QAAQ,oBAAoB;AAInD,OAAO,SAASC,YAAYC,KAAuB;IACjD,MAAMC,QAAQN;IACd,MAAMO,aAAaD,MAAME,OAAO,CAACC,IAAI,KAAK;IAE1C,MAAMC,iBAAiBX,QAAQ;QAC7B,OAAOI;IACT,GAAG,EAAE;IAEL,MAAMQ,kBAAkBZ,QAAQ;QAC9B,MAAMa,cAAcN,MAAME,OAAO,CAACC,IAAI,KAAK,UAAU,wBAAwB;QAE7E,OAAOP,WAAWI,KAAK,CAAC;YACtB,KAAK;gBACHO,iBAAiB;gBACjBC,QAAQ,CAAC,UAAU,EAAEF,aAAa;gBAClCG,cAAc,GAAGT,MAAMU,KAAK,CAACD,YAAY,CAAC,EAAE,CAAC;YAC/C;YACA,0BAA0B;gBACxBE,SAAS;YACX;YACA,eAAe;gBACbC,SAAS;YACX;QACF;IACF,GAAG;QAACZ;KAAM;IAEV,qBACE,KAACL;QACE,GAAGI,KAAK;QACTC,OAAOC,aAAa,SAAS;QAC7BY,YAAY;YACVC,aAAa;YACbC,qBAAqB;YACrBC,2BAA2B;YAC3BC,YAAY;YACZC,oBAAoB;QACtB;QACAC,YAAY;YAACvB,WAAWwB,YAAY;YAAEhB;YAAgBC;SAAgB;QACtEgB,aAAY;;AAGlB"}
1
+ {"version":3,"sources":["../../../src/components/logql-editor.tsx"],"sourcesContent":["// Copyright 2025 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ReactElement, useMemo } from 'react';\nimport { useTheme } from '@mui/material';\nimport CodeMirror, { EditorView, ReactCodeMirrorProps } from '@uiw/react-codemirror';\nimport { LogQLExtension, CompletionConfig } from './logql-extension';\n\nexport type LogQLEditorProps = Omit<ReactCodeMirrorProps, 'theme' | 'extensions'> & {\n completionConfig?: CompletionConfig;\n};\n\nexport function LogQLEditor(props: LogQLEditorProps): ReactElement {\n const { completionConfig, ...codemirrorProps } = props;\n const theme = useTheme();\n const isDarkMode = theme.palette.mode === 'dark';\n\n const logqlExtension = useMemo(() => {\n return LogQLExtension(completionConfig);\n }, [completionConfig]);\n\n const codemirrorTheme = useMemo(() => {\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',\n },\n '.cm-content': {\n padding: '8px',\n },\n });\n }, [theme]);\n\n return (\n <CodeMirror\n {...codemirrorProps}\n theme={isDarkMode ? 'dark' : 'light'}\n basicSetup={{\n lineNumbers: false,\n highlightActiveLine: false,\n highlightActiveLineGutter: false,\n foldGutter: false,\n syntaxHighlighting: true,\n }}\n extensions={[EditorView.lineWrapping, logqlExtension, codemirrorTheme]}\n placeholder='Example: {job=\"my-service\"} |= \"error\"'\n />\n );\n}\n"],"names":["useMemo","useTheme","CodeMirror","EditorView","LogQLExtension","LogQLEditor","props","completionConfig","codemirrorProps","theme","isDarkMode","palette","mode","logqlExtension","codemirrorTheme","borderColor","backgroundColor","border","borderRadius","shape","outline","padding","basicSetup","lineNumbers","highlightActiveLine","highlightActiveLineGutter","foldGutter","syntaxHighlighting","extensions","lineWrapping","placeholder"],"mappings":";AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAAuBA,OAAO,QAAQ,QAAQ;AAC9C,SAASC,QAAQ,QAAQ,gBAAgB;AACzC,OAAOC,cAAcC,UAAU,QAA8B,wBAAwB;AACrF,SAASC,cAAc,QAA0B,oBAAoB;AAMrE,OAAO,SAASC,YAAYC,KAAuB;IACjD,MAAM,EAAEC,gBAAgB,EAAE,GAAGC,iBAAiB,GAAGF;IACjD,MAAMG,QAAQR;IACd,MAAMS,aAAaD,MAAME,OAAO,CAACC,IAAI,KAAK;IAE1C,MAAMC,iBAAiBb,QAAQ;QAC7B,OAAOI,eAAeG;IACxB,GAAG;QAACA;KAAiB;IAErB,MAAMO,kBAAkBd,QAAQ;QAC9B,MAAMe,cAAcN,MAAME,OAAO,CAACC,IAAI,KAAK,UAAU,wBAAwB;QAE7E,OAAOT,WAAWM,KAAK,CAAC;YACtB,KAAK;gBACHO,iBAAiB;gBACjBC,QAAQ,CAAC,UAAU,EAAEF,aAAa;gBAClCG,cAAc,GAAGT,MAAMU,KAAK,CAACD,YAAY,CAAC,EAAE,CAAC;YAC/C;YACA,0BAA0B;gBACxBE,SAAS;YACX;YACA,eAAe;gBACbC,SAAS;YACX;QACF;IACF,GAAG;QAACZ;KAAM;IAEV,qBACE,KAACP;QACE,GAAGM,eAAe;QACnBC,OAAOC,aAAa,SAAS;QAC7BY,YAAY;YACVC,aAAa;YACbC,qBAAqB;YACrBC,2BAA2B;YAC3BC,YAAY;YACZC,oBAAoB;QACtB;QACAC,YAAY;YAACzB,WAAW0B,YAAY;YAAEhB;YAAgBC;SAAgB;QACtEgB,aAAY;;AAGlB"}