Skip to content

Commit

Permalink
v4.1.1 See changelog.md
Browse files Browse the repository at this point in the history
  • Loading branch information
TotallyInformation committed Aug 8, 2021
1 parent 6e0bbc3 commit 82ba5d3
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 162 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,22 @@ uibuilder adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

<!-- Nothing currently. -->

### New

* [Issue #151](https://github.com/TotallyInformation/node-red-contrib-uibuilder/issues/151)If the advanced option to "Show web view of source files" is selected, also show a link to the webpage.
### Changed

* [Issue #149](https://github.com/TotallyInformation/node-red-contrib-uibuilder/issues/149) If security is turned on, you can now run without Node-RED using TLS even in production. This is because you may wish to provide TLS via a reverse proxy.

You still get a warning in the editor though.

* Moved back-end libraries from `nodes` folder to `nodes/libs` to keep things tidier (especially if additional nodes added in the future)
* Add simple debug function to web.js to allow the ExpressJS routing stack to be dumped to stdout

### Fixed

* [Issue #150](https://github.com/TotallyInformation/node-red-contrib-uibuilder/issues/150) Switching between src and dist folders now works without having to restart Node-RED. Existing routes are removed first then re-added.
* Common folder is only served once (previously it was been added to the ExpresJS router stack once for each node instance).

## [4.1.0](https://github.com/TotallyInformation/node-red-contrib-uibuilder/compare/v4.0.1...v4.1.0)

Expand Down
2 changes: 1 addition & 1 deletion front-end/src/uibuilderfe.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ if (typeof require !== 'undefined' && typeof io === 'undefined') {

//#region ======== Start of setup ======== //

self.version = '4.1.0'
self.version = '4.1.1'
self.debug = false // do not change directly - use .debug() method
self.moduleName = 'uibuilder' // Must match moduleName in uibuilder.js on the server
// @ts-expect-error ts(2345) Tests loaded ver of lib to see if minified
Expand Down
2 changes: 1 addition & 1 deletion front-end/src/uibuilderfe.min.js

Large diffs are not rendered by default.

61 changes: 48 additions & 13 deletions nodes/libs/web.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ class UibWeb {
this.log = log

/** Optional port. If set, uibuilder will use its own ExpressJS server */
// @ts-expect-error ts(2367)
if ( RED.settings.uibuilder && RED.settings.uibuilder.port && RED.settings.uibuilder.port != RED.settings.uiPort) uib.customServer.port = RED.settings.uibuilder.port

// TODO: Replace _XXX with #XXX once node.js v14 is the minimum supported version
Expand Down Expand Up @@ -194,6 +193,13 @@ class UibWeb {

}

// Serve up the master common folder (e.g. /uibuilder/common/)
// Only load this once for all instances
//TODO: This needs some tweaking to allow the cache settings to change - currently you'd have to restart node-red.
let commonStatic = serveStatic( uib.commonFolder, uib.staticOpts )
// @ts-ignore
this.app.use( tilib.urlJoin(uib.moduleName, uib.commonFolderName), commonStatic )

} // --- End of webSetup() --- //

/** Set which folder to use for the central, static, front-end resources
Expand Down Expand Up @@ -259,20 +265,16 @@ class UibWeb {
)
}

/** Serve up the uibuilder static common folder on `<url>/<commonFolderName>` and `uibuilder/<commonFolderName>` */
/** Serve up the uibuilder static common folder on `<url>/<commonFolderName>` (it is already available on `../uibuilder/<commonFolderName>/`, see _webSetup() */
let commonStatic = serveStatic( uib.commonFolder, uib.staticOpts )
// @ts-ignore
this.app.use( tilib.urlJoin(node.url, uib.commonFolderName), commonStatic )
if ( node.commonStaticLoaded === false ) {
// Only load this once for all instances
//TODO: This needs some tweaking to allow the cache settings to change - currently you'd have to restart node-red.
// @ts-ignore
this.app.use( tilib.urlJoin(uib.moduleName, uib.commonFolderName), commonStatic )
node.commonStaticLoaded = true
}

}

/** (1) Optional middleware from a file */
/** (1) Optional middleware from a file
* @param {uibNode} node
*/
addMiddlewareFile(node) {
// Reference static vars
const uib = this.uib
Expand All @@ -298,7 +300,9 @@ class UibWeb {
}
} // --- End of addMiddlewareFile() --- //

/** (2) Generic dynamic middleware to add uibuilder specific headers & cookies */
/** (2) Generic dynamic middleware to add uibuilder specific headers & cookies
* @param {uibNode} node
*/
addMasterMiddleware(node) {
// Reference static vars
//const uib = this.uib
Expand Down Expand Up @@ -328,7 +332,9 @@ class UibWeb {
this.app.use( tilib.urlJoin(node.url), masterMiddleware )
} // --- End of addMasterMiddleware() --- //

/** (3) Add static ExpressJS route for instance local custom files */
/** (3) Add static ExpressJS route for instance local custom files
* @param {uibNode} node
*/
addInstanceStaticRoute(node) {
// Reference static vars
const uib = this.uib
Expand Down Expand Up @@ -356,6 +362,9 @@ class UibWeb {

const customFull = path.join(node.customFolder, customStatic)

// Remove existing middleware so that it can be redone - allows for changing of src/dist folder
this.removeInstanceMiddleware(node)

// Does the customStatic folder exist? If not, then create it
try {
fs.ensureDirSync( customFull )
Expand All @@ -374,7 +383,9 @@ class UibWeb {

} // --- End of addInstanceStaticRoute() --- //

/** Remove all of the app.use middleware for this instance */
/** Remove all of the app.use middleware for this instance
* @param {uibNode} node
*/
removeInstanceMiddleware(node) {

// We need to remove the app.use paths too as they will be recreated on redeploy
Expand Down Expand Up @@ -408,6 +419,30 @@ class UibWeb {
}

} // --- End of removeAllMiddleware() --- //

/** Dump to console log all middleware for this instance
*
* @param {uibNode} node
*/
dumpInstanceMiddleware(node) {
var urlRe = new RegExp('^' + tilib.escapeRegExp('/^\\' + tilib.urlJoin(node.url)) + '.*$')
var urlReVendor = new RegExp('^' + tilib.escapeRegExp('/^\\/uibuilder\\/vendor\\') + '.*$')
this.app._router.stack.forEach( function(r, i, _stack) { // eslint-disable-line no-unused-vars
// Check whether the URL matches a vendor path...
let rUrlVendor = r.regexp.toString().replace(urlReVendor, '')
// If it DOES NOT, then...
if (rUrlVendor !== '') {
// Check whether the URL is a uibuilder one...
let rUrl = r.regexp.toString().replace(urlRe, '')
// If it IS ...
if ( rUrl === '' ) {
console.log(`[UIBUILDER:web:dumpInstanceMiddleware] ${i}: ${r.name}: ${r.regexp.toString()}` )
if (r.name !== 'serveStatic') console.log(i, r.handle.toString())
}
}
})

}

//#endregion ====== Per-node instance processing ====== //

Expand Down
68 changes: 42 additions & 26 deletions nodes/uibuilder.html
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,7 @@
* Change happens when config panel is opened as well as for a real change
*/
$('#node-input-url').change(function () {

var thisurl = $(this).val()
var eUrlSplit = window.origin.split(':')
var nrPort = Number(eUrlSplit[2])
Expand All @@ -934,8 +935,16 @@
var urlPrefix = eUrlSplit.join(':') + '/'
// Show the root URL
$('#uibuilderurl').prop('href', urlPrefix + nodeRoot + thisurl).text('Open ' + nodeRoot + thisurl)
$('#node-input-showfolder-url').empty().append('<a href="' + urlPrefix + nodeRoot + $(this).val() + '/idx" target="_blank">' + nodeRoot + $(this).val() + '/idx</a>')
$('#uibinstanceconf').prop('href', `./uibuilder/instance/${thisurl}?cmd=showinstancesettings`)
// NB: The index url link is only shown if the option is turned on
$('#show-src-folder-idx-url').empty().append('<div>at <a href="' + urlPrefix + nodeRoot + $(this).val() + '/idx" target="_blank" class="red-ui-button">' + nodeRoot + $(this).val() + '/idx</a></div>')

})

// When the show web view (index) of source files changes
$('#node-input-showfolder').change(function() {
if ($(this).is(':checked') === false) $('#show-src-folder-idx-url').hide()
else $('#show-src-folder-idx-url').show()
})

//#region ---- Template settings ---- //
Expand Down Expand Up @@ -1002,18 +1011,19 @@
// Security turning on/off
$('#node-input-useSecurity').change(function() {
// security is requested, enable other settings and add warnings if needed
if ( this.checked ) {
// If in production, cannot turn on security without https, in dev, give a warning
if (window.location.protocol !== 'https' && window.location.protocol !== 'https:') {
if (RED.settings.uibuilderNodeEnv !== 'development') {
console.error('HTTPS NOT IN USE BUT SECURITY REQUESTED AND Node environment is NOT "development"')
$('#node-input-useSecurity').prop('checked', false); this.checked = false
} else {
console.warn('HTTPS NOT IN USE BUT SECURITY REQUESTED - Node environment is "development" so this is allowed but not recommended')
}
// TODO: Add user warnings
}
}
// @since v4.1.1 disable lockout of security for non-http in production
// if ( this.checked ) {
// // If in production, cannot turn on security without https, in dev, give a warning
// if (window.location.protocol !== 'https' && window.location.protocol !== 'https:') {
// if (RED.settings.uibuilderNodeEnv !== 'development') {
// console.error('HTTPS NOT IN USE BUT SECURITY REQUESTED AND Node environment is NOT "development"')
// $('#node-input-useSecurity').prop('checked', false); this.checked = false
// } else {
// console.warn('HTTPS NOT IN USE BUT SECURITY REQUESTED - Node environment is "development" so this is allowed but not recommended')
// }
// // TODO: Add user warnings
// }
// }
// Yes, we do need this.checked twice :-)
if ( this.checked ) {
$('#node-input-sessionLength').prop('disabled', false)
Expand Down Expand Up @@ -1368,9 +1378,11 @@
//#endregion ---- File Editor ---- //

//#region ---- npm ---- //

// NB: Assuming that the edit section is closed
// Show the npm section, hide the main, adv & security sections
$('#show-npm-props').click(function(e) {

e.preventDefault() // don't trigger normal click event
$('#main-props').hide()
$('#adv-props').hide()
Expand All @@ -1379,8 +1391,8 @@
$('#show-sec-props').html('<i class="fa fa-caret-right"></i> Advanced Settings')
$('#npm-props').show()

/** todo! Improve feedback */
//#region Setup the package list
//! TODO Improve feedback
// Setup the package list
$('#node-input-packageList').editableList({
addItem: addPackageRow, // function
removeItem: removePackageRow, // function(data){},
Expand All @@ -1400,20 +1412,20 @@
$('#node-input-packageList').editableList('addItem',packageName)
})


// spinner
$('.red-ui-editableList-addButton').after(' <i class="spinner"></i>')
$('i.spinner').hide()
//#endregion --- package list ---- //

})

// Hide the npm section, show the main section
$('#npm-close').click(function(e) {
e.preventDefault() // don't trigger normal click event

$('#main-props').show()
$('#npm-props').hide()
})

//#endregion ---- npm ---- //

/** TODO: Get list of installed ACE themes, add chooser, save current choice
Expand Down Expand Up @@ -1461,6 +1473,7 @@

}, // ---- End of oneditcancel ---- //

/** Show notification warning before allowing delete */
oneditdelete: function() {
const that = this
let myNotify = RED.notify(`<b>DELETE</b>: <p>You are deleting a uibuilder instance with url <i>${this.url}</i>.<br>Would you like to also delete the folder?<br><b>WARNING</b>: This cannot be undone.</p>`, {
Expand Down Expand Up @@ -1499,11 +1512,12 @@
]

})
},
}, // ---- End of oneditdelete ---- //

}) // ---- End of registerType() ---- //

})()

</script>

<script type="text/html" data-template-name="uibuilder">
Expand Down Expand Up @@ -1564,7 +1578,8 @@
</div>
</div>

<div aria-label="Show advanced edit properties, collapsible" class="form-row">
<div aria-label="Show advanced properties, collapsible" class="form-row">

<b id="show-adv-props" title="Show&sol;Hide the advanced configuration settings">
<i class="fa fa-caret-right"></i> Advanced Settings
</b>
Expand All @@ -1586,7 +1601,8 @@
<!-- Provide a searchable file index view? -->
<div class="form-row" title="If turned on, an index page showing all available files is created. This can be a security vulnerability and not recommended in Production.">
<input type="checkbox" id="node-input-showfolder" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-showfolder" style="width: 90%;">Show web view of source files at <span id="node-input-showfolder-url">_</span>.</label>
<label for="node-input-showfolder" style="width: 90%;">Show web view of source files</label>
<span id="show-src-folder-idx-url">_</span>.
</div>

<!-- Allow scripts/styles to be passed to front-end? -->
Expand All @@ -1610,6 +1626,7 @@
</label>
</div>
</div>

</div>

<div aria-label="Show security properties, collapsible" class="form-row">
Expand Down Expand Up @@ -1648,8 +1665,7 @@

<div class="form-tips node-help" title="">
Warning: To safely deploy security, you really need to be using TLS.
If you deploy without TLS, you will get warnings. If you try to deploy to production without TLS,
security will not turn on.
If you deploy without TLS, you will get warnings. Ignore them if providing TLS via reverse-proxy.
</div>
<div class="form-tips node-help" title="">
In development mode, if the "Copy Index" (see advanced settings) flag is on, a simplistic template
Expand Down Expand Up @@ -1796,15 +1812,15 @@
</div>
<!-- #endregion -->

<!-- #region Info -->
<div id="info">
<div id="info" aria-label="Information and utility links - always showing">

<a id="uibuilderurl" title="Open the uibuilder web page" href="uibindex" target="_blank" class="red-ui-button editor-button"></a>
<a href="uibindex" target="_blank" class="red-ui-button editor-button" title="Shows available libraries, configuration and other detailed uibuilder information">uibuilder details</a>
<a id="uibinstanceconf" href="./uibuilder/instance/_url_?cmd=showinstancesettings" target="_blank" class="red-ui-button editor-button" title="Shows detailed configuration for this instance of uibuilder">Instance Details</a>
<a href="./uibuilder/techdocs" target="_blank" class="red-ui-button editor-button" title="Shows the uibuilder technical documentation as a new page">Tech Docs</a>

</div>
<div class="form-row" id="info-webserver"></div>
<!-- #endregion -->
<div id="info-webserver" class="form-row"></div>

</script>

Expand Down
4 changes: 2 additions & 2 deletions nodes/uibuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -444,8 +444,8 @@ module.exports = function(/** @type {runtimeRED} */ RED) {
const ioNs = sockets.addNS(node) // NB: Namespace is set from url
node.ioNamespace = ioNs.name

log.debug(`uibuilder : ${uibInstance} : URL . . . . . : ${tilib.urlJoin( uib.nodeRoot, node.url )}`)
log.debug(`uibuilder : ${uibInstance} : Source files . : ${node.customFolder}`)
log.trace(`[uibuilder:${uibInstance}] URL . . . . . : ${tilib.urlJoin( uib.nodeRoot, node.url )}`)
log.trace(`[uibuilder:${uibInstance}] Source files . : ${node.customFolder}`)

// We only do the following if io is not already assigned (e.g. after a redeploy)
uiblib.setNodeStatus( { fill: 'blue', shape: 'dot', text: 'Node Initialised' }, node )
Expand Down
Loading

0 comments on commit 82ba5d3

Please sign in to comment.