@flowfuse/nr-assistant 0.2.2-480c08b-202506180948.0 → 0.3.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/README.md +10 -5
- package/index.html +207 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,17 +16,22 @@ This plugin is designed to assist users of the FlowFuse platform by providing to
|
|
|
16
16
|
* Function node Code Lens
|
|
17
17
|
* JSON generation in all typed inputs and JSON editors (like the inject node, change node, template node, etc)
|
|
18
18
|
* Flows Explainer
|
|
19
|
+
* HTML, VUE, and CSS generation in FlowFuse Dashboard ui-template nodes
|
|
19
20
|
|
|
20
21
|
### Function Builder
|
|
21
|
-

|
|
23
23
|
|
|
24
24
|
### JSON generator
|
|
25
|
-

|
|
27
26
|
|
|
28
27
|
### Flows Explainer
|
|
29
|
-

|
|
29
|
+
|
|
30
|
+
### FlowFuse Dashboard UI Template Assistant
|
|
31
|
+

|
|
32
|
+
|
|
33
|
+
### FlowFuse Dashboard UI CSS Assistant
|
|
34
|
+

|
|
30
35
|
|
|
31
36
|
|
|
32
37
|
## Installation
|
package/index.html
CHANGED
|
@@ -80,6 +80,8 @@
|
|
|
80
80
|
|
|
81
81
|
const funcCommandId = 'nr-assistant-fn-inline'
|
|
82
82
|
const jsonCommandId = 'nr-assistant-json-inline'
|
|
83
|
+
const cssCommandId = 'nr-assistant-css-inline'
|
|
84
|
+
const db2uiTemplateCommandId = 'nr-assistant-html-dashboard2-template-inline'
|
|
83
85
|
|
|
84
86
|
debug('registering code lens providers...')
|
|
85
87
|
|
|
@@ -175,6 +177,87 @@
|
|
|
175
177
|
}
|
|
176
178
|
})
|
|
177
179
|
|
|
180
|
+
monaco.languages.registerCodeLensProvider('css', {
|
|
181
|
+
provideCodeLenses: function (model, token) {
|
|
182
|
+
debug('CSS CodeLens provider called', model, token)
|
|
183
|
+
const thisEditor = getMonacoEditorForModel(model)
|
|
184
|
+
const node = RED.view.selection()?.nodes?.[0]
|
|
185
|
+
if (!thisEditor || !node) {
|
|
186
|
+
return
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
lenses: [
|
|
191
|
+
{
|
|
192
|
+
range: {
|
|
193
|
+
startLineNumber: 1,
|
|
194
|
+
startColumn: 1,
|
|
195
|
+
endLineNumber: 2,
|
|
196
|
+
endColumn: 1
|
|
197
|
+
},
|
|
198
|
+
id: cssCommandId
|
|
199
|
+
}
|
|
200
|
+
],
|
|
201
|
+
dispose: () => { }
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
resolveCodeLens: function (model, codeLens, token) {
|
|
205
|
+
debug('CSS CodeLens resolve called', model, codeLens, token)
|
|
206
|
+
if (codeLens.id !== cssCommandId) {
|
|
207
|
+
return codeLens
|
|
208
|
+
}
|
|
209
|
+
codeLens.command = {
|
|
210
|
+
id: codeLens.id,
|
|
211
|
+
title: 'Ask the FlowFuse Assistant 🪄',
|
|
212
|
+
tooltip: 'Click to ask FlowFuse Assistant for help with CSS',
|
|
213
|
+
arguments: [model, codeLens, token]
|
|
214
|
+
}
|
|
215
|
+
return codeLens
|
|
216
|
+
}
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
monaco.languages.registerCodeLensProvider('html', {
|
|
220
|
+
provideCodeLenses: function (model, token) {
|
|
221
|
+
debug('HTML CodeLens provider called', model, token)
|
|
222
|
+
const thisEditor = getMonacoEditorForModel(model)
|
|
223
|
+
if (!thisEditor) {
|
|
224
|
+
return
|
|
225
|
+
}
|
|
226
|
+
const node = RED.view.selection()?.nodes?.[0]
|
|
227
|
+
// only support dashboard2 ui-template nodes for now
|
|
228
|
+
if (!node || node.type !== 'ui-template' || node._def?.set?.id !== '@flowfuse/node-red-dashboard/ui-template') {
|
|
229
|
+
return
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
lenses: [
|
|
233
|
+
{
|
|
234
|
+
range: {
|
|
235
|
+
startLineNumber: 1,
|
|
236
|
+
startColumn: 1,
|
|
237
|
+
endLineNumber: 2,
|
|
238
|
+
endColumn: 1
|
|
239
|
+
},
|
|
240
|
+
id: db2uiTemplateCommandId
|
|
241
|
+
}
|
|
242
|
+
],
|
|
243
|
+
dispose: () => { }
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
resolveCodeLens: function (model, codeLens, token) {
|
|
247
|
+
debug('HTML CodeLens resolve called', model, codeLens, token)
|
|
248
|
+
if (codeLens.id !== db2uiTemplateCommandId) {
|
|
249
|
+
return codeLens
|
|
250
|
+
}
|
|
251
|
+
codeLens.command = {
|
|
252
|
+
id: codeLens.id,
|
|
253
|
+
title: 'Ask the FlowFuse Assistant 🪄',
|
|
254
|
+
tooltip: 'Click to ask FlowFuse Assistant for help with VUE or HTML',
|
|
255
|
+
arguments: [model, codeLens, token]
|
|
256
|
+
}
|
|
257
|
+
return codeLens
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
|
|
178
261
|
debug('registering commands...')
|
|
179
262
|
|
|
180
263
|
monaco.editor.registerCommand(funcCommandId, function (accessor, model, codeLens, token) {
|
|
@@ -368,6 +451,130 @@
|
|
|
368
451
|
}
|
|
369
452
|
})
|
|
370
453
|
|
|
454
|
+
monaco.editor.registerCommand(cssCommandId, function (accessor, model, codeLens, token) {
|
|
455
|
+
debug('running command', cssCommandId)
|
|
456
|
+
const node = RED.view.selection()?.nodes?.[0]
|
|
457
|
+
if (!node) {
|
|
458
|
+
console.warn('No node selected') // should not happen
|
|
459
|
+
return
|
|
460
|
+
}
|
|
461
|
+
if (!assistantOptions.enabled) {
|
|
462
|
+
RED.notify(plugin._('errors.assistant-not-enabled'), 'warning')
|
|
463
|
+
return
|
|
464
|
+
}
|
|
465
|
+
const thisEditor = getMonacoEditorForModel(model)
|
|
466
|
+
if (thisEditor) {
|
|
467
|
+
if (!document.body.contains(thisEditor.getDomNode())) {
|
|
468
|
+
console.warn('Editor is no longer in the DOM, cannot proceed.')
|
|
469
|
+
return
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// FUTURE: for including selected text in the context for features like "fix my code", "refactor this", "what is this?" etc
|
|
473
|
+
// const userSelection = triggeredEditor.getSelection()
|
|
474
|
+
// const selectedText = model.getValueInRange(userSelection)
|
|
475
|
+
/** @type {PromptOptions} */
|
|
476
|
+
const promptOptions = {
|
|
477
|
+
method: 'css',
|
|
478
|
+
lang: 'css',
|
|
479
|
+
type: node.type
|
|
480
|
+
// selectedText: model.getValueInRange(userSelection)
|
|
481
|
+
}
|
|
482
|
+
/** @type {PromptUIOptions} */
|
|
483
|
+
const uiOptions = {
|
|
484
|
+
title: 'FlowFuse Assistant : CSS',
|
|
485
|
+
explanation: 'The FlowFuse Assistant can help you write CSS.',
|
|
486
|
+
description: 'Enter a short description of what you want it to do.'
|
|
487
|
+
}
|
|
488
|
+
doPrompt(node, thisEditor, promptOptions, uiOptions, (error, response) => {
|
|
489
|
+
if (error) {
|
|
490
|
+
console.warn('Error processing request', error)
|
|
491
|
+
return
|
|
492
|
+
}
|
|
493
|
+
debug('css response', response)
|
|
494
|
+
const responseData = response?.data
|
|
495
|
+
if (responseData && responseData.css) {
|
|
496
|
+
// ensure the editor is still present in the DOM
|
|
497
|
+
if (!document.body.contains(thisEditor.getDomNode())) {
|
|
498
|
+
console.warn('Editor is no longer in the DOM')
|
|
499
|
+
return
|
|
500
|
+
}
|
|
501
|
+
thisEditor.focus()
|
|
502
|
+
const currentSelection = thisEditor.getSelection()
|
|
503
|
+
thisEditor.executeEdits('', [
|
|
504
|
+
{
|
|
505
|
+
range: new monaco.Range(currentSelection.startLineNumber, currentSelection.startColumn, currentSelection.endLineNumber, currentSelection.endColumn),
|
|
506
|
+
text: responseData.css
|
|
507
|
+
}
|
|
508
|
+
])
|
|
509
|
+
}
|
|
510
|
+
})
|
|
511
|
+
} else {
|
|
512
|
+
console.warn('Could not find editor for model', model.uri.toString())
|
|
513
|
+
}
|
|
514
|
+
})
|
|
515
|
+
|
|
516
|
+
monaco.editor.registerCommand(db2uiTemplateCommandId, function (accessor, model, codeLens, token) {
|
|
517
|
+
debug('running command', db2uiTemplateCommandId)
|
|
518
|
+
const node = RED.view.selection()?.nodes?.[0]
|
|
519
|
+
if (!node) {
|
|
520
|
+
console.warn('No node selected') // should not happen
|
|
521
|
+
return
|
|
522
|
+
}
|
|
523
|
+
if (!assistantOptions.enabled) {
|
|
524
|
+
RED.notify(plugin._('errors.assistant-not-enabled'), 'warning')
|
|
525
|
+
return
|
|
526
|
+
}
|
|
527
|
+
const thisEditor = getMonacoEditorForModel(model)
|
|
528
|
+
if (thisEditor) {
|
|
529
|
+
if (!document.body.contains(thisEditor.getDomNode())) {
|
|
530
|
+
console.warn('Editor is no longer in the DOM, cannot proceed.')
|
|
531
|
+
return
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// FUTURE: for including selected text in the context for features like "fix my code", "refactor this", "what is this?" etc
|
|
535
|
+
// const userSelection = triggeredEditor.getSelection()
|
|
536
|
+
// const selectedText = model.getValueInRange(userSelection)
|
|
537
|
+
/** @type {PromptOptions} */
|
|
538
|
+
const promptOptions = {
|
|
539
|
+
method: 'dashboard2-template',
|
|
540
|
+
lang: 'html',
|
|
541
|
+
type: node.type
|
|
542
|
+
// selectedText: model.getValueInRange(userSelection)
|
|
543
|
+
}
|
|
544
|
+
/** @type {PromptUIOptions} */
|
|
545
|
+
const uiOptions = {
|
|
546
|
+
title: 'FlowFuse Assistant : Dashboard 2 UI Template',
|
|
547
|
+
explanation: 'The FlowFuse Assistant can help you write HTML, VUE and JavaScript.',
|
|
548
|
+
description: 'Enter a short description of what you want it to do.'
|
|
549
|
+
}
|
|
550
|
+
doPrompt(node, thisEditor, promptOptions, uiOptions, (error, response) => {
|
|
551
|
+
if (error) {
|
|
552
|
+
console.warn('Error processing request', error)
|
|
553
|
+
return
|
|
554
|
+
}
|
|
555
|
+
debug('html response', response)
|
|
556
|
+
const responseData = response?.data
|
|
557
|
+
if (responseData && responseData.html) {
|
|
558
|
+
// ensure the editor is still present in the DOM
|
|
559
|
+
if (!document.body.contains(thisEditor.getDomNode())) {
|
|
560
|
+
console.warn('Editor is no longer in the DOM')
|
|
561
|
+
return
|
|
562
|
+
}
|
|
563
|
+
thisEditor.focus()
|
|
564
|
+
const currentSelection = thisEditor.getSelection()
|
|
565
|
+
thisEditor.executeEdits('', [
|
|
566
|
+
{
|
|
567
|
+
range: new monaco.Range(currentSelection.startLineNumber, currentSelection.startColumn, currentSelection.endLineNumber, currentSelection.endColumn),
|
|
568
|
+
text: responseData.html
|
|
569
|
+
}
|
|
570
|
+
])
|
|
571
|
+
}
|
|
572
|
+
})
|
|
573
|
+
} else {
|
|
574
|
+
console.warn('Could not find editor for model', model.uri.toString())
|
|
575
|
+
}
|
|
576
|
+
})
|
|
577
|
+
|
|
371
578
|
const toolbarMenuButton = $('<li><a id="red-ui-header-button-ff-ai" class="button" href="#"></a></li>')
|
|
372
579
|
const toolbarMenuButtonAnchor = toolbarMenuButton.find('a')
|
|
373
580
|
const deployButtonLi = $('#red-ui-header-button-deploy').closest('li')
|