Extending the console is easy!
The console uses metadata defined by the docRouter module to generate the commands.
In order to create another command, add a new file under the repo/sys/console/api
folder. The command will be named after the new api file name.
The api file should expose the following structure:
module.exports = { console: { autoLoad: true, router: expressRouter } };
When the autoLoad
flag is set to true
, it will make the plugin to be automatically integrated into the console when it is started.
The router
parameter is the express router
object. Look at the api files for an example of how the apis are exposed.
Each API can contain any number of commands, all namespaced by the api file name. The console will generate a command for each of the methods in the api file.
To execute a method (command), type the api file name and then the method name. ie, to execute command1
in file api1
, type api1 command1
and then provide the params if required.
Simple commands are commands that get parameters and return json/html to be displayed in the console as a result of executing the command with the provided parameters.
These commands do not require any client side logics. They are called by the console with the neccessary parameters provided, process the request and return the final result which is displayed as is.
A command that returns a json
result, will use a generic json-view control to display the object, any other result will be displayed as is (html
).
Most of the commands currently implemented are simple commands.
In this manual we will refer to the sample.js
file as an example to extending the console.
As can be seen, the file begins with the docRouter definition, defining /api/sample
as the root for this api:
docRouter(router, '/api/sample', function (router) {
Each method in the api file defines
- a Verb-
GET
orPOST
- The console uses this info to invoke the method - a set of parameters- Parameters are optional. Each parameter defines its
type
- The parameter type:string
,int
,bool
.required
-true
/false
.style
-template
- this parameter is expected to be provided as part if the url,query
- as part of the querystring orbody
- as part of the post body.short
- an optional switch that will be used to refer that parameter in the command line.defaultValue
- a value that will be used if the parameter was not provided as part of the command line. In this case, the value is automatically considered as an optional parameter.defaultEnvVar
- defines an environment variable parameter name that will be used as a default value if the parameter was not provided. If it does not exist or empty, the default value will be used if provided as described above. An example to using this option can be found in thelog.js
api file.
The following is an example for a command that gets 3 parameters: tparam1
and tparam2
which are defined as a template
parameters, and qparam
which is defined as a qurtystring
parameter.
The tparam2
parameter has a defaultValue
set, which means that as far of the console's concern, this is an optional parameter that will get the value provided in the defaultValue
if not provided
in the command line.
app.get('/json/:tparam1/:tparam2', function(req, res) {
var tparam1 = req.params.tparam1;
var tparam2 = req.params.tparam2;
var qparam = req.query['qparam'];
var o = {tparam1: tparam1, tparam2: tparam2, qparam: qparam};
res.writeHead(200, {'Content-Type': 'application/json' });
res.end(JSON.stringify(o));
},
{
id: 'sample_json',
name: 'json',
usage: 'json tparam1 qparam [tparam2]',
example: 'json tparam1 qparamValue',
doc: 'sample for a GET command getting template params and a query param',
params: {
"tparam1" : {
"short": "b",
"type": "string",
"doc": "template param",
"style": "template",
"required": "true"
},
"qparam" : {
"short": "q",
"type": "string",
"doc": "querty string param",
"style": "query",
"required": "true"
},
tparam2 : {
"short": "a",
"type": "string",
"doc": "template param",
"style": "template",
"required": "true",
"defaultValue": "someTemplateValue"
}
}
}
);
- The following command:
sample json 1 2
callsGET /api/sample/json/1/someTemplateValue?qparam=2
and returns the result{"tparam1":"1","tparam2":"someTemplateValue","qparam":"2"}
. - The following command:
sample json 1 2 3
callsGET /api/sample/json/1/3?qparam=2
and returns the following result{"tparam1":"1","tparam2":"3","qparam":"2"}
.
Required parameters should always be provided at the begining of the command
The following sample html
command defines a required bosy parameter bparam
and also an optional boolean parameter flag
.
Boolean parameters are always considered as optional and defaults to false
. To set them to true
, we should only add them to the command line.
Notice that this time, the method uses the POST
verb, and that the bparam
parameter will be sent as part of the request's body.
app.post('/html', function(req, res) {
var flag = req.query.flag;
res.writeHead(200, {'Content-Type': 'text/html' });
res.end("<div style='background-color: red;'>HTML output: Template Param: "+req.params.tparam+
" Flag: " + flag +"</div>");
},
{
id: 'sample_html',
name: 'html',
usage: 'html tparam qparam',
example: 'html tparam qparam',
doc: 'sample for a POST command getting a template param returning html',
params: {
"bparam" : {
"short": "b",
"type": "string",
"doc": "template param",
"style": "body",
"required": "true"
},
"flag" : {
"short": "f",
"type": "bool",
"doc": "some boolean flag",
"style": "query",
"required": "true"
},
}
}
);
- The following command:
sample html 1 -f
callsPOST /api/sample/html?flag=true
with a body{bparam: 1}
and returns the result<div style='background-color: red;'>HTML output: Template Param: 1 Flag: true</div>
. - The following command:
sample html 1
calls/api/sample/html
with a body{bparam: 1}
and returns the following result<div style='background-color: red;'>HTML output: Template Param: 1 Flag: undefined</div>
.
Commands that need any processing on the client side, are considered as advanced commands.
Such commands may be for example, commands that get json
and present charts, or the current log command that gets the results and make some further processing before displaying it to the user.
Advanced command will define a controller
attribute, in which a javascript file and a handler method name will be set.
The following sample handler
command, will get two parameters, and the returned result will be transfered to the handler
method in the /plugins/sample.js
file.
The controller.handler
attribute is optional and will override the default handler name which is the command name if defined.
app.get('/handler/:tparam', function(req, res) {
var tparam = req.params.tparam;
var qparam = req.query['qparam'];
var o = {tparam: tparam};
res.writeHead(200, {'Content-Type': 'application/json' });
res.end(JSON.stringify(o));
},
{
id: 'sample_handler',
name: 'handler',
usage: 'handler',
example: 'handler',
doc: 'sample for a GET command using external handler',
params: {
"tparam" : {
"short": "t",
"type": "string",
"doc": "template param",
"style": "template",
"required": "true"
}
},
controller: {
url: '../../plugins/sample.js',
handler: 'handler' // this is optional, the default will be the command name
}
}
);
The following is the /plugins/sample.js
file.
The anode.loadCss
and anode.addCss
are discussed later on in the Adding A Command Custom Style section.
console.info('sample handler loaded');
// the following 2 lines are possible. in this case, the css are defined on the server side
//anode.loadCss('plugins/sample.css');
//anode.addCss(".anode-sample {width: 300px;border: 1px solid gray;background-color: rgba(236, 255, 117, 0.60);padding: 4px;}")
// anode will always be in the global context in this stage as this script always loaded after anode is already initialized
this.handler = function(error, response){
if ($.query.get('debug')) debugger;
var args = response.args;
var context = response.context;
var url = context.url;
var env = context.env;
var command = context.command;
var data = response.data;
var progress = 0;
var intrvl = setInterval(function(){
response.promise.setProgress(progress);
if(progress==100) {
clearInterval(intrvl);
response.promise.resolve(
$("<div>").addClass('anode-sample').html(
'this is the client side plugin handler speaking.. got the following parametrs:' + JSON.stringify(args) +
'. got the following response: ' + JSON.stringify(data)));
}
progress+=10;
}, 200);
}
When the script is loaded, it is wrapped in a function and called with a call
method, providing the context object. All handlers will be added to this context when executing the wrapped code.
Since the script is loaded dynamically, you wan't be able to see it in the developer tools of Chrome/FireFox. One solution for this issue, is adding if ($.query.get('debug')) debugger;
statement to the begining of the method, and load the console with ?debug
at the query string. This will make the browser to stop at this line and allow you to debug it.
When the script is loaded, it is attached as the command execute method.
When the console calls this method, it will pass an error
and a response
object.
The response
object contains the following parameters:
args
- contains all arguments provided as part of the command line.data
- contains the data returned from the api call.promise
- an object that helps us manage the command response. This object contains the following methods:setProgress(percent)
- set a percentage indicator, use when the processing might be long and we would like to update the user on the progress that is made.resolve(res)
- used to end the command processing by passing the final result to the console. The result may be any string or html element.
context
- contains command execution related objects such asurl
- the url that was called .env
- a copy of the environment variable collection (so it won't be able to change it).command
- a copy of the command object if there's any need for details from it.
Try executing sample handler val
to see how it behaves.
If the controller needs any special stylesheet, it can do so in few ways
-
Use the
anode.loadCss(url)
command to load a css file and add it to the DOM. -
Use the
anode.addCss(style)
command to embed style classes. -
On the server side, use the
cssUrl
or thecss
attributes as can be seen in the sample file for thehtmlbcast
andhandler
commands.controller: { css: '.anode-sample-class{ background-color: green; }' }
controller: { url: '../../plugins/sample.js', cssUrl: '../../plugins/sample.css' }
Note: It is very important to namespace your css classes to avoid impact on other elements in the DOM. In the example above, the style is namespaced with the anode-sample
class.
Please type man plugins
for information about how to create your own remote management API and integrate it into the console.