@@ -7,31 +7,9 @@ import init, {
77 vrl_version
88} from "./pkg/vector_vrl_web_playground.js" ;
99import { registerVrlCompletion } from "./vrl-completion.js" ;
10+ import { DEFAULT_EXAMPLE , VRL_EXAMPLES } from "./vrl-examples.js" ;
1011import { vrlLanguageDefinition , vrlThemeDefinition } from "./vrl-highlighter.js" ;
1112
12- const PROGRAM_EDITOR_DEFAULT_VALUE = `# Remove some fields
13- del(.foo)
14-
15- # Add a timestamp
16- .timestamp = now()
17-
18- # Parse HTTP status code into local variable
19- http_status_code = parse_int!(.http_status)
20- del(.http_status)
21-
22- # Add status
23- if http_status_code >= 200 && http_status_code <= 299 {
24- .status = "success"
25- } else {
26- .status = "error"
27- }` ;
28-
29- const EVENT_EDITOR_DEFAULT_VALUE = `{
30- "message": "Hello VRL",
31- "foo": "delete me",
32- "http_status": "200"
33- }` ;
34-
3513const OUTPUT_EDITOR_DEFAULT_VALUE = `{}` ;
3614
3715const HISTORY_STORAGE_KEY = "vrl_playground_history" ;
@@ -114,25 +92,33 @@ export class VrlWebPlayground {
11492 getSampleEvent : ( ) => this . _sampleEvent ( )
11593 } ) ;
11694
95+ // Size the panels before Monaco measures its containers.
96+ this . addVersions ( ) ;
97+ this . _initSplitPanels ( ) ;
98+
11799 // Editors
118- this . eventEditor = this . createDefaultEditor ( "container-event" , EVENT_EDITOR_DEFAULT_VALUE , "json" , "vs-light" ) ;
119- this . outputEditor = this . createDefaultEditor ( "container-output" , OUTPUT_EDITOR_DEFAULT_VALUE , "json" , "vs-light" ) ;
120- this . programEditor = this . createDefaultEditor (
121- "container-program" ,
122- PROGRAM_EDITOR_DEFAULT_VALUE ,
123- "vrl" ,
124- "vrl-theme"
100+ this . eventEditor = this . createDefaultEditor (
101+ "container-event" ,
102+ JSON . stringify ( DEFAULT_EXAMPLE . event , null , 2 ) ,
103+ "json" ,
104+ "vs-light"
125105 ) ;
126-
127- // Resizable panels
128- this . _initSplitPanels ( ) ;
106+ this . outputEditor = this . createDefaultEditor ( "container-output" , OUTPUT_EDITOR_DEFAULT_VALUE , "json" , "vs-light" ) ;
107+ this . returnedValueEditor = this . createDefaultEditor ( "container-returned-value" , "" , "json" , "vs-light" ) ;
108+ this . returnedValueEditor . updateOptions ( { readOnly : true } ) ;
109+ this . programEditor = this . createDefaultEditor ( "container-program" , DEFAULT_EXAMPLE . program , "vrl" , "vrl-theme" ) ;
110+ this . programEditor . addAction ( {
111+ id : "vrl.find" ,
112+ label : "Find" ,
113+ contextMenuGroupId : "navigation" ,
114+ contextMenuOrder : 0 ,
115+ run : ( editor ) => editor . getAction ( "actions.find" ) . run ( )
116+ } ) ;
117+ this . _initChangeAllAction ( ) ;
129118
130119 // Theme
131120 this . _initTheme ( ) ;
132121
133- // Versions
134- this . addVersions ( ) ;
135-
136122 // Keyboard shortcut: Shift+Enter runs the program
137123 window . addEventListener ( "keydown" , ( e ) => {
138124 if ( e . shiftKey && e . key === "Enter" ) {
@@ -141,6 +127,8 @@ export class VrlWebPlayground {
141127 }
142128 } ) ;
143129
130+ this . _initExamples ( ) ;
131+
144132 // Populate history dropdown from localStorage
145133 this . _populateHistoryDropdown ( ) ;
146134
@@ -155,6 +143,64 @@ export class VrlWebPlayground {
155143
156144 // Handle shared state from URL (if present)
157145 this . _maybeLoadFromUrl ( ) ;
146+
147+ for ( const editor of [ this . programEditor , this . eventEditor , this . outputEditor , this . returnedValueEditor ] ) {
148+ editor . layout ( ) ;
149+ }
150+ document . getElementById ( "main-split" ) . setAttribute ( "aria-busy" , "false" ) ;
151+ }
152+
153+ _initExamples ( ) {
154+ const select = document . getElementById ( "examples-select" ) ;
155+ if ( ! select ) return ;
156+
157+ for ( const example of VRL_EXAMPLES ) {
158+ const option = document . createElement ( "option" ) ;
159+ option . value = example . id ;
160+ option . textContent = example . name ;
161+ select . appendChild ( option ) ;
162+ }
163+
164+ select . addEventListener ( "change" , ( ) => {
165+ const example = VRL_EXAMPLES . find ( ( entry ) => entry . id === select . value ) ;
166+ if ( ! example ) return ;
167+
168+ this . programEditor . setValue ( example . program ) ;
169+ this . eventEditor . setValue ( JSON . stringify ( example . event , null , 2 ) ) ;
170+ this . enableJsonLinting ( ) ;
171+ this . handleRunCode ( ) ;
172+ } ) ;
173+
174+ const updateSelection = ( ) => {
175+ const example = VRL_EXAMPLES . find (
176+ ( entry ) =>
177+ entry . program === this . _safeGet ( this . programEditor ) &&
178+ JSON . stringify ( entry . event , null , 2 ) === this . _safeGet ( this . eventEditor )
179+ ) ;
180+ select . value = example ?. id ?? "" ;
181+ } ;
182+ this . programEditor . onDidChangeModelContent ( updateSelection ) ;
183+ this . eventEditor . onDidChangeModelContent ( updateSelection ) ;
184+ }
185+
186+ _initChangeAllAction ( ) {
187+ // The context menu takes focus, so remember which editor opened it.
188+ let focusedEditor = this . programEditor ;
189+ for ( const editor of [ this . programEditor , this . eventEditor , this . outputEditor , this . returnedValueEditor ] ) {
190+ editor . onDidFocusEditorText ( ( ) => {
191+ focusedEditor = editor ;
192+ } ) ;
193+ }
194+
195+ this . monaco . editor . registerCommand ( "editor.action.changeAll" , async ( ) => {
196+ const editor = focusedEditor ;
197+ if ( editor !== this . programEditor ) {
198+ return editor . getAction ( "editor.action.changeAll" ) . run ( ) ;
199+ }
200+ // Find seeds the query from the selection or the word under the cursor.
201+ await editor . getAction ( "actions.find" ) . run ( ) ;
202+ return editor . getAction ( "editor.action.startFindReplaceAction" ) . run ( ) ;
203+ } ) ;
158204 }
159205
160206 _maybeLoadFromUrl ( ) {
@@ -256,10 +302,10 @@ export class VrlWebPlayground {
256302 cursor : "col-resize"
257303 } ) ;
258304
259- window . Split ( [ "#event-cell" , "#output-cell" ] , {
305+ window . Split ( [ "#event-cell" , "#output-cell" , "#returned-value-cell" ] , {
260306 direction : "vertical" ,
261- sizes : [ 50 , 50 ] ,
262- minSize : 100 ,
307+ sizes : [ 40 , 40 , 20 ] ,
308+ minSize : [ 80 , 80 , 60 ] ,
263309 gutterSize : 6 ,
264310 cursor : "row-resize"
265311 } ) ;
@@ -304,6 +350,7 @@ export class VrlWebPlayground {
304350 }
305351
306352 _clearOutput ( ) {
353+ this . returnedValueEditor ?. setValue ( "" ) ;
307354 if ( this . outputEditor ) {
308355 // wipe the buffer so stale values never linger
309356 this . outputEditor . setValue ( "" ) ;
@@ -341,6 +388,15 @@ export class VrlWebPlayground {
341388 }
342389 }
343390
391+ _formatReturnedValue ( runResult ) {
392+ if ( typeof runResult ?. runtime_output === "string" ) return runResult . runtime_output ;
393+ // Also support older runtimes, where only the deserialized value is available.
394+ if ( runResult && Object . prototype . hasOwnProperty . call ( runResult , "runtime_result" ) ) {
395+ return JSON . stringify ( runResult . runtime_result , null , "\t" ) ;
396+ }
397+ return "" ;
398+ }
399+
344400 _safeGet ( editor , fallback = "" ) {
345401 return editor ?. getValue ?. ( ) ?? fallback ;
346402 }
@@ -496,6 +552,7 @@ export class VrlWebPlayground {
496552 if ( entry . outputIsJson ) this . enableJsonLinting ( ) ;
497553 else this . disableJsonLinting ( ) ;
498554 this . outputEditor ?. setValue ( entry . output ?? "" ) ;
555+ this . returnedValueEditor ?. setValue ( entry . returnedValue ?? "" ) ;
499556 this . _setElapsed ( entry . elapsedTime ) ;
500557 }
501558
@@ -527,13 +584,16 @@ export class VrlWebPlayground {
527584 if ( isJson ) this . enableJsonLinting ( ) ;
528585 else this . disableJsonLinting ( ) ;
529586 this . outputEditor . setValue ( text ) ;
587+ const returnedValue = this . _formatReturnedValue ( runResult ) ;
588+ this . returnedValueEditor . setValue ( returnedValue ) ;
530589
531590 this . _setElapsed ( runResult ?. elapsed_time ) ;
532591 this . _saveToHistory ( {
533592 program : this . _safeGet ( this . programEditor ) ,
534593 event : this . _safeGet ( this . eventEditor ) ,
535594 output : text ,
536595 outputIsJson : isJson ,
596+ returnedValue,
537597 elapsedTime : runResult ?. elapsed_time ,
538598 timezone
539599 } ) ;
@@ -566,6 +626,8 @@ export class VrlWebPlayground {
566626 // Output is not pure JSON (multiple objects / possible errors)
567627 this . disableJsonLinting ( ) ;
568628 this . outputEditor . setValue ( outputText ) ;
629+ const returnedValue = results . map ( ( r ) => this . _formatReturnedValue ( r ) ) . join ( "\n" ) ;
630+ this . returnedValueEditor . setValue ( returnedValue ) ;
569631
570632 // Aggregate elapsed time, rounded
571633 const total = results . reduce ( ( sum , r ) => sum + ( typeof r ?. elapsed_time === "number" ? r . elapsed_time : 0 ) , 0 ) ;
@@ -575,6 +637,7 @@ export class VrlWebPlayground {
575637 event : this . _safeGet ( this . eventEditor ) ,
576638 output : outputText ,
577639 outputIsJson : false ,
640+ returnedValue,
578641 elapsedTime : total ,
579642 timezone
580643 } ) ;
0 commit comments