1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Support for library source plugins

This commit is contained in:
Nick O'Leary 2020-12-17 14:35:01 +00:00 committed by Nick O'Leary
parent f96ce2fd83
commit 8a076c01ab
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
9 changed files with 283 additions and 155 deletions

View File

@ -26,7 +26,8 @@ RED.clipboard = (function() {
var currentPopoverError;
var activeTab;
var libraryBrowser;
var examplesBrowser;
var activeLibraries = {};
var pendingImportConfig;
@ -93,7 +94,7 @@ RED.clipboard = (function() {
$( this ).dialog( "close" );
} else {
var flowToExport = $("#red-ui-clipboard-dialog-export-text").val();
var selectedPath = libraryBrowser.getSelected();
var selectedPath = activeLibraries[activeTab].getSelected();
if (!selectedPath.children) {
selectedPath = selectedPath.parent;
}
@ -159,12 +160,7 @@ RED.clipboard = (function() {
if (activeTab === "red-ui-clipboard-dialog-import-tab-clipboard") {
importNodes($("#red-ui-clipboard-dialog-import-text").val(),addNewFlow);
} else {
var selectedPath;
if (activeTab === "red-ui-clipboard-dialog-import-tab-library") {
selectedPath = libraryBrowser.getSelected();
} else {
selectedPath = examplesBrowser.getSelected();
}
var selectedPath = activeLibraries[activeTab].getSelected();
if (selectedPath.path) {
$.get('library/'+selectedPath.library+'/'+selectedPath.type+'/'+selectedPath.path, function(data) {
importNodes(data,addNewFlow);
@ -254,11 +250,8 @@ RED.clipboard = (function() {
'</div>'+
'</div>'+
'</div>'+
'<div id="red-ui-clipboard-dialog-export-tab-library" class="red-ui-clipboard-dialog-tab-library">'+
'<div id="red-ui-clipboard-dialog-export-tab-library-browser"></div>'+
'<div class="form-row">'+
'<label data-i18n="clipboard.export.exportAs"></label><input id="red-ui-clipboard-dialog-tab-library-name" type="text">'+
'</div>'+
'<div class="form-row" id="red-ui-clipboard-dialog-export-tab-library-filename">'+
'<label data-i18n="clipboard.export.exportAs"></label><input id="red-ui-clipboard-dialog-tab-library-name" type="text">'+
'</div>'+
'</div>'+
'</div>'
@ -280,8 +273,6 @@ RED.clipboard = (function() {
'<textarea id="red-ui-clipboard-dialog-import-text"></textarea>'+
'</div>'+
'</div>'+
'<div id="red-ui-clipboard-dialog-import-tab-library" class="red-ui-clipboard-dialog-tab-library"></div>'+
'<div id="red-ui-clipboard-dialog-import-tab-examples" class="red-ui-clipboard-dialog-tab-library"></div>'+
'</div>'+
'</div>'+
'<div class="form-row">'+
@ -414,7 +405,7 @@ RED.clipboard = (function() {
}
},100);
} else {
var file = libraryBrowser.getSelected();
var file = activeLibraries[activeTab].getSelected();
if (file && file.label && !file.children) {
$("#red-ui-clipboard-dialog-ok").button("enable");
} else {
@ -446,7 +437,7 @@ RED.clipboard = (function() {
if (tab.id === "red-ui-clipboard-dialog-import-tab-clipboard") {
$("#red-ui-clipboard-dialog-import-text").trigger("focus");
} else {
libraryBrowser.focus();
activeLibraries[tab.id].focus();
}
validateImport();
}
@ -455,54 +446,43 @@ RED.clipboard = (function() {
id: "red-ui-clipboard-dialog-import-tab-clipboard",
label: RED._("clipboard.clipboard")
});
tabs.addTab({
id: "red-ui-clipboard-dialog-import-tab-library",
label: RED._("library.library")
});
tabs.addTab({
id: "red-ui-clipboard-dialog-import-tab-examples",
label: RED._("library.types.examples")
});
var libraries = RED.settings.libraries || [];
libraries.forEach(function(lib) {
var tabId = "red-ui-clipboard-dialog-import-tab-library-"+lib.id
tabs.addTab({
id: tabId,
label: RED._(lib.label||lib.id)
})
var content = $('<div id="red-ui-clipboard-dialog-import-tab-library" class="red-ui-clipboard-dialog-tab-library"></div>')
.attr("id",tabId)
.hide()
.appendTo("#red-ui-clipboard-dialog-import-tabs-content");
var browser = RED.library.createBrowser({
container: content,
onselect: function(file) {
if (file && file.label && !file.children) {
$("#red-ui-clipboard-dialog-ok").button("enable");
} else {
$("#red-ui-clipboard-dialog-ok").button("disable");
}
},
onconfirm: function(item) {
if (item && item.label && !item.children) {
$("#red-ui-clipboard-dialog-ok").trigger("click");
}
}
})
loadFlowLibrary(browser,lib);
activeLibraries[tabId] = browser;
})
$("#red-ui-clipboard-dialog-tab-library-name").on("keyup", validateExportFilename);
$("#red-ui-clipboard-dialog-tab-library-name").on('paste',function() { setTimeout(validateExportFilename,10)});
$("#red-ui-clipboard-dialog-export").button("enable");
libraryBrowser = RED.library.createBrowser({
container: $("#red-ui-clipboard-dialog-import-tab-library"),
onselect: function(file) {
if (file && file.label && !file.children) {
$("#red-ui-clipboard-dialog-ok").button("enable");
} else {
$("#red-ui-clipboard-dialog-ok").button("disable");
}
},
onconfirm: function(item) {
if (item && item.label && !item.children) {
$("#red-ui-clipboard-dialog-ok").trigger("click");
}
}
})
loadFlowLibrary(libraryBrowser,"local",RED._("library.types.local"));
examplesBrowser = RED.library.createBrowser({
container: $("#red-ui-clipboard-dialog-import-tab-examples"),
onselect: function(file) {
if (file && file.label && !file.children) {
$("#red-ui-clipboard-dialog-ok").button("enable");
} else {
$("#red-ui-clipboard-dialog-ok").button("disable");
}
},
onconfirm: function(item) {
if (item && item.label && !item.children) {
$("#red-ui-clipboard-dialog-ok").trigger("click");
}
}
})
loadFlowLibrary(examplesBrowser,"_examples_",RED._("library.types.examples"));
dialogContainer.i18n();
$("#red-ui-clipboard-dialog-ok").show();
@ -582,10 +562,12 @@ RED.clipboard = (function() {
if (tab.id === "red-ui-clipboard-dialog-export-tab-clipboard") {
$("#red-ui-clipboard-dialog-export").button("option","label", RED._("clipboard.export.copy"))
$("#red-ui-clipboard-dialog-download").show();
$("#red-ui-clipboard-dialog-export-tab-library-filename").hide();
} else {
$("#red-ui-clipboard-dialog-export").button("option","label", RED._("clipboard.export.export"))
$("#red-ui-clipboard-dialog-download").hide();
libraryBrowser.focus();
$("#red-ui-clipboard-dialog-export-tab-library-filename").show();
activeLibraries[activeTab].focus();
}
}
@ -594,26 +576,45 @@ RED.clipboard = (function() {
id: "red-ui-clipboard-dialog-export-tab-clipboard",
label: RED._("clipboard.clipboard")
});
tabs.addTab({
id: "red-ui-clipboard-dialog-export-tab-library",
label: RED._("library.library")
});
var libraries = RED.settings.libraries || [];
libraries.forEach(function(lib) {
if (lib.readOnly) {
return
}
var tabId = "red-ui-clipboard-dialog-export-tab-library-"+lib.id
tabs.addTab({
id: tabId,
label: RED._(lib.label||lib.id)
})
var content = $('<div class="red-ui-clipboard-dialog-export-tab-library-browser red-ui-clipboard-dialog-tab-library"></div>')
.attr("id",tabId)
.hide()
.insertBefore("#red-ui-clipboard-dialog-export-tab-library-filename");
var browser = RED.library.createBrowser({
container: content,
folderTools: true,
onselect: function(file) {
if (file && file.label && !file.children) {
$("#red-ui-clipboard-dialog-tab-library-name").val(file.label);
}
},
})
loadFlowLibrary(browser,lib);
activeLibraries[tabId] = browser;
})
$("#red-ui-clipboard-dialog-tab-library-name").on("keyup", validateExportFilename);
$("#red-ui-clipboard-dialog-tab-library-name").on('paste',function() { setTimeout(validateExportFilename,10)});
$("#red-ui-clipboard-dialog-export").button("enable");
libraryBrowser = RED.library.createBrowser({
container: $("#red-ui-clipboard-dialog-export-tab-library-browser"),
folderTools: true,
onselect: function(file) {
if (file && file.label && !file.children) {
$("#red-ui-clipboard-dialog-tab-library-name").val(file.label);
}
}
})
loadFlowLibrary(libraryBrowser,"local",RED._("library.types.local"));
var clipboardTabs = RED.tabs.create({
id: "red-ui-clipboard-dialog-export-tab-clipboard-tabs",
onchange: function(tab) {
@ -852,35 +853,28 @@ RED.clipboard = (function() {
$("#red-ui-clipboard-dialog-export-tab-clipboard-preview-list").treeList('data',treeData);
}
function loadFlowLibrary(browser,library,label) {
// if (includeExamples) {
// listing.push({
// library: "_examples_",
// type: "flows",
// icon: 'fa fa-hdd-o',
// label: RED._("library.types.examples"),
// path: "",
// children: function(done,item) {
// RED.library.loadLibraryFolder("_examples_","flows","",function(children) {
// item.children = children;
// done(children);
// })
// }
// })
// }
function loadFlowLibrary(browser,library) {
browser.data([{
library: library,
library: library.id,
type: "flows",
icon: 'fa fa-hdd-o',
label: label,
icon: library.icon || 'fa fa-hdd-o',
label: RED._(library.label||library.id),
path: "",
expanded: true,
children: function(done, item) {
RED.library.loadLibraryFolder(library,"flows","",function(children) {
item.children = children;
done(children);
})
}
children: [{
library: library.id,
type: "flows",
icon: 'fa fa-cube',
label: "flows",
path: "",
expanded: true,
children: function(done, item) {
RED.library.loadLibraryFolder(library.id,"flows","",function(children) {
item.children = children;
done(children);
})
}
}]
}], true);
}

View File

@ -216,31 +216,7 @@ RED.library = (function() {
{ id:'node-input-'+options.type+'-menu-open-library',
label: RED._("library.openLibrary"),
onselect: function() {
activeLibrary = options;
loadLibraryFolder("local",options.url, "", function(items) {
var listing = [{
library: "local",
type: options.url,
icon: 'fa fa-hdd-o',
label: RED._("library.types.local"),
path: "",
expanded: true,
writable: false,
children: [{
library: "local",
type: options.url,
icon: 'fa fa-cube',
label: options.type,
path: "",
expanded: true,
children: items
}]
}]
loadLibraryBrowser.data(listing);
setTimeout(function() {
loadLibraryBrowser.select(listing[0].children[0]);
},200);
});
libraryEditor = ace.edit('red-ui-library-dialog-load-preview-text',{
useWorker: false
});
@ -256,6 +232,43 @@ RED.library = (function() {
libraryEditor.renderer.$cursorLayer.element.style.opacity=0;
libraryEditor.$blockScrolling = Infinity;
activeLibrary = options;
var listing = [];
var libraries = RED.settings.libraries || [];
libraries.forEach(function(lib) {
if (lib.types && lib.types.indexOf(options.url) === -1) {
return;
}
listing.push({
library: lib.id,
type: options.url,
icon: lib.icon || 'fa fa-hdd-o',
label: RED._(lib.label||lib.id),
path: "",
expanded: true,
writable: false,
children: [{
library: lib.id,
type: options.url,
icon: 'fa fa-cube',
label: options.type,
path: "",
expanded: false,
children: function(done, item) {
loadLibraryFolder(lib.id, options.url, "", function(children) {
item.children = children;
done(children);
})
}
}]
})
});
loadLibraryBrowser.data(listing);
setTimeout(function() {
loadLibraryBrowser.select(listing[0].children[0]);
},200);
var dialogHeight = 400;
var winHeight = $(window).height();
if (winHeight < 570) {
@ -278,30 +291,40 @@ RED.library = (function() {
}
$("#red-ui-library-dialog-save-filename").attr("value",filename+"."+(options.ext||"txt"));
loadLibraryFolder("local",options.url, "", function(items) {
var listing = [{
library: "local",
var listing = [];
var libraries = RED.settings.libraries || [];
libraries.forEach(function(lib) {
if (lib.types && lib.types.indexOf(options.url) === -1) {
return;
}
listing.push({
library: lib.id,
type: options.url,
icon: 'fa fa-hdd-o',
label: RED._("library.types.local"),
icon: lib.icon || 'fa fa-hdd-o',
label: RED._(lib.label||lib.id),
path: "",
expanded: true,
writable: false,
children: [{
library: "local",
library: lib.id,
type: options.url,
icon: 'fa fa-cube',
label: options.type,
path: "",
expanded: true,
children: items
expanded: false,
children: function(done, item) {
loadLibraryFolder(lib.id, options.url, "", function(children) {
item.children = children;
done(children);
})
}
}]
}]
saveLibraryBrowser.data(listing);
setTimeout(function() {
saveLibraryBrowser.select(listing[0].children[0]);
},200);
})
});
saveLibraryBrowser.data(listing);
setTimeout(function() {
saveLibraryBrowser.select(listing[0].children[0]);
},200);
var dialogHeight = 400;
var winHeight = $(window).height();

View File

@ -93,10 +93,9 @@
border:1px solid $primary-border-color;
}
.red-ui-clipboard-dialog-tab-library {
.form-row {
margin-left: 10px;
}
#red-ui-clipboard-dialog-export-tab-library-filename {
height: auto !important;
margin-left: 10px;
}
#red-ui-clipboard-dialog {
@ -110,7 +109,7 @@
#red-ui-clipboard-dialog-tab-library-name {
width: calc(100% - 120px);
}
#red-ui-clipboard-dialog-export-tab-library-browser {
.red-ui-clipboard-dialog-tabs-content>div.red-ui-clipboard-dialog-export-tab-library-browser {
height: calc(100% - 60px);
margin-bottom: 13px;
border-bottom: 1px solid $primary-border-color;

View File

@ -81,7 +81,7 @@ var api = module.exports = {
if (!runtime.settings.disableEditor) {
safeSettings.context = runtime.nodes.listContextStores();
safeSettings.libraries = runtime.library.getLibraries();
if (util.isArray(runtime.settings.paletteCategories)) {
safeSettings.paletteCategories = runtime.settings.paletteCategories;
}

View File

@ -74,7 +74,6 @@ function init(userSettings,httpServer,_adminApi) {
adminApi = _adminApi;
}
redNodes.init(runtime);
library.init(runtime);
externalAPI.init(runtime);
}
@ -104,6 +103,7 @@ function start() {
return i18n.registerMessageCatalog("runtime",path.resolve(path.join(__dirname,"..","locales")),"runtime.json")
.then(function() { return storage.init(runtime)})
.then(function() { return settings.load(storage)})
.then(function() { return library.init(runtime)})
.then(function() {
if (log.metric()) {

View File

@ -15,21 +15,54 @@
**/
var knownTypes = {};
const {events} = require("@node-red/util")
const knownTypes = {};
const libraries = {};
const libraryPlugins = {};
var libraries = {};
// Libraries defined in the settings file. Their configurations
// cannot be modified in the editor.
let runtimeLibraries = [];
// Libraries defined by the user in the editor.
let userLibraries = [];
function init(runtime) {
knownTypes = {
'flows': 'node-red'
};
libraries["_examples_"] = require("./examples");
libraries["_examples_"].init(runtime);
events.on("registry:plugin-added", function(id) {
const plugin = runtime.plugins.getPlugin(id);
if (plugin.type === "node-red-library-source") {
libraryPlugins[plugin.id] = plugin;
runtimeLibraries.forEach(library => {
if (library.type === id) {
library.local = false;
libraries[library.id] = new plugin.class(library)
if (libraries[library.id].init) {
libraries[library.id].init();
}
}
})
}
})
knownTypes.flows = 'node-red';
libraries["examples"] = require("./examples");
libraries["examples"].init(runtime);
libraries["local"] = require("./local");
libraries["local"].init(runtime);
try {
runtimeLibraries = runtime.settings.editorTheme.library.sources;
} catch(err) {
runtimeLibraries = [];
}
// userLibraries = runtime.settings.get("library")
}
function registerType(id,type) {
@ -56,7 +89,7 @@ function saveEntry(library,type,path,meta,body) {
throw new Error(`Unknown library type '${type}'`);
}
if (libraries.hasOwnProperty(library)) {
if (libraries[library].hasOwnProperty("saveEntry")) {
if (libraries[library].saveEntry) {
return libraries[library].saveEntry(type,path,meta,body);
} else {
throw new Error(`Library '${library}' is read-only`);
@ -66,8 +99,43 @@ function saveEntry(library,type,path,meta,body) {
}
}
function getLibraries() {
const libraryList = [
{
id: "local",
label: "editor:library.types.local",
user: false,
icon: "fa fa-bath"
},
{
id: "examples",
label: "editor:library.types.examples",
user: false,
readOnly: true,
types: ['flows']
}
];
for (let id in libraries) {
if (libraries.hasOwnProperty(id)) {
if (id !== 'local' && id !== 'examples') {
libraryList.push({
id: id,
label: libraries[id].name || id,
user: false,
icon: libraries[id].icon
})
}
}
}
return libraryList;
}
module.exports = {
init: init,
getLibraries: getLibraries,
register: registerType,
getEntry: getEntry,
saveEntry: saveEntry

View File

@ -0,0 +1,11 @@
<script type="text/javascript">
RED.plugins.registerPlugin("node-red-library-filestore", {
type: "node-red-library-source",
name: "Local File-System Library",
icon: "font-awesome/fa-hdd-o",
defaults: {
name: { value: "" },
path: { value: ""}
}
})
</script>

View File

@ -0,0 +1,32 @@
module.exports = function(RED) {
class FileStorePlugin {
constructor(config) {
this.id = config.id;
this.name = config.name;
this.config = config;
this.icon = config.icon;
console.log("FileStorePlugin",config)
}
async init() {
console.log("FileStorePlugin.init")
}
async getEntry(type,path) {
console.log("FileStorePlugin.getLibraryEntry",type,path)
return []
}
async saveEntry(type,path,meta,body) {
console.log("FileStorePlugin.saveLibraryEntry",type,path)
}
}
RED.plugins.registerPlugin("node-red-library-filestore", {
type: "node-red-library-source",
class: FileStorePlugin
})
}

View File

@ -6,7 +6,8 @@
"plugins": {
"test": "test.js",
"test-editor-plugin": "test-editor-plugin.html",
"test-runtime-plugin": "test-runtime-plugin.js"
"test-runtime-plugin": "test-runtime-plugin.js",
"library-filestore": "library-filestore.js"
}
}
}