@@ -71,7 +71,7 @@ export class ExpertComms {
7171 MESSAGE_SCOPE = 'flowfuse-expert'
7272
7373 /** @type {ExpertAutomations } */
74- nodeRedAutomationHelper = new ExpertAutomations ( ) // will set RED instance later in init
74+ nrAutomations = new ExpertAutomations ( ) // will set RED instance later in init
7575
7676 /**
7777 * targetOrigin is set to '*' by default, which allows messages to be sent and received from any origin.
@@ -121,7 +121,7 @@ export class ExpertComms {
121121 'custom:close-search' : { params : null } ,
122122 'custom:close-typeSearch' : { params : null } ,
123123 'custom:close-actionList' : { params : null } ,
124- ...this . nodeRedAutomationHelper . supportedActions
124+ ...this . nrAutomations . supportedActions
125125 }
126126
127127 /**
@@ -201,7 +201,7 @@ export class ExpertComms {
201201 this . RED = RED
202202 this . RED . nrAssistant = this
203203 this . assistantOptions = assistantOptions
204- this . nodeRedAutomationHelper . init ( this , RED )
204+ this . nrAutomations . init ( this , RED )
205205
206206 if ( ! window . parent ?. postMessage || window . self === window . top ) {
207207 console . warn ( 'Parent window not detected - certain interactions with the FlowFuse Expert will not be available' )
@@ -327,10 +327,20 @@ export class ExpertComms {
327327 }
328328
329329 for ( const eventName in this . commandMap ) {
330- if ( type === eventName && typeof this . commandMap [ eventName ] === 'function' ) {
330+ const handler = this . commandMap [ eventName ]
331+ // identify if the hander is a string, function or async function
332+ let handlerType = typeof handler
333+ if ( handlerType === 'function' && handler . constructor . name === 'AsyncFunction' ) {
334+ handlerType = 'asyncfunction'
335+ }
336+ if ( type === eventName && handlerType === 'function' ) {
331337 return this . commandMap [ eventName ] ( payload )
332338 }
333339
340+ if ( type === eventName && handlerType === 'asyncfunction' ) {
341+ return await this . commandMap [ eventName ] ( payload )
342+ }
343+
334344 if (
335345 type === eventName &&
336346 typeof this . commandMap [ eventName ] === 'string' &&
@@ -495,7 +505,7 @@ export class ExpertComms {
495505 /**
496506 * FlowFuse Expert message handlers
497507 */
498- handleActionInvocation ( { event, type, action, params } = { } ) {
508+ async handleActionInvocation ( { event, type, action, params } = { } ) {
499509 this . debug ( `Received request to invoke action "${ action } " with params` , params )
500510 // handle action invocation requests (must be registered actions in supportedActions)
501511 if ( typeof action !== 'string' ) {
@@ -536,9 +546,10 @@ export class ExpertComms {
536546 case 'custom:import-flow' :
537547 // import-flow is a custom action - handle it here directly
538548 try {
539- this . importNodes ( params . flow , params . addFlow === true )
549+ this . nrAutomations . importFlow ( params . flow , { addFlow : params . addFlow } )
540550 this . postReply ( { type, success : true } , event )
541551 } catch ( err ) {
552+ this . RED . notify ( 'Import failed:' + err . message , 'error' )
542553 this . postReply ( { type, error : err ?. message } , event )
543554 }
544555 return
@@ -547,7 +558,7 @@ export class ExpertComms {
547558 try {
548559 if ( actionNamespace === 'automation' ) {
549560 // Handle supported automated actions
550- this . nodeRedAutomationHelper . invokeAction ( action , { event, params } , result )
561+ await this . nrAutomations . invokeAction ( action , { event, params } , result )
551562 } else {
552563 // Handle supported native Node-RED actions
553564 this . RED . actions . invoke ( action , params )
@@ -708,62 +719,6 @@ export class ExpertComms {
708719 return { valid : true }
709720 }
710721
711- /// Function extracted from Node-RED source `editor-client/src/js/ui/clipboard.js`
712- /**
713- * Performs the import of nodes, handling any conflicts that may arise
714- * @param {string } nodesStr the nodes to import as a string
715- * @param {boolean } addFlow whether to add the nodes to a new flow or to the current flow
716- */
717- importNodes ( nodesStr , addFlow ) {
718- let newNodes = nodesStr
719- if ( typeof nodesStr === 'string' ) {
720- try {
721- nodesStr = nodesStr . trim ( )
722- if ( nodesStr . length === 0 ) {
723- return
724- }
725- newNodes = this . validateFlowString ( nodesStr )
726- } catch ( err ) {
727- const e = new Error ( this . RED . _ ( 'clipboard.invalidFlow' , { message : 'test' } ) )
728- e . code = 'NODE_RED'
729- throw e
730- }
731- }
732- const importOptions = { generateIds : true , addFlow }
733- try {
734- this . RED . view . importNodes ( newNodes , importOptions )
735- } catch ( error ) {
736- // Thrown for import_conflict
737- this . RED . notify ( 'Import failed:' + error . message , 'error' )
738- throw error
739- }
740- }
741-
742- /// Function extracted from Node-RED source `editor-client/src/js/ui/clipboard.js`
743- /**
744- * Validates if the provided string looks like valid flow json
745- * @param {string } flowString the string to validate
746- * @returns If valid, returns the node array
747- */
748- validateFlowString ( flowString ) {
749- const res = JSON . parse ( flowString )
750- if ( ! Array . isArray ( res ) ) {
751- throw new Error ( this . RED . _ ( 'clipboard.import.errors.notArray' ) )
752- }
753- for ( let i = 0 ; i < res . length ; i ++ ) {
754- if ( typeof res [ i ] !== 'object' ) {
755- throw new Error ( this . RED . _ ( 'clipboard.import.errors.itemNotObject' , { index : i } ) )
756- }
757- if ( ! Object . hasOwn ( res [ i ] , 'id' ) ) {
758- throw new Error ( this . RED . _ ( 'clipboard.import.errors.missingId' , { index : i } ) )
759- }
760- if ( ! Object . hasOwn ( res [ i ] , 'type' ) ) {
761- throw new Error ( this . RED . _ ( 'clipboard.import.errors.missingType' , { index : i } ) )
762- }
763- }
764- return res
765- }
766-
767722 debug ( ...args ) {
768723 if ( this . RED . nrAssistant ?. DEBUG ) {
769724 const scriptName = 'assistant-index.html.js' // must match the sourceURL set in the script below
0 commit comments