diff --git a/packages/node_modules/@node-red/editor-client/src/js/red.js b/packages/node_modules/@node-red/editor-client/src/js/red.js index 99cb8375b..68cd0c780 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/red.js +++ b/packages/node_modules/@node-red/editor-client/src/js/red.js @@ -673,6 +673,69 @@ var RED = (function() { RED.sidebar.show(":first", true); + RED.plugins.registerPlugin('demo-suggestion-source', { + type: 'node-red-flow-suggestion-source', + getSuggestions: async function (context) { + console.log(context) + const suggestion = { + label: 'Change/Debug Combo', + nodes: [ + { id: 'suggestion-1', type: 'change', x: 0, y: 0, wires:[['suggestion-2']] }, + { id: 'suggestion-2', type: 'function', outputs: 3, x: 200, y: 0, wires:[['suggestion-3'],['suggestion-4'],['suggestion-6']] }, + { id: 'suggestion-3', _g: 'suggestion-group-1', type: 'debug', x: 375, y: -40 }, + { id: 'suggestion-4', _g: 'suggestion-group-1', type: 'debug', x: 375, y: 0 }, + { id: 'suggestion-5', _g: 'suggestion-group-1', type: 'debug', x: 410, y: 40 }, + { id: 'suggestion-6', type: 'junction', wires: [['suggestion-5']], x:325, y:40 } + ] + } + const suggestion2 = { + label: 'Another Change/Debug Combo', + nodes: [ + { id: 'suggestion-1', type: 'change', x: 100, y: 100, wires:[['suggestion-2']] }, + { id: 'suggestion-2', type: 'function', outputs: 3, x: 300, y: 100 }, + ] + } + const suggestion3 = { + nodes: [ + { type: 'mqtt in' } + ] + } + await new Promise(resolve => setTimeout(resolve, 1000)); // Simulate async operation + return [suggestion, suggestion2,suggestion3] + } + }) + + RED.plugins.registerPlugin('demo-mqtt-autocomplete-source', { + type: 'node-red-mqtt-topic-autocomplete-source', + getCompletions: async function (value, node) { + return [ + 'home/upstairs/temperature', + 'home/upstairs/humidity', + 'home/upstairs/pressure', + 'home/downstairs/temperature', + 'home/temperature', + 'home/humidity', + 'home/pressure' + ].map(t => t) + } + }) + + RED.plugins.registerPlugin('demo-mqtt-autocomplete-source-2', { + type: 'node-red-mqtt-topic-autocomplete-source', + getCompletions: async function (value, node) { + return [ + 'away/upstairs/temperature', + 'away/upstairs/humidity', + 'away/upstairs/pressure', + 'away/downstairs/temperature', + 'away/temperature', + 'away/humidity', + 'away/pressure' + ].map(t => t) + } + }) + + setTimeout(function() { loader.end(); checkTelemetry(function () { diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js index a4de3f2a9..a0804da14 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/autoComplete.js @@ -15,14 +15,25 @@ * The function must either return auto-complete options, or pass them * to the optional 'done' parameter. * If the function signature includes 'done', it must be used + * The auto-complete options can either be an array of strings, or an array of objects in the form: + * { + * value: String : the value to insert if selected + * label: String|DOM Element : the label to display in the dropdown. + * } + * * minLength: number * If `minLength` is 0, pressing down arrow will show the list + * + * completionPluginType: String + * If provided instead of `search`, this will look for any plugins + * registered with the given type that implement the `getCompletions` function. This + * can be an async function that returns an array of string completions. It does not support + * the full options object as above. * - * The auto-complete options should be an array of objects in the form: - * { - * value: String : the value to insert if selected - * label: String|DOM Element : the label to display in the dropdown. - * } + * node: Node + * If provided, this will be passed to the `getCompletions` function of the plugin + * to allow the plugin to provide context-aware completions. + * * */ @@ -31,6 +42,54 @@ const that = this; this.completionMenuShown = false; this.options.minLength = parseInteger(this.options.minLength, 1, 0); + if (!this.options.search) { + // No search function provided; nothing to provide completions + if (this.options.completionPluginType) { + const plugins = RED.plugins.getPluginsByType(this.options.completionPluginType) + if (plugins.length > 0) { + this.options.search = async function (value, done) { + // for now, only support a single plugin + const promises = plugins.map(plugin => plugin.getCompletions(value, that.options.context)) + const completions = (await Promise.all(promises)).flat() + const results = [] + completions.forEach(completion => { + const element = $('