@perses-dev/loki-plugin 0.4.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.
- package/__mf/js/Loki.b64c7408.js +6 -0
- package/__mf/js/async/1238.71fd7843.js +1 -0
- package/__mf/js/async/1490.0d8dcc42.js +22 -0
- package/__mf/js/async/1501.eefd56b9.js +1 -0
- package/__mf/js/async/1616.60c9a082.js +1 -0
- package/__mf/js/async/1728.21a8f690.js +1 -0
- package/__mf/js/async/1811.a291a38b.js +28 -0
- package/__mf/js/async/1825.5005b3af.js +1 -0
- package/__mf/js/async/1969.53d223ca.js +1 -0
- package/__mf/js/async/2043.eb7e1c61.js +2 -0
- package/__mf/js/async/2386.a3cfef97.js +2 -0
- package/__mf/js/async/3059.cb101ca2.js +1 -0
- package/__mf/js/async/3181.d2b90b95.js +2 -0
- package/__mf/js/async/3849.85df5535.js +7 -0
- package/__mf/js/async/392.c0f9d49a.js +2 -0
- package/__mf/js/async/{1964.7b2e7223.js → 4121.328a1e93.js} +2 -2
- package/__mf/js/async/4466.21ddc88c.js +74 -0
- package/__mf/js/async/{2651.ef335482.js → 5002.29685f8e.js} +1 -1
- package/__mf/js/async/5071.a03a64fd.js +1 -0
- package/__mf/js/async/5440.3fedd5ea.js +2 -0
- package/__mf/js/async/5501.01af8b43.js +2 -0
- package/__mf/js/async/{5214.fee648bb.js → 5587.55dbc663.js} +1 -1
- package/__mf/js/async/6100.e2898f9c.js +1 -0
- package/__mf/js/async/6274.293b47c4.js +2 -0
- package/__mf/js/async/6283.78af4bc8.js +2 -0
- package/__mf/js/async/6498.903f2a94.js +2 -0
- package/__mf/js/async/7177.b50a1c64.js +1 -0
- package/__mf/js/async/7192.4dea1fd0.js +1 -0
- package/__mf/js/async/7370.0ddd349a.js +2 -0
- package/__mf/js/async/7968.ec040694.js +1 -0
- package/__mf/js/async/7978.38078276.js +1 -0
- package/__mf/js/async/8035.8dab4893.js +38 -0
- package/__mf/js/async/8356.5635696c.js +1 -0
- package/__mf/js/async/8470.c67049a2.js +2 -0
- package/__mf/js/async/8482.07caae1a.js +1 -0
- package/__mf/js/async/873.02aa55af.js +1 -0
- package/__mf/js/async/8988.1c565f12.js +1 -0
- package/__mf/js/async/9071.ed72bdac.js +2 -0
- package/__mf/js/async/9235.f2e0e95c.js +1 -0
- package/__mf/js/async/9389.a8ea42a0.js +2 -0
- package/__mf/js/async/941.0bce16fe.js +2 -0
- package/__mf/js/async/9588.2d82f477.js +1 -0
- package/__mf/js/async/9754.5d7b21c2.js +10 -0
- package/__mf/js/async/9836.de786d07.js +1 -0
- package/__mf/js/async/__federation_expose_LokiDatasource.3da46ee2.js +2 -0
- package/__mf/js/async/__federation_expose_LokiLogQuery.c1be0273.js +1 -0
- package/__mf/js/async/__federation_expose_LokiTimeSeriesQuery.cf876f4b.js +1 -0
- package/__mf/js/main.de30f7e6.js +6 -0
- package/lib/bootstrap.js +3 -3
- package/lib/bootstrap.js.map +1 -1
- package/lib/cjs/bootstrap.js +1 -1
- package/lib/cjs/components/complete.js +258 -0
- package/lib/cjs/components/logql-editor.js +6 -3
- package/lib/cjs/components/logql-extension.js +15 -1
- package/lib/cjs/model/index.js +1 -0
- package/lib/cjs/model/loki-client.js +10 -10
- package/lib/cjs/model/loki-selectors.js +5 -5
- package/lib/cjs/queries/constants.js +3 -3
- package/lib/cjs/queries/loki-log-query/LokiLogQueryEditor.js +16 -1
- package/lib/components/complete.d.ts +37 -0
- package/lib/components/complete.d.ts.map +1 -0
- package/lib/components/complete.js +249 -0
- package/lib/components/complete.js.map +1 -0
- package/lib/components/logql-editor.d.ts +4 -1
- package/lib/components/logql-editor.d.ts.map +1 -1
- package/lib/components/logql-editor.js +7 -4
- package/lib/components/logql-editor.js.map +1 -1
- package/lib/components/logql-extension.d.ts +9 -1
- package/lib/components/logql-extension.d.ts.map +1 -1
- package/lib/components/logql-extension.js +15 -1
- package/lib/components/logql-extension.js.map +1 -1
- package/lib/datasources/loki-datasource/LokiDatasourceEditor.js +1 -1
- package/lib/datasources/loki-datasource/LokiDatasourceEditor.js.map +1 -1
- package/lib/model/index.d.ts +1 -0
- package/lib/model/index.d.ts.map +1 -1
- package/lib/model/index.js +1 -0
- package/lib/model/index.js.map +1 -1
- package/lib/queries/loki-log-query/LokiLogQueryEditor.d.ts.map +1 -1
- package/lib/queries/loki-log-query/LokiLogQueryEditor.js +19 -4
- package/lib/queries/loki-log-query/LokiLogQueryEditor.js.map +1 -1
- package/lib/queries/loki-log-query/get-loki-log-data.js.map +1 -1
- package/lib/queries/loki-time-series-query/LokiTimeSeriesQueryEditor.js +1 -1
- package/lib/queries/loki-time-series-query/LokiTimeSeriesQueryEditor.js.map +1 -1
- package/lib/queries/loki-time-series-query/get-loki-time-series-data.d.ts +1 -4
- package/lib/queries/loki-time-series-query/get-loki-time-series-data.d.ts.map +1 -1
- package/lib/queries/loki-time-series-query/get-loki-time-series-data.js.map +1 -1
- package/mf-manifest.json +107 -102
- package/mf-stats.json +107 -102
- package/package.json +7 -6
- package/__mf/js/Loki.c48c56a7.js +0 -5
- package/__mf/js/async/1360.2348e2a7.js +0 -10
- package/__mf/js/async/1398.ca579c40.js +0 -2
- package/__mf/js/async/1540.6b797827.js +0 -74
- package/__mf/js/async/1580.c7d3c3f1.js +0 -2
- package/__mf/js/async/2226.a056d1a3.js +0 -1
- package/__mf/js/async/2292.35c2eeec.js +0 -2
- package/__mf/js/async/2652.7b7038d2.js +0 -28
- package/__mf/js/async/282.6c4c5a94.js +0 -1
- package/__mf/js/async/3224.b1170acc.js +0 -1
- package/__mf/js/async/3431.2270637c.js +0 -1
- package/__mf/js/async/3863.16343b76.js +0 -2
- package/__mf/js/async/3960.6091bb00.js +0 -2
- package/__mf/js/async/3980.08ab4aef.js +0 -2
- package/__mf/js/async/4075.19dee570.js +0 -1
- package/__mf/js/async/4238.155e3b8a.js +0 -1
- package/__mf/js/async/4269.b4d0f49d.js +0 -2
- package/__mf/js/async/4310.6d2d2ce3.js +0 -7
- package/__mf/js/async/4421.28cc8e2d.js +0 -1
- package/__mf/js/async/4557.fd670526.js +0 -2
- package/__mf/js/async/4676.d4c41b7a.js +0 -22
- package/__mf/js/async/5409.ff95cf63.js +0 -1
- package/__mf/js/async/5780.d837c3cd.js +0 -1
- package/__mf/js/async/5981.a46c5157.js +0 -2
- package/__mf/js/async/6134.f7ee513c.js +0 -38
- package/__mf/js/async/6292.9997ca36.js +0 -1
- package/__mf/js/async/6329.9c3a3698.js +0 -2
- package/__mf/js/async/6333.01fb6457.js +0 -2
- package/__mf/js/async/6377.9f308c7f.js +0 -2
- package/__mf/js/async/6770.ba5a38f3.js +0 -1
- package/__mf/js/async/694.c25a1f84.js +0 -1
- package/__mf/js/async/7376.0459aaf7.js +0 -1
- package/__mf/js/async/738.a16c93b6.js +0 -1
- package/__mf/js/async/7740.6f193fac.js +0 -1
- package/__mf/js/async/7797.822237c9.js +0 -1
- package/__mf/js/async/8216.d9cc6234.js +0 -1
- package/__mf/js/async/8488.5b4b7170.js +0 -1
- package/__mf/js/async/8537.dc791586.js +0 -1
- package/__mf/js/async/9173.75bbe78a.js +0 -2
- package/__mf/js/async/9554.728cf7b9.js +0 -2
- package/__mf/js/async/__federation_expose_LokiDatasource.3ce6abca.js +0 -2
- package/__mf/js/async/__federation_expose_LokiLogQuery.c446c7ff.js +0 -1
- package/__mf/js/async/__federation_expose_LokiTimeSeriesQuery.eda99bf8.js +0 -1
- package/__mf/js/main.ccf461ea.js +0 -5
- /package/__mf/css/async/{1580.d3010b86.css → 3061.d3010b86.css} +0 -0
- /package/__mf/css/async/{2341.d3010b86.css → 5442.d3010b86.css} +0 -0
- /package/__mf/css/async/{6759.d3010b86.css → 7370.d3010b86.css} +0 -0
- /package/__mf/js/async/{4676.d4c41b7a.js.LICENSE.txt → 1490.0d8dcc42.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{2292.35c2eeec.js.LICENSE.txt → 2043.eb7e1c61.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{1398.ca579c40.js.LICENSE.txt → 2386.a3cfef97.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{1580.c7d3c3f1.js.LICENSE.txt → 3181.d2b90b95.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{4310.6d2d2ce3.js.LICENSE.txt → 3849.85df5535.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{5981.a46c5157.js.LICENSE.txt → 392.c0f9d49a.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{1964.7b2e7223.js.LICENSE.txt → 4121.328a1e93.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{6377.9f308c7f.js.LICENSE.txt → 5440.3fedd5ea.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{4557.fd670526.js.LICENSE.txt → 5501.01af8b43.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{3960.6091bb00.js.LICENSE.txt → 6274.293b47c4.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{3980.08ab4aef.js.LICENSE.txt → 6283.78af4bc8.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{9554.728cf7b9.js.LICENSE.txt → 6498.903f2a94.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{3863.16343b76.js.LICENSE.txt → 7370.0ddd349a.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{9173.75bbe78a.js.LICENSE.txt → 8470.c67049a2.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{4269.b4d0f49d.js.LICENSE.txt → 9071.ed72bdac.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{6329.9c3a3698.js.LICENSE.txt → 9389.a8ea42a0.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{6333.01fb6457.js.LICENSE.txt → 941.0bce16fe.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{1360.2348e2a7.js.LICENSE.txt → 9754.5d7b21c2.js.LICENSE.txt} +0 -0
- /package/__mf/js/async/{__federation_expose_LokiDatasource.3ce6abca.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
|
|
20
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
23
|
_export(exports, {
|
|
24
|
-
indexStats
|
|
24
|
+
get indexStats () {
|
|
25
25
|
return indexStats;
|
|
26
26
|
},
|
|
27
|
-
labelValues
|
|
27
|
+
get labelValues () {
|
|
28
28
|
return labelValues;
|
|
29
29
|
},
|
|
30
|
-
labels
|
|
30
|
+
get labels () {
|
|
31
31
|
return labels;
|
|
32
32
|
},
|
|
33
|
-
query
|
|
33
|
+
get query () {
|
|
34
34
|
return query;
|
|
35
35
|
},
|
|
36
|
-
queryRange
|
|
36
|
+
get queryRange () {
|
|
37
37
|
return queryRange;
|
|
38
38
|
},
|
|
39
|
-
series
|
|
39
|
+
get series () {
|
|
40
40
|
return series;
|
|
41
41
|
},
|
|
42
|
-
toUnixSeconds
|
|
42
|
+
get toUnixSeconds () {
|
|
43
43
|
return toUnixSeconds;
|
|
44
44
|
},
|
|
45
|
-
volume
|
|
45
|
+
get volume () {
|
|
46
46
|
return volume;
|
|
47
47
|
},
|
|
48
|
-
volumeRange
|
|
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
|
|
20
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
23
|
_export(exports, {
|
|
24
|
-
DEFAULT_LOKI
|
|
24
|
+
get DEFAULT_LOKI () {
|
|
25
25
|
return DEFAULT_LOKI;
|
|
26
26
|
},
|
|
27
|
-
LOKI_DATASOURCE_KIND
|
|
27
|
+
get LOKI_DATASOURCE_KIND () {
|
|
28
28
|
return LOKI_DATASOURCE_KIND;
|
|
29
29
|
},
|
|
30
|
-
isDefaultLokiSelector
|
|
30
|
+
get isDefaultLokiSelector () {
|
|
31
31
|
return isDefaultLokiSelector;
|
|
32
32
|
},
|
|
33
|
-
isLokiDatasourceSelector
|
|
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
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
_export(exports, {
|
|
12
|
-
DATASOURCE_KIND
|
|
12
|
+
get DATASOURCE_KIND () {
|
|
13
13
|
return DATASOURCE_KIND;
|
|
14
14
|
},
|
|
15
|
-
DEFAULT_DATASOURCE
|
|
15
|
+
get DEFAULT_DATASOURCE () {
|
|
16
16
|
return DEFAULT_DATASOURCE;
|
|
17
17
|
}
|
|
18
18
|
});
|
|
@@ -36,6 +36,20 @@ function LokiLogQueryEditor(props) {
|
|
|
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)=>{
|
|
@@ -104,7 +118,8 @@ function LokiLogQueryEditor(props) {
|
|
|
104
118
|
handleQueryExecute(query);
|
|
105
119
|
}
|
|
106
120
|
},
|
|
107
|
-
placeholder: 'Enter LogQL query (e.g. {job="mysql"} |= "error")'
|
|
121
|
+
placeholder: 'Enter LogQL query (e.g. {job="mysql"} |= "error")',
|
|
122
|
+
completionConfig: completionConfig
|
|
108
123
|
})
|
|
109
124
|
]
|
|
110
125
|
}),
|
|
@@ -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
|
-
|
|
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;
|
|
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
|
-
...
|
|
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'
|
|
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"}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { LRLanguage } from '@codemirror/language';
|
|
2
2
|
import { Extension } from '@uiw/react-codemirror';
|
|
3
|
-
|
|
3
|
+
import { AbsoluteTimeRange } from '@perses-dev/core';
|
|
4
|
+
import { LokiClient } from '../model';
|
|
5
|
+
export interface CompletionConfig {
|
|
6
|
+
/** a LokiClient instance, can be created with LokiDatasource.createClient() */
|
|
7
|
+
client?: LokiClient;
|
|
8
|
+
/** search for label values in a given time range */
|
|
9
|
+
timeRange?: AbsoluteTimeRange;
|
|
10
|
+
}
|
|
11
|
+
export declare function LogQLExtension(completionCfg?: CompletionConfig): Array<LRLanguage | Extension>;
|
|
4
12
|
//# sourceMappingURL=logql-extension.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logql-extension.d.ts","sourceRoot":"","sources":["../../../src/components/logql-extension.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"logql-extension.d.ts","sourceRoot":"","sources":["../../../src/components/logql-extension.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGlD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAgBtC,MAAM,WAAW,gBAAgB;IAC/B,+EAA+E;IAC/E,MAAM,CAAC,EAAE,UAAU,CAAC;IAEpB,oDAAoD;IACpD,SAAS,CAAC,EAAE,iBAAiB,CAAC;CAC/B;AAED,wBAAgB,cAAc,CAAC,aAAa,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAC,UAAU,GAAG,SAAS,CAAC,CAgB9F"}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import { LRLanguage } from '@codemirror/language';
|
|
14
14
|
import { parser } from '@grafana/lezer-logql';
|
|
15
15
|
import { logqlHighlight } from './logql-highlight';
|
|
16
|
+
import { complete } from './complete';
|
|
16
17
|
function logqlLanguage() {
|
|
17
18
|
return LRLanguage.define({
|
|
18
19
|
parser: parser.configure({
|
|
@@ -37,8 +38,21 @@ function logqlLanguage() {
|
|
|
37
38
|
}
|
|
38
39
|
});
|
|
39
40
|
}
|
|
40
|
-
export function LogQLExtension() {
|
|
41
|
+
export function LogQLExtension(completionCfg) {
|
|
41
42
|
const language = logqlLanguage();
|
|
43
|
+
// Only add autocomplete if config is provided
|
|
44
|
+
if (completionCfg) {
|
|
45
|
+
const completion = language.data.of({
|
|
46
|
+
autocomplete: (ctx)=>complete(completionCfg, ctx).catch((e)=>{
|
|
47
|
+
console.error('error during LogQL auto-complete', e);
|
|
48
|
+
return null;
|
|
49
|
+
})
|
|
50
|
+
});
|
|
51
|
+
return [
|
|
52
|
+
language,
|
|
53
|
+
completion
|
|
54
|
+
];
|
|
55
|
+
}
|
|
42
56
|
return [
|
|
43
57
|
language
|
|
44
58
|
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/logql-extension.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 { LRLanguage } from '@codemirror/language';\nimport { parser } from '@grafana/lezer-logql';\nimport { Extension } from '@uiw/react-codemirror';\nimport { logqlHighlight } from './logql-highlight';\n\nfunction logqlLanguage(): LRLanguage {\n return LRLanguage.define({\n parser: parser.configure({\n props: [logqlHighlight],\n }),\n languageData: {\n closeBrackets: { brackets: ['(', '[', '{', \"'\", '\"', '`'] },\n commentTokens: { line: '#' },\n },\n });\n}\n\nexport function LogQLExtension(): Array<LRLanguage | Extension> {\n const language = logqlLanguage();\n return [language];\n}\n"],"names":["LRLanguage","parser","logqlHighlight","logqlLanguage","define","configure","props","languageData","closeBrackets","brackets","commentTokens","line","LogQLExtension","language"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,UAAU,QAAQ,uBAAuB;AAClD,SAASC,MAAM,QAAQ,uBAAuB;
|
|
1
|
+
{"version":3,"sources":["../../../src/components/logql-extension.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 { LRLanguage } from '@codemirror/language';\nimport { parser } from '@grafana/lezer-logql';\nimport { CompletionContext } from '@codemirror/autocomplete';\nimport { Extension } from '@uiw/react-codemirror';\nimport { AbsoluteTimeRange } from '@perses-dev/core';\nimport { LokiClient } from '../model';\nimport { logqlHighlight } from './logql-highlight';\nimport { complete } from './complete';\n\nfunction logqlLanguage(): LRLanguage {\n return LRLanguage.define({\n parser: parser.configure({\n props: [logqlHighlight],\n }),\n languageData: {\n closeBrackets: { brackets: ['(', '[', '{', \"'\", '\"', '`'] },\n commentTokens: { line: '#' },\n },\n });\n}\n\nexport interface CompletionConfig {\n /** a LokiClient instance, can be created with LokiDatasource.createClient() */\n client?: LokiClient;\n\n /** search for label values in a given time range */\n timeRange?: AbsoluteTimeRange;\n}\n\nexport function LogQLExtension(completionCfg?: CompletionConfig): Array<LRLanguage | Extension> {\n const language = logqlLanguage();\n\n // Only add autocomplete if config is provided\n if (completionCfg) {\n const completion = language.data.of({\n autocomplete: (ctx: CompletionContext) =>\n complete(completionCfg, ctx).catch((e) => {\n console.error('error during LogQL auto-complete', e);\n return null;\n }),\n });\n return [language, completion];\n }\n\n return [language];\n}\n"],"names":["LRLanguage","parser","logqlHighlight","complete","logqlLanguage","define","configure","props","languageData","closeBrackets","brackets","commentTokens","line","LogQLExtension","completionCfg","language","completion","data","of","autocomplete","ctx","catch","e","console","error"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,UAAU,QAAQ,uBAAuB;AAClD,SAASC,MAAM,QAAQ,uBAAuB;AAK9C,SAASC,cAAc,QAAQ,oBAAoB;AACnD,SAASC,QAAQ,QAAQ,aAAa;AAEtC,SAASC;IACP,OAAOJ,WAAWK,MAAM,CAAC;QACvBJ,QAAQA,OAAOK,SAAS,CAAC;YACvBC,OAAO;gBAACL;aAAe;QACzB;QACAM,cAAc;YACZC,eAAe;gBAAEC,UAAU;oBAAC;oBAAK;oBAAK;oBAAK;oBAAK;oBAAK;iBAAI;YAAC;YAC1DC,eAAe;gBAAEC,MAAM;YAAI;QAC7B;IACF;AACF;AAUA,OAAO,SAASC,eAAeC,aAAgC;IAC7D,MAAMC,WAAWX;IAEjB,8CAA8C;IAC9C,IAAIU,eAAe;QACjB,MAAME,aAAaD,SAASE,IAAI,CAACC,EAAE,CAAC;YAClCC,cAAc,CAACC,MACbjB,SAASW,eAAeM,KAAKC,KAAK,CAAC,CAACC;oBAClCC,QAAQC,KAAK,CAAC,oCAAoCF;oBAClD,OAAO;gBACT;QACJ;QACA,OAAO;YAACP;YAAUC;SAAW;IAC/B;IAEA,OAAO;QAACD;KAAS;AACnB"}
|
|
@@ -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,7 +11,6 @@
|
|
|
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 { HTTPSettingsEditor } from '@perses-dev/plugin-system';
|
|
15
15
|
export function LokiDatasourceEditor(props) {
|
|
16
16
|
const { value, onChange, isReadonly } = props;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/datasources/loki-datasource/LokiDatasourceEditor.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 { HTTPSettingsEditor } from '@perses-dev/plugin-system';\nimport { ReactElement } from 'react';\nimport { LokiDatasourceSpec } from './loki-datasource-types';\n\nexport interface LokiDatasourceEditorProps {\n value: LokiDatasourceSpec;\n onChange: (next: LokiDatasourceSpec) => void;\n isReadonly?: boolean;\n}\n\nexport function LokiDatasourceEditor(props: LokiDatasourceEditorProps): ReactElement {\n const { value, onChange, isReadonly } = props;\n\n const initialSpecDirect: LokiDatasourceSpec = {\n directUrl: '',\n };\n\n const initialSpecProxy: LokiDatasourceSpec = {\n proxy: {\n kind: 'HTTPProxy',\n spec: {\n allowedEndpoints: [\n {\n endpointPattern: '/loki/api/v1/query',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/query_range',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/labels',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/label/([a-zA-Z0-9_-]+)/values',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/series',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/index/volume',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/index/volume_range',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/index/stats',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/tail',\n method: 'GET',\n },\n ],\n url: '',\n },\n },\n };\n\n return (\n <HTTPSettingsEditor\n value={value}\n onChange={onChange}\n isReadonly={isReadonly}\n initialSpecDirect={initialSpecDirect}\n initialSpecProxy={initialSpecProxy}\n />\n );\n}\n"],"names":["HTTPSettingsEditor","LokiDatasourceEditor","props","value","onChange","isReadonly","initialSpecDirect","directUrl","initialSpecProxy","proxy","kind","spec","allowedEndpoints","endpointPattern","method","url"],"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
|
|
1
|
+
{"version":3,"sources":["../../../../src/datasources/loki-datasource/LokiDatasourceEditor.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 { HTTPSettingsEditor } from '@perses-dev/plugin-system';\nimport { ReactElement } from 'react';\nimport { LokiDatasourceSpec } from './loki-datasource-types';\n\nexport interface LokiDatasourceEditorProps {\n value: LokiDatasourceSpec;\n onChange: (next: LokiDatasourceSpec) => void;\n isReadonly?: boolean;\n}\n\nexport function LokiDatasourceEditor(props: LokiDatasourceEditorProps): ReactElement {\n const { value, onChange, isReadonly } = props;\n\n const initialSpecDirect: LokiDatasourceSpec = {\n directUrl: '',\n };\n\n const initialSpecProxy: LokiDatasourceSpec = {\n proxy: {\n kind: 'HTTPProxy',\n spec: {\n allowedEndpoints: [\n {\n endpointPattern: '/loki/api/v1/query',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/query_range',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/labels',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/label/([a-zA-Z0-9_-]+)/values',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/series',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/index/volume',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/index/volume_range',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/index/stats',\n method: 'GET',\n },\n {\n endpointPattern: '/loki/api/v1/tail',\n method: 'GET',\n },\n ],\n url: '',\n },\n },\n };\n\n return (\n <HTTPSettingsEditor\n value={value}\n onChange={onChange}\n isReadonly={isReadonly}\n initialSpecDirect={initialSpecDirect}\n initialSpecProxy={initialSpecProxy}\n />\n );\n}\n"],"names":["HTTPSettingsEditor","LokiDatasourceEditor","props","value","onChange","isReadonly","initialSpecDirect","directUrl","initialSpecProxy","proxy","kind","spec","allowedEndpoints","endpointPattern","method","url"],"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,kBAAkB,QAAQ,4BAA4B;AAU/D,OAAO,SAASC,qBAAqBC,KAAgC;IACnE,MAAM,EAAEC,KAAK,EAAEC,QAAQ,EAAEC,UAAU,EAAE,GAAGH;IAExC,MAAMI,oBAAwC;QAC5CC,WAAW;IACb;IAEA,MAAMC,mBAAuC;QAC3CC,OAAO;YACLC,MAAM;YACNC,MAAM;gBACJC,kBAAkB;oBAChB;wBACEC,iBAAiB;wBACjBC,QAAQ;oBACV;oBACA;wBACED,iBAAiB;wBACjBC,QAAQ;oBACV;oBACA;wBACED,iBAAiB;wBACjBC,QAAQ;oBACV;oBACA;wBACED,iBAAiB;wBACjBC,QAAQ;oBACV;oBACA;wBACED,iBAAiB;wBACjBC,QAAQ;oBACV;oBACA;wBACED,iBAAiB;wBACjBC,QAAQ;oBACV;oBACA;wBACED,iBAAiB;wBACjBC,QAAQ;oBACV;oBACA;wBACED,iBAAiB;wBACjBC,QAAQ;oBACV;oBACA;wBACED,iBAAiB;wBACjBC,QAAQ;oBACV;iBACD;gBACDC,KAAK;YACP;QACF;IACF;IAEA,qBACE,KAACf;QACCG,OAAOA;QACPC,UAAUA;QACVC,YAAYA;QACZC,mBAAmBA;QACnBE,kBAAkBA;;AAGxB"}
|