2013-09-05 16:02:48 +02:00
/ * *
2015-01-18 10:35:32 +01:00
* Copyright 2013 , 2015 IBM Corp .
2013-09-05 16:02:48 +02:00
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* * /
2014-08-08 01:01:35 +02:00
var RED = ( function ( ) {
2013-09-05 16:02:48 +02:00
2015-01-08 23:34:26 +01:00
var deploymentTypes = {
2015-01-17 21:36:18 +01:00
"full" : { img : "images/deploy-full-o.png" } ,
"nodes" : { img : "images/deploy-nodes-o.png" } ,
"flows" : { img : "images/deploy-flows-o.png" }
2015-01-08 23:34:26 +01:00
}
var deploymentType = "full" ;
2013-09-05 16:02:48 +02:00
function save ( force ) {
if ( RED . view . dirty ( ) ) {
2014-09-04 09:19:37 +02:00
//$("#debug-tab-clear").click(); // uncomment this to auto clear debug on deploy
2013-12-11 23:22:33 +01:00
2013-09-05 16:02:48 +02:00
if ( ! force ) {
var invalid = false ;
2013-12-12 16:51:15 +01:00
var unknownNodes = [ ] ;
2013-09-05 16:02:48 +02:00
RED . nodes . eachNode ( function ( node ) {
2014-05-08 15:15:54 +02:00
invalid = invalid || ! node . valid ;
if ( node . type === "unknown" ) {
if ( unknownNodes . indexOf ( node . name ) == - 1 ) {
unknownNodes . push ( node . name ) ;
2013-12-11 23:22:33 +01:00
}
2014-05-08 15:15:54 +02:00
invalid = true ;
}
2013-09-05 16:02:48 +02:00
} ) ;
if ( invalid ) {
2013-12-12 16:51:15 +01:00
if ( unknownNodes . length > 0 ) {
$ ( "#node-dialog-confirm-deploy-config" ) . hide ( ) ;
$ ( "#node-dialog-confirm-deploy-unknown" ) . show ( ) ;
var list = "<li>" + unknownNodes . join ( "</li><li>" ) + "</li>" ;
$ ( "#node-dialog-confirm-deploy-unknown-list" ) . html ( list ) ;
} else {
$ ( "#node-dialog-confirm-deploy-config" ) . show ( ) ;
$ ( "#node-dialog-confirm-deploy-unknown" ) . hide ( ) ;
}
2013-09-05 16:02:48 +02:00
$ ( "#node-dialog-confirm-deploy" ) . dialog ( "open" ) ;
return ;
}
}
var nns = RED . nodes . createCompleteNodeSet ( ) ;
2014-09-04 09:19:37 +02:00
2014-08-19 23:58:52 +02:00
$ ( "#btn-icn-deploy" ) . removeClass ( 'fa-download' ) ;
2014-02-20 18:31:40 +01:00
$ ( "#btn-icn-deploy" ) . addClass ( 'spinner' ) ;
RED . view . dirty ( false ) ;
2014-09-04 09:19:37 +02:00
2014-04-15 23:30:07 +02:00
$ . ajax ( {
url : "flows" ,
type : "POST" ,
data : JSON . stringify ( nns ) ,
2015-01-08 23:34:26 +01:00
contentType : "application/json; charset=utf-8" ,
headers : {
"Node-RED-Deployment-Type" : deploymentType
}
2014-04-15 23:30:07 +02:00
} ) . done ( function ( data , textStatus , xhr ) {
RED . notify ( "Successfully deployed" , "success" ) ;
RED . nodes . eachNode ( function ( node ) {
if ( node . changed ) {
node . dirty = true ;
node . changed = false ;
2013-09-05 16:02:48 +02:00
}
2014-07-19 01:16:21 +02:00
if ( node . credentials ) {
delete node . credentials ;
2014-06-24 12:13:19 +02:00
}
} ) ;
RED . nodes . eachConfig ( function ( confNode ) {
2014-07-19 01:16:21 +02:00
if ( confNode . credentials ) {
delete confNode . credentials ;
2014-06-24 12:13:19 +02:00
}
2014-04-15 23:30:07 +02:00
} ) ;
// Once deployed, cannot undo back to a clean state
RED . history . markAllDirty ( ) ;
RED . view . redraw ( ) ;
} ) . fail ( function ( xhr , textStatus , err ) {
RED . view . dirty ( true ) ;
if ( xhr . responseText ) {
RED . notify ( "<strong>Error</strong>: " + xhr . responseText , "error" ) ;
} else {
RED . notify ( "<strong>Error</strong>: no response from server" , "error" ) ;
}
} ) . always ( function ( ) {
$ ( "#btn-icn-deploy" ) . removeClass ( 'spinner' ) ;
2014-08-19 23:58:52 +02:00
$ ( "#btn-icn-deploy" ) . addClass ( 'fa-download' ) ;
2013-09-05 16:02:48 +02:00
} ) ;
}
}
$ ( '#btn-deploy' ) . click ( function ( ) { save ( ) ; } ) ;
$ ( "#node-dialog-confirm-deploy" ) . dialog ( {
title : "Confirm deploy" ,
modal : true ,
autoOpen : false ,
width : 530 ,
height : 230 ,
buttons : [
{
text : "Confirm deploy" ,
click : function ( ) {
save ( true ) ;
$ ( this ) . dialog ( "close" ) ;
}
} ,
{
text : "Cancel" ,
click : function ( ) {
$ ( this ) . dialog ( "close" ) ;
}
}
]
} ) ;
2014-02-16 01:39:30 +01:00
function loadSettings ( ) {
2014-10-30 15:19:44 +01:00
RED . settings . init ( loadNodeList ) ;
2014-08-28 01:35:07 +02:00
}
2014-10-30 15:19:44 +01:00
2014-08-28 01:35:07 +02:00
function loadNodeList ( ) {
$ . ajax ( {
headers : {
"Accept" : "application/json"
} ,
2014-09-24 10:57:45 +02:00
cache : false ,
2014-08-28 01:35:07 +02:00
url : 'nodes' ,
success : function ( data ) {
RED . nodes . setNodeList ( data ) ;
loadNodes ( ) ;
}
2014-02-16 01:39:30 +01:00
} ) ;
}
2014-09-04 09:19:37 +02:00
2013-09-05 16:02:48 +02:00
function loadNodes ( ) {
2014-08-28 01:35:07 +02:00
$ . ajax ( {
headers : {
"Accept" : "text/html"
} ,
2014-09-24 10:57:45 +02:00
cache : false ,
2014-08-28 01:35:07 +02:00
url : 'nodes' ,
success : function ( data ) {
$ ( "body" ) . append ( data ) ;
$ ( ".palette-spinner" ) . hide ( ) ;
$ ( ".palette-scroll" ) . show ( ) ;
$ ( "#palette-search" ) . show ( ) ;
loadFlows ( ) ;
}
2013-09-05 16:02:48 +02:00
} ) ;
}
function loadFlows ( ) {
2014-09-24 10:57:45 +02:00
$ . ajax ( {
headers : {
"Accept" : "application/json"
} ,
cache : false ,
url : 'flows' ,
success : function ( nodes ) {
RED . nodes . import ( nodes ) ;
RED . view . dirty ( false ) ;
RED . view . redraw ( ) ;
RED . comms . subscribe ( "status/#" , function ( topic , msg ) {
var parts = topic . split ( "/" ) ;
var node = RED . nodes . node ( parts [ 1 ] ) ;
if ( node ) {
node . status = msg ;
if ( statusEnabled ) {
node . dirty = true ;
RED . view . redraw ( ) ;
2014-08-28 01:35:07 +02:00
}
}
2014-09-24 10:57:45 +02:00
} ) ;
RED . comms . subscribe ( "node/#" , function ( topic , msg ) {
var i , m ;
var typeList ;
var info ;
2014-11-07 13:28:19 +01:00
2014-09-24 10:57:45 +02:00
if ( topic == "node/added" ) {
var addedTypes = [ ] ;
for ( i = 0 ; i < msg . length ; i ++ ) {
m = msg [ i ] ;
var id = m . id ;
RED . nodes . addNodeSet ( m ) ;
if ( m . loaded ) {
addedTypes = addedTypes . concat ( m . types ) ;
$ . get ( 'nodes/' + id , function ( data ) {
$ ( "body" ) . append ( data ) ;
} ) ;
}
2014-08-07 14:46:03 +02:00
}
2014-09-24 10:57:45 +02:00
if ( addedTypes . length ) {
typeList = "<ul><li>" + addedTypes . join ( "</li><li>" ) + "</li></ul>" ;
RED . notify ( "Node" + ( addedTypes . length != 1 ? "s" : "" ) + " added to palette:" + typeList , "success" ) ;
}
} else if ( topic == "node/removed" ) {
for ( i = 0 ; i < msg . length ; i ++ ) {
m = msg [ i ] ;
info = RED . nodes . removeNodeSet ( m . id ) ;
if ( info . added ) {
typeList = "<ul><li>" + m . types . join ( "</li><li>" ) + "</li></ul>" ;
RED . notify ( "Node" + ( m . types . length != 1 ? "s" : "" ) + " removed from palette:" + typeList , "success" ) ;
}
}
} else if ( topic == "node/enabled" ) {
if ( msg . types ) {
info = RED . nodes . getNodeSet ( msg . id ) ;
if ( info . added ) {
RED . nodes . enableNodeSet ( msg . id ) ;
2014-08-28 01:35:07 +02:00
typeList = "<ul><li>" + msg . types . join ( "</li><li>" ) + "</li></ul>" ;
2014-09-24 10:57:45 +02:00
RED . notify ( "Node" + ( msg . types . length != 1 ? "s" : "" ) + " enabled:" + typeList , "success" ) ;
} else {
$ . get ( 'nodes/' + msg . id , function ( data ) {
$ ( "body" ) . append ( data ) ;
typeList = "<ul><li>" + msg . types . join ( "</li><li>" ) + "</li></ul>" ;
RED . notify ( "Node" + ( msg . types . length != 1 ? "s" : "" ) + " added to palette:" + typeList , "success" ) ;
} ) ;
2014-11-07 13:28:19 +01:00
}
2014-09-24 10:57:45 +02:00
}
} else if ( topic == "node/disabled" ) {
if ( msg . types ) {
RED . nodes . disableNodeSet ( msg . id ) ;
typeList = "<ul><li>" + msg . types . join ( "</li><li>" ) + "</li></ul>" ;
RED . notify ( "Node" + ( msg . types . length != 1 ? "s" : "" ) + " disabled:" + typeList , "success" ) ;
}
2014-08-07 14:46:03 +02:00
}
2014-09-24 10:57:45 +02:00
} ) ;
}
2013-09-05 16:02:48 +02:00
} ) ;
}
2014-05-11 00:33:02 +02:00
var statusEnabled = false ;
2014-08-20 22:58:54 +02:00
function toggleStatus ( state ) {
statusEnabled = state ;
2014-05-11 00:33:02 +02:00
RED . view . status ( statusEnabled ) ;
}
2014-09-04 09:19:37 +02:00
2013-09-05 16:02:48 +02:00
function showHelp ( ) {
2013-12-11 23:22:33 +01:00
2013-09-05 16:02:48 +02:00
var dialog = $ ( '#node-help' ) ;
2013-12-11 23:22:33 +01:00
2013-09-05 16:02:48 +02:00
//$("#node-help").draggable({
// handle: ".modal-header"
2013-12-11 23:22:33 +01:00
//});
2013-09-05 16:02:48 +02:00
dialog . on ( 'show' , function ( ) {
2014-05-08 15:15:54 +02:00
RED . keyboard . disable ( ) ;
2013-09-05 16:02:48 +02:00
} ) ;
dialog . on ( 'hidden' , function ( ) {
2014-05-08 15:15:54 +02:00
RED . keyboard . enable ( ) ;
2013-09-05 16:02:48 +02:00
} ) ;
dialog . modal ( ) ;
}
2015-01-08 23:34:26 +01:00
function changeDeploymentType ( type ) {
deploymentType = type ;
2015-01-14 23:40:45 +01:00
$ ( "#btn-deploy img" ) . attr ( "src" , deploymentTypes [ type ] . img ) ;
2015-01-08 23:34:26 +01:00
}
2014-11-11 11:15:02 +01:00
2014-11-12 14:21:39 +01:00
function loadEditor ( ) {
RED . menu . init ( { id : "btn-sidemenu" ,
options : [
{ id : "btn-sidebar" , label : "Sidebar" , toggle : true , onselect : RED . sidebar . toggleSidebar , selected : true } ,
{ id : "btn-node-status" , label : "Display node status" , toggle : true , onselect : toggleStatus , selected : true } ,
null ,
{ id : "btn-import-menu" , label : "Import" , options : [
{ id : "btn-import-clipboard" , label : "Clipboard" , onselect : RED . view . showImportNodesDialog } ,
{ id : "btn-import-library" , label : "Library" , options : [ ] }
] } ,
{ id : "btn-export-menu" , label : "Export" , disabled : true , options : [
{ id : "btn-export-clipboard" , label : "Clipboard" , disabled : true , onselect : RED . view . showExportNodesDialog } ,
{ id : "btn-export-library" , label : "Library" , disabled : true , onselect : RED . view . showExportNodesLibraryDialog }
] } ,
null ,
{ id : "btn-config-nodes" , label : "Configuration nodes" , onselect : RED . sidebar . config . show } ,
null ,
{ id : "btn-subflow-menu" , label : "Subflows" , options : [
{ id : "btn-create-subflow" , label : "Create subflow" , onselect : RED . view . createSubflow } ,
{ id : "btn-convert-subflow" , label : "Selection to subflow" , disabled : true , onselect : RED . view . convertToSubflow } ,
] } ,
null ,
{ id : "btn-workspace-menu" , label : "Workspaces" , options : [
{ id : "btn-workspace-add" , label : "Add" } ,
{ id : "btn-workspace-edit" , label : "Rename" } ,
{ id : "btn-workspace-delete" , label : "Delete" } ,
null
] } ,
null ,
{ id : "btn-keyboard-shortcuts" , label : "Keyboard Shortcuts" , onselect : showHelp } ,
{ id : "btn-help" , label : "Node-RED Website" , href : "http://nodered.org/docs" }
]
} ) ;
RED . menu . init ( { id : "btn-deploy-options" ,
options : [
{ id : "btn-deploy-full" , toggle : "deploy-type" , icon : "images/deploy-full.png" , label : "Full" , sublabel : "Deploys everything in the workspace" , onselect : function ( s ) { if ( s ) { changeDeploymentType ( "full" ) } } } ,
{ id : "btn-deploy-flow" , toggle : "deploy-type" , icon : "images/deploy-flows.png" , label : "Modified Flows" , sublabel : "Only deploys flows that contain changed nodes" , onselect : function ( s ) { if ( s ) { changeDeploymentType ( "flows" ) } } } ,
{ id : "btn-deploy-node" , toggle : "deploy-type" , icon : "images/deploy-nodes.png" , label : "Modified Nodes" , sublabel : "Only deploys nodes that have changed" , onselect : function ( s ) { if ( s ) { changeDeploymentType ( "nodes" ) } } }
]
} ) ;
if ( RED . settings . user ) {
$ ( "#header .username" ) . html ( RED . settings . user . username ) ;
$ ( "#header .user" ) . show ( ) ;
RED . menu . addItem ( "btn-sidemenu" , null ) ;
RED . menu . addItem ( "btn-sidemenu" , {
id : "btn-logout" ,
icon : "fa fa-user" ,
label : "Logout" ,
onselect : function ( ) {
// TODO: invalidate token
$ . ajax ( {
url : "auth/revoke" ,
type : "POST" ,
data : { token : RED . settings . get ( "auth-tokens" ) . access _token } ,
success : function ( ) {
RED . settings . remove ( "auth-tokens" ) ;
document . location . reload ( true ) ;
}
} )
}
2014-11-11 11:15:02 +01:00
} ) ;
2014-11-12 14:21:39 +01:00
}
$ ( "#main-container" ) . show ( ) ;
$ ( "#btn-deploy" ) . show ( ) ;
$ ( "#btn-sidemenu" ) . show ( ) ;
2015-01-08 23:34:26 +01:00
2014-11-12 14:21:39 +01:00
RED . library . init ( ) ;
RED . palette . init ( ) ;
RED . sidebar . init ( ) ;
RED . view . init ( ) ;
RED . keyboard . add ( /* ? */ 191 , { shift : true } , function ( ) { showHelp ( ) ; d3 . event . preventDefault ( ) ; } ) ;
RED . comms . connect ( ) ;
loadNodeList ( ) ;
}
function showLogin ( ) {
var dialog = $ ( "#node-dialog-login" ) ;
dialog . dialog ( {
autoOpen : false ,
dialogClass : "ui-dialog-no-close" ,
modal : true ,
closeOnEscape : false ,
width : 600 ,
resizable : false ,
draggable : false
} ) ;
$ ( "#node-dialog-login-fields" ) . empty ( ) ;
$ . ajax ( {
dataType : "json" ,
url : "auth/login" ,
success : function ( data ) {
if ( data . type == "credentials" ) {
for ( var i = 0 ; i < data . prompts . length ; i ++ ) {
var field = data . prompts [ i ] ;
var row = $ ( "<div/>" , { class : "form-row" } ) ;
$ ( '<label for="node-dialog-login-' + field . id + '">' + field . label + ':</label><br/>' ) . appendTo ( row ) ;
$ ( '<input style="width: 100%" id="node-dialog-login-' + field . id + '" type="' + field . type + '"/>' ) . appendTo ( row ) ;
row . appendTo ( "#node-dialog-login-fields" ) ;
}
$ ( '<div class="form-row" style="text-align: right"><span id="node-dialog-login-failed" style="line-height: 2em;float:left;" class="hide">Login failed</span><img src="spin.svg" style="height: 30px" class="login-spinner hide"/> <a href="#" id="node-dialog-login-submit">Login</a></div>' ) . appendTo ( "#node-dialog-login-fields" ) ;
$ ( "#node-dialog-login-submit" ) . button ( ) . click ( function ( event ) {
$ ( "#node-dialog-login-submit" ) . button ( "option" , "disabled" , true ) ;
$ ( "#node-dialog-login-failed" ) . hide ( ) ;
$ ( ".login-spinner" ) . show ( ) ;
var body = {
client _id : "node-red-admin" ,
grant _type : "password" ,
scope : "*"
2014-11-11 11:15:02 +01:00
}
2014-11-12 14:21:39 +01:00
for ( var i = 0 ; i < data . prompts . length ; i ++ ) {
var field = data . prompts [ i ] ;
body [ field . id ] = $ ( "#node-dialog-login-" + field . id ) . val ( ) ;
}
$ . ajax ( {
url : "auth/token" ,
type : "POST" ,
data : body
} ) . done ( function ( data , textStatus , xhr ) {
RED . settings . set ( "auth-tokens" , data ) ;
$ ( "#node-dialog-login" ) . dialog ( "close" ) ;
load ( ) ;
} ) . fail ( function ( jqXHR , textStatus , errorThrown ) {
RED . settings . remove ( "auth-tokens" ) ;
$ ( "#node-dialog-login-failed" ) . show ( ) ;
} ) . always ( function ( ) {
$ ( "#node-dialog-login-submit" ) . button ( "option" , "disabled" , false ) ;
$ ( ".login-spinner" ) . hide ( ) ;
} ) ;
event . preventDefault ( ) ;
} ) ;
}
2014-11-11 11:15:02 +01:00
dialog . dialog ( "open" ) ;
2014-11-12 14:21:39 +01:00
}
} ) ;
}
function load ( ) {
RED . settings . init ( function ( err , msg ) {
if ( err ) {
if ( err === 401 ) {
showLogin ( ) ;
} else {
console . log ( "Unexpected error:" , err , msg ) ;
}
} else {
loadEditor ( ) ;
2014-11-11 11:15:02 +01:00
}
2015-01-14 23:40:45 +01:00
} ) ;
2014-11-11 11:15:02 +01:00
}
$ ( function ( ) {
if ( ( window . location . hostname !== "localhost" ) && ( window . location . hostname !== "127.0.0.1" ) ) {
document . title = "Node-RED : " + window . location . hostname ;
}
$ ( "#btn-deploy" ) . hide ( ) ;
$ ( "#btn-sidemenu" ) . hide ( ) ;
2015-01-18 10:35:32 +01:00
2014-11-11 11:15:02 +01:00
load ( ) ;
2013-09-05 16:02:48 +02:00
} ) ;
2014-11-07 13:28:19 +01:00
2013-09-05 16:02:48 +02:00
return {
} ;
2014-08-08 01:01:35 +02:00
} ) ( ) ;