1- import Editor from "@monaco-editor/react" ;
1+ import Editor , { type OnMount } from "@monaco-editor/react" ;
22import {
33 Card ,
44 CardAction ,
@@ -36,6 +36,7 @@ import {
3636} from "@/components/date-time-range" ;
3737import { parseDate } from "chrono-node" ;
3838import { languageConfiguration , monarchlanguage } from '@grafana/monaco-logql' ;
39+ import { editor } from "monaco-editor" ;
3940
4041export interface LogQLEditorProps {
4142 readonly onRun ?: ( logql : string , start ?: number , end ?: number ) => void ;
@@ -57,26 +58,26 @@ export function LogQLEditor({
5758 className,
5859} : LogQLEditorProps ) {
5960 const [ value , setValue ] = useState < string > ( DEFAULT_EXAMPLE_ID ) ;
60- const [ logql , setLogql ] = useState ( "" ) ;
61+ const [ logql , setLogql ] = useState < undefined | string > ( "" ) ;
6162 const [ timeRange , setTimeRange ] = useState < DateTimeRangeValue > ( {
6263 from : "1h ago" ,
6364 to : "now" ,
6465 } ) ;
6566 const dateStart = useMemo (
6667 ( ) => ( timeRange ?. from ? parseDate ( timeRange ?. from ) ?. valueOf ( ) : undefined ) ,
67- [ timeRange . from ] ,
68+ [ timeRange ? .from ] ,
6869 ) ;
6970 const dateEnd = useMemo (
7071 ( ) => ( timeRange ?. to ? parseDate ( timeRange ?. to ) ?. valueOf ( ) : undefined ) ,
71- [ timeRange . to ] ,
72+ [ timeRange ? .to ] ,
7273 ) ;
7374
7475 const runQuery = useCallback (
75- ( text ?: string ) => {
76+ ( text ?: any ) => {
7677 if ( ! onRun || isLoading ) {
7778 return ;
7879 }
79- const current = typeof text === "string" ? text : logql ;
80+ const current = typeof text === "string" ? text : ( logql ?? '' ) ;
8081 onRun ( current , dateStart , dateEnd ) ;
8182 } ,
8283 [ onRun , isLoading , logql , dateStart , dateEnd ] ,
@@ -89,6 +90,67 @@ export function LogQLEditor({
8990 }
9091 } , [ value ] ) ;
9192
93+ const initEditorHandler : OnMount = useCallback ( ( editorInstance , monaco ) => {
94+ monaco . languages . register ( { id : "logql" } ) ;
95+ monaco . languages . setMonarchTokensProvider ( "logql" , monarchlanguage ) ;
96+ monaco . languages . setLanguageConfiguration ( "logql" , languageConfiguration ) ;
97+ monaco . languages . registerCompletionItemProvider ( "logql" , {
98+ provideCompletionItems : ( ) => {
99+ const suggestions = COMPLETIONS . map ( ( label ) => ( {
100+ label,
101+ kind : monaco . languages . CompletionItemKind . Keyword ,
102+ insertText : label ,
103+ range : {
104+ startLineNumber : 1 ,
105+ endLineNumber : 1 ,
106+ startColumn : 1 ,
107+ endColumn : 1 ,
108+ } ,
109+ detail : "LogQL snippet" ,
110+ documentation : "LogQL snippet" ,
111+ sortText : label ,
112+ filterText : label ,
113+ } ) ) ;
114+ return { suggestions } ;
115+ } ,
116+ } ) ;
117+
118+ const executeFromEditor = ( ) =>
119+ runQuery ( editorInstance . getValue ( ) ?? "" ) ;
120+ const keybindings = [
121+ monaco . KeyMod . CtrlCmd | monaco . KeyCode . Enter ,
122+ monaco . KeyMod . Shift | monaco . KeyCode . Enter ,
123+ monaco . KeyMod . WinCtrl | monaco . KeyCode . Enter ,
124+ monaco . KeyMod . CtrlCmd |
125+ monaco . KeyMod . Shift |
126+ monaco . KeyCode . Enter ,
127+ ] ;
128+ keybindings . forEach ( ( binding ) => {
129+ editorInstance . addCommand ( binding , executeFromEditor ) ;
130+ } ) ;
131+ } , [ ] )
132+
133+ const editorOptions = useMemo ( ( ) => ( {
134+ readOnly : isLoading ,
135+ minimap : { enabled : false } ,
136+ fontSize : 12 ,
137+ lineNumbers : "off" ,
138+ scrollBeyondLastLine : false ,
139+ selectionHighlight : ! isLoading ,
140+ } as editor . IStandaloneEditorConstructionOptions ) , [ isLoading ] )
141+
142+ const examples = useMemo ( ( ) => (
143+ EXAMPLES . map ( ( example ) => (
144+ < SelectItem
145+ value = { example . id }
146+ key = { example . id }
147+ className = { "cursor-pointer" }
148+ >
149+ Example: { example . title }
150+ </ SelectItem >
151+ ) )
152+ ) , [ ] )
153+
92154 return (
93155 < Card className = { cn ( "w-full h-full py-4 border-none shadow-none drop-shadow-none" , className ) } >
94156 < CardHeader
@@ -101,15 +163,7 @@ export function LogQLEditor({
101163 < SelectValue placeholder = "Select example" />
102164 </ SelectTrigger >
103165 < SelectContent >
104- { EXAMPLES . map ( ( example ) => (
105- < SelectItem
106- value = { example . id }
107- key = { example . id }
108- className = { "cursor-pointer" }
109- >
110- Example: { example . title }
111- </ SelectItem >
112- ) ) }
166+ { examples }
113167 </ SelectContent >
114168 </ Select >
115169 { execMode === 'query' &&
@@ -118,7 +172,7 @@ export function LogQLEditor({
118172 < Button
119173 disabled = { isLoading }
120174 className = { "cursor-pointer max-sm:w-full" }
121- onClick = { ( ) => runQuery ( ) }
175+ onClick = { runQuery }
122176 >
123177 { isLoading ? < Spinner /> : < PlayIcon /> }
124178 Execute
@@ -137,55 +191,10 @@ export function LogQLEditor({
137191 defaultLanguage = "logql"
138192 language = "logql"
139193 theme = "vs-light"
140- value = { logql }
141- options = { {
142- readOnly : isLoading ,
143- minimap : { enabled : false } ,
144- fontSize : 12 ,
145- lineNumbers : "off" ,
146- scrollBeyondLastLine : false ,
147- selectionHighlight : ! isLoading ,
148- } }
149- onChange = { ( next ) => setLogql ( next ?? "" ) }
150- onMount = { ( editorInstance , monaco ) => {
151- monaco . languages . register ( { id : "logql" } ) ;
152- monaco . languages . setMonarchTokensProvider ( "logql" , monarchlanguage ) ;
153- monaco . languages . setLanguageConfiguration ( "logql" , languageConfiguration ) ;
154- monaco . languages . registerCompletionItemProvider ( "logql" , {
155- provideCompletionItems : ( ) => {
156- const suggestions = COMPLETIONS . map ( ( label ) => ( {
157- label,
158- kind : monaco . languages . CompletionItemKind . Keyword ,
159- insertText : label ,
160- range : {
161- startLineNumber : 1 ,
162- endLineNumber : 1 ,
163- startColumn : 1 ,
164- endColumn : 1 ,
165- } ,
166- detail : "LogQL snippet" ,
167- documentation : "LogQL snippet" ,
168- sortText : label ,
169- filterText : label ,
170- } ) ) ;
171- return { suggestions } ;
172- } ,
173- } ) ;
174-
175- const executeFromEditor = ( ) =>
176- runQuery ( editorInstance . getValue ( ) ?? "" ) ;
177- const keybindings = [
178- monaco . KeyMod . CtrlCmd | monaco . KeyCode . Enter ,
179- monaco . KeyMod . Shift | monaco . KeyCode . Enter ,
180- monaco . KeyMod . WinCtrl | monaco . KeyCode . Enter ,
181- monaco . KeyMod . CtrlCmd |
182- monaco . KeyMod . Shift |
183- monaco . KeyCode . Enter ,
184- ] ;
185- keybindings . forEach ( ( binding ) => {
186- editorInstance . addCommand ( binding , executeFromEditor ) ;
187- } ) ;
188- } }
194+ value = { logql ?? '' }
195+ options = { editorOptions }
196+ onChange = { setLogql }
197+ onMount = { initEditorHandler }
189198 />
190199 </ CardContent >
191200 { error && (
0 commit comments