You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ea...@apache.org on 2016/08/19 16:59:08 UTC
[01/11] qpid-dispatch git commit: DISPATCH-316 Hawtio and stand-alone
consoles now use common code
Repository: qpid-dispatch
Updated Branches:
refs/heads/master c9d14137d -> d98ae37ef
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/lib/rhea-min.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/lib/rhea-min.js b/console/stand-alone/plugin/lib/rhea-min.js
index f61579a..42ca130 100644
--- a/console/stand-alone/plugin/lib/rhea-min.js
+++ b/console/stand-alone/plugin/lib/rhea-min.js
@@ -1,93 +1,6 @@
-require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
-(function (process,Buffer){
-"use strict";function get_socket_id(t){return t.get_id_string?t.get_id_string():t.localAddress+":"+t.localPort+" -> "+t.remoteAddress+":"+t.remotePort}function session_per_connection(t){var e=null;return{get_session:function(){return e||(e=t.create_session(),e.begin()),e}}}function restrict(t,e){if(t){var o,n=t;return function(i){return o!==i&&(n=t,o=i),n--?e(i):-1}}return e}function backoff(t,e){var o,n=t;return function(i){o!==i&&(n=t,o=i);var s=n,r=2*n;return n=e>r?r:e,s}}function get_connect_fn(t){if(void 0===t.transport||"tcp"===t.transport)return net.connect;if("tls"===t.transport||"ssl"===t.transport)return tls.connect;throw Error("Unrecognised transport: "+t.transport)}function connection_details(t){var e={};return e.connect=t.connect?t.connect:get_connect_fn(t),e.host=t.host?t.host:"localhost",e.port=t.port?t.port:5672,e.options=t,e}function delegate_to_session(t){Connection.prototype["on_"+t]=function(e){var o=this.remote_channel_map[e.channel];if(!o)throw Error(t+" receiv
ed on invalid channel "+e.channel);o["on_"+t](e)}}var frames=require("./frames.js"),log=require("./log.js"),sasl=require("./sasl.js"),types=require("./types.js"),util=require("./util.js"),EndpointState=require("./endpoint.js"),Session=require("./session.js"),Transport=require("./transport.js"),net=require("net"),tls=require("tls"),EventEmitter=require("events").EventEmitter,AMQP_PROTOCOL_ID=0,TLS_PROTOCOL_ID=2,conn_counter=1,Connection=function(t,e){if(this.options={},t)for(var o in t)this.options[o]=t[o];if(this.container=e,this.options.id||(this.options.id="connection-"+conn_counter++),this.options.container_id||(this.options.container_id=e?e.id:util.generate_uuid()),!this.options.connection_details){var n=this;this.options.connection_details=function(){return connection_details(n.options)}}var i=this.get_option("reconnect",!0);if("boolean"==typeof i&&i){var s=this.get_option("initial_reconnect_delay",100),r=this.get_option("max_reconnect_delay",6e4);this.options.reconnect=restric
t(this.get_option("reconnect_limit"),backoff(s,r))}else if("number"==typeof i){var c=this.options.reconnect;this.options.reconnect=restrict(this.get_option("reconnect_limit"),function(){return c})}this.registered=!1,this.state=new EndpointState,this.local_channel_map={},this.remote_channel_map={},this.local={},this.remote={},this.local.open=frames.open(this.options),this.local.close=frames.close({}),this.session_policy=session_per_connection(this),this.amqp_transport=new Transport(this.options.id,AMQP_PROTOCOL_ID,frames.TYPE_AMQP,this),this.sasl_transport=void 0,this.transport=this.amqp_transport,this.conn_established_counter=0,this.heartbeat_out=void 0,this.heartbeat_in=void 0,this.abort_idle=!1,this.socket_ready=!1,this.scheduled_reconnect=void 0};Connection.prototype=Object.create(EventEmitter.prototype),Connection.prototype.constructor=Connection,Connection.prototype.dispatch=function(t,e){return log.events("Connection got event: "+t),this.listeners(t).length?(EventEmitter.proto
type.emit.apply(this,arguments),!0):this.container?this.container.dispatch.apply(this.container,arguments):void 0},Connection.prototype.reset=function(){this.abort_idle&&(this.abort_idle=!1,this.local.close.error=void 0,this.state=new EndpointState,this.state.open()),this.amqp_transport=new Transport(this.options.id,AMQP_PROTOCOL_ID,frames.TYPE_AMQP,this),this.sasl_transport=void 0,this.transport=this.amqp_transport,this.state.disconnected(),this.remote={},this.remote_channel_map={};for(var t in this.local_channel_map)this.local_channel_map[t].reset();this.socket_ready=!1},Connection.prototype.connect=function(){return this.is_server=!1,this._connect(this.options.connection_details(this.conn_established_counter)),this.open(),this},Connection.prototype.reconnect=function(){return this.scheduled_reconnect=void 0,log.reconnect("reconnecting..."),this.reset(),this._connect(this.options.connection_details(this.conn_established_counter)),process.nextTick(this._process.bind(this)),this},Co
nnection.prototype._connect=function(t){return t.connect?this.init(t.connect(t.port,t.host,t.options,this.connected.bind(this))):this.init(get_connect_fn(t)(t.port,t.host,t.options,this.connected.bind(this))),this},Connection.prototype.accept=function(t){return this.is_server=!0,log.io("["+this.id+"] client accepted: "+get_socket_id(t)),this.socket_ready=!0,this.init(t)},Connection.prototype.init=function(t){if(this.socket=t,this.socket.on("data",this.input.bind(this)),this.socket.on("error",this.error.bind(this)),this.socket.on("end",this.eof.bind(this)),this.is_server){var e;this.container&&Object.getOwnPropertyNames(this.container.sasl_server_mechanisms).length&&(e=this.container.sasl_server_mechanisms),this.socket.encrypted&&this.socket.authorized&&this.get_option("enable_sasl_external",!1)&&(e=sasl.server_add_external(e?util.clone(e):{})),e&&(this.sasl_transport=new sasl.Server(this,e))}else{var o=this.get_option("sasl_mechanisms");if(!o){var n=this.get_option("username"),i=thi
s.get_option("password");n&&(o=sasl.client_mechanisms(),i?o.enable_plain(n,i):o.enable_anonymous(n))}this.socket.encrypted&&this.options.cert&&this.get_option("enable_sasl_external",!1)&&(o||(o=sasl.client_mechanisms()),o.enable_external()),o&&(this.sasl_transport=new sasl.Client(this,o))}return this.transport=this.sasl_transport?this.sasl_transport:this.amqp_transport,this},Connection.prototype.attach_sender=function(t){return this.session_policy.get_session().attach_sender(t)},Connection.prototype.open_sender=Connection.prototype.attach_sender,Connection.prototype.attach_receiver=function(t){return this.session_policy.get_session().attach_receiver(t)},Connection.prototype.open_receiver=Connection.prototype.attach_receiver,Connection.prototype.get_option=function(t,e){return void 0!==this.options[t]?this.options[t]:this.container?this.container.get_option(t,e):e},Connection.prototype.connected=function(){this.socket_ready=!0,this.conn_established_counter++,log.io("["+this.options.i
d+"] connected "+get_socket_id(this.socket)),this.output()},Connection.prototype.sasl_failed=function(t){this.transport_error={condition:"amqp:unauthorized-access",description:t},this._handle_error()},Connection.prototype._handle_error=function(){var t=this.get_error();return t?(this.dispatch("connection_error",this._context())||this.dispatch("connection_close",this._context())||console.log("error: "+JSON.stringify(t)),!0):!1},Connection.prototype.get_error=function(){return this.transport_error?this.transport_error:this.remote.close&&this.remote.close.error?this.remote.close.error:void 0},Connection.prototype.output=function(){this.socket&&this.socket_ready&&(this.heartbeat_out&&clearTimeout(this.heartbeat_out),this.transport.write(this.socket),(this.is_closed()&&this.state.has_settled()||this.abort_idle||this.transport_error)&&!this.transport.has_writes_pending()?this.socket.end():this.is_open()&&this.remote.open.idle_time_out&&(this.heartbeat_out=setTimeout(this._write_frame.bind
(this),this.remote.open.idle_time_out/2)))},Connection.prototype.input=function(t){this.heartbeat_in&&clearTimeout(this.heartbeat_in),log.io("["+this.options.id+"] read "+t.length+" bytes");var e;this.previous_input?(e=Buffer.concat([this.previous_input,t],this.previous_input.length+t.length),this.previous_input=null):e=t;var o=this.transport.read(e,this);o<e.length&&(this.previous_input=e.slice(o)),this.local.open.idle_time_out&&(this.heartbeat_in=setTimeout(this.idle.bind(this),this.local.open.idle_time_out)),this.transport.has_writes_pending()&&this.output()},Connection.prototype.idle=function(){this.is_open()&&(this.abort_idle=!0,this.local.close.error={condition:"amqp:resource-limit-exceeded",description:"max idle time exceeded"},this.close())},Connection.prototype.error=function(t){console.log("["+this.options.id+"] error: "+t),this._disconnected()},Connection.prototype.eof=function(t){this._disconnected()},Connection.prototype._disconnected=function(){if(!this.is_closed()&&vo
id 0==this.scheduled_reconnect&&(this.dispatch("disconnected",this._context())||console.log("["+this.options.id+"] disconnected"),!this.is_server&&!this.transport_error&&this.options.reconnect)){var t=this.options.reconnect(this.conn_established_counter);t>=0&&(log.reconnect("Scheduled reconnect in "+t+"ms"),this.scheduled_reconnect=setTimeout(this.reconnect.bind(this),t))}},Connection.prototype.open=function(){this.state.open()&&this._register()},Connection.prototype.close=function(){this.state.close()&&this._register()},Connection.prototype.is_open=function(){return this.state.is_open()},Connection.prototype.is_closed=function(){return this.state.is_closed()},Connection.prototype.create_session=function(){for(var t=0;this.local_channel_map[t];)t++;var e=new Session(this,t);return this.local_channel_map[t]=e,e},Connection.prototype.on_open=function(t){if(!this.state.remote_opened())throw Error("Open already received");this.remote.open=t.performative,this.open(),this.dispatch("conne
ction_open",this._context())},Connection.prototype.on_close=function(t){if(!this.state.remote_closed())throw Error("Close already received");this.remote.close=t.performative,this.close(),this.remote.close.error?this._handle_error():this.dispatch("connection_close",this._context()),this.heartbeat_out&&clearTimeout(this.heartbeat_out)},Connection.prototype._register=function(){this.registered||(this.registered=!0,process.nextTick(this._process.bind(this)))},Connection.prototype._process=function(){this.registered=!1;do{this.state.need_open()&&this._write_open();for(var t in this.local_channel_map)this.local_channel_map[t]._process();this.state.need_close()&&this._write_close()}while(!this.state.has_settled())},Connection.prototype._write_frame=function(t,e,o){this.amqp_transport.encode(frames.amqp_frame(t,e,o)),this.output()},Connection.prototype._write_open=function(){this._write_frame(0,this.local.open.described())},Connection.prototype._write_close=function(){this._write_frame(0,th
is.local.close.described())},Connection.prototype.on_begin=function(t){var e;if(null===t.performative.remote_channel||void 0===t.performative.remote_channel)e=this.create_session(),e.local.begin.remote_channel=t.channel;else if(e=this.local_channel_map[t.performative.remote_channel],!e)throw Error("Invalid value for remote channel "+t.performative.remote_channel);e.on_begin(t),this.remote_channel_map[t.channel]=e},Connection.prototype.get_peer_certificate=function(){return this.socket&&this.socket.getPeerCertificate?this.socket.getPeerCertificate():void 0},Connection.prototype._context=function(t){var e=t?t:{};return e.connection=this,this.container&&(e.container=this.container),e},delegate_to_session("end"),delegate_to_session("attach"),delegate_to_session("detach"),delegate_to_session("transfer"),delegate_to_session("disposition"),delegate_to_session("flow"),module.exports=Connection;
-}).call(this,require('_process'),require("buffer").Buffer)
-
-},{"./endpoint.js":2,"./frames.js":3,"./log.js":5,"./sasl.js":8,"./session.js":9,"./transport.js":11,"./types.js":12,"./util.js":13,"_process":24,"buffer":19,"events":23,"net":18,"tls":18}],2:[function(require,module,exports){
-"use strict";var EndpointState=function(){this.init()};EndpointState.prototype.init=function(){this.local_open=!1,this.remote_open=!1,this.open_requests=0,this.close_requests=0,this.initialised=!1},EndpointState.prototype.open=function(){return this.initialised=!0,this.local_open?!1:(this.local_open=!0,this.open_requests++,!0)},EndpointState.prototype.close=function(){return this.local_open?(this.local_open=!1,this.close_requests++,!0):!1},EndpointState.prototype.disconnected=function(){var t=this.local_open;this.init(),t?this.open():this.close()},EndpointState.prototype.remote_opened=function(t){return this.remote_open?!1:(this.remote_open=!0,!0)},EndpointState.prototype.remote_closed=function(t){return this.remote_open?(this.remote_open=!1,!0):!1},EndpointState.prototype.is_open=function(){return this.local_open&&this.remote_open},EndpointState.prototype.is_closed=function(){return this.initialised&&!this.local_open&&!this.remote_open},EndpointState.prototype.has_settled=function(
){return 0==this.open_requests&&0==this.close_requests},EndpointState.prototype.need_open=function(){return this.open_requests>0?(this.open_requests--,!0):!1},EndpointState.prototype.need_close=function(){return this.close_requests>0?(this.close_requests--,!0):!1},module.exports=EndpointState;
-},{}],3:[function(require,module,exports){
-"use strict";function define_frame(e,a){var t=types.define_composite(a);frames[a.name]=t.create,by_descriptor[Number(t.descriptor.numeric).toString(10)]=t,by_descriptor[t.descriptor.symbolic]=t}var types=require("./types.js"),frames={},by_descriptor={};frames.read_header=function(e){var a=4,t={},n=e.toString("ascii",0,a);if("AMQP"!==n)throw Error("Invalid protocol header for AMQP "+n);if(t.protocol_id=e.readUInt8(a++),t.major=e.readUInt8(a++),t.minor=e.readUInt8(a++),t.revision=e.readUInt8(a++),1!==t.major||0!==t.minor)throw Error("Unsupported AMQP version: "+JSON.stringify(t));return t},frames.write_header=function(e,a){var t=4;return e.write("AMQP",0,t,"ascii"),e.writeUInt8(a.protocol_id,t++),e.writeUInt8(a.major,t++),e.writeUInt8(a.minor,t++),e.writeUInt8(a.revision,t++),8},frames.TYPE_AMQP=0,frames.TYPE_SASL=1,frames.read_frame=function(e){var a=new types.Reader(e),t={};if(t.size=a.read_uint(4),a.remaining<t.size)return null;var n=a.read_uint(1);if(2>n)throw Error("Invalid data
offset, must be at least 2 was "+n);if(t.type=a.read_uint(1),t.type===frames.TYPE_AMQP)t.channel=a.read_uint(2);else{if(t.type!==frames.TYPE_SASL)throw Error("Unknown frame type "+t.type);a.skip(2)}if(n>1&&a.skip(4*n-8),a.remaining()){t.performative=a.read();var r=by_descriptor[t.performative.descriptor.value];r&&(t.performative=new r(t.performative.value)),a.remaining()&&(t.payload=a.read_bytes(a.remaining()))}return t},frames.write_frame=function(e){var a=new types.Writer;if(a.skip(4),a.write_uint(2,1),a.write_uint(e.type,1),e.type===frames.TYPE_AMQP)a.write_uint(e.channel,2);else{if(e.type!==frames.TYPE_SASL)throw Error("Unknown frame type "+e.type);a.write_uint(0,2)}e.performative&&(a.write(e.performative),e.payload&&a.write_bytes(e.payload));var t=a.toBuffer();return t.writeUInt32BE(t.length,0),t},frames.amqp_frame=function(e,a,t){return{channel:e||0,type:frames.TYPE_AMQP,performative:a,payload:t}},frames.sasl_frame=function(e){return{channel:0,type:frames.TYPE_SASL,performativ
e:e}};var open={name:"open",code:16,fields:[{name:"container_id",type:"string",mandatory:!0},{name:"hostname",type:"string"},{name:"max_frame_size",type:"uint",default_value:4294967295},{name:"channel_max",type:"ushort",default_value:65535},{name:"idle_time_out",type:"uint"},{name:"outgoing_locales",type:"symbol",multiple:!0},{name:"incoming_locales",type:"symbol",multiple:!0},{name:"offered_capabilities",type:"symbol",multiple:!0},{name:"desired_capabilities",type:"symbol",multiple:!0},{name:"properties",type:"symbolic_map"}]},begin={name:"begin",code:17,fields:[{name:"remote_channel",type:"ushort"},{name:"next_outgoing_id",type:"uint",mandatory:!0},{name:"incoming_window",type:"uint",mandatory:!0},{name:"outgoing_window",type:"uint",mandatory:!0},{name:"handle_max",type:"uint",default_value:"4294967295"},{name:"offered_capabilities",type:"symbol",multiple:!0},{name:"desired_capabilities",type:"symbol",multiple:!0},{name:"properties",type:"symbolic_map"}]},attach={name:"attach",cod
e:18,fields:[{name:"name",type:"string",mandatory:!0},{name:"handle",type:"uint",mandatory:!0},{name:"role",type:"boolean",mandatory:!0},{name:"snd_settle_mode",type:"ubyte",default_value:2},{name:"rcv_settle_mode",type:"ubyte",default_value:0},{name:"source",type:"*"},{name:"target",type:"*"},{name:"unsettled",type:"map"},{name:"incomplete_unsettled",type:"boolean",default_value:!1},{name:"initial_delivery_count",type:"uint"},{name:"max_message_size",type:"ulong"},{name:"offered_capabilities",type:"symbol",multiple:!0},{name:"desired_capabilities",type:"symbol",multiple:!0},{name:"properties",type:"symbolic_map"}]},flow={name:"flow",code:19,fields:[{name:"next_incoming_id",type:"uint"},{name:"incoming_window",type:"uint",mandatory:!0},{name:"next_outgoing_id",type:"uint",mandatory:!0},{name:"outgoing_window",type:"uint",mandatory:!0},{name:"handle",type:"uint"},{name:"delivery_count",type:"uint"},{name:"link_credit",type:"uint"},{name:"available",type:"uint"},{name:"drain",type:"bo
olean",default_value:!1},{name:"echo",type:"boolean",default_value:!1},{name:"properties",type:"symbolic_map"}]},transfer={name:"transfer",code:20,fields:[{name:"handle",type:"uint",mandatory:!0},{name:"delivery_id",type:"uint"},{name:"delivery_tag",type:"binary"},{name:"message_format",type:"uint"},{name:"settled",type:"boolean"},{name:"more",type:"boolean",default_value:!1},{name:"rcv_settle_mode",type:"ubyte"},{name:"state",type:"delivery_state"},{name:"resume",type:"boolean",default_value:!1},{name:"aborted",type:"boolean",default_value:!1},{name:"batchable",type:"boolean",default_value:!1}]},disposition={name:"disposition",code:21,fields:[{name:"role",type:"boolean",mandatory:!0},{name:"first",type:"uint",mandatory:!0},{name:"last",type:"uint"},{name:"settled",type:"boolean",default_value:!1},{name:"state",type:"*"},{name:"batchable",type:"boolean",default_value:!1}]},detach={name:"detach",code:22,fields:[{name:"handle",type:"uint",mandatory:!0},{name:"closed",type:"boolean",de
fault_value:!1},{name:"error",type:"error"}]},end={name:"end",code:23,fields:[{name:"error",type:"error"}]},close={name:"close",code:24,fields:[{name:"error",type:"error"}]};define_frame(frames.TYPE_AMQP,open),define_frame(frames.TYPE_AMQP,begin),define_frame(frames.TYPE_AMQP,attach),define_frame(frames.TYPE_AMQP,flow),define_frame(frames.TYPE_AMQP,transfer),define_frame(frames.TYPE_AMQP,disposition),define_frame(frames.TYPE_AMQP,detach),define_frame(frames.TYPE_AMQP,end),define_frame(frames.TYPE_AMQP,close);var sasl_mechanisms={name:"sasl_mechanisms",code:64,fields:[{name:"sasl_server_mechanisms",type:"symbol",multiple:!0,mandatory:!0}]},sasl_init={name:"sasl_init",code:65,fields:[{name:"mechanism",type:"symbol",mandatory:!0},{name:"initial_response",type:"binary"},{name:"hostname",type:"string"}]},sasl_challenge={name:"sasl_challenge",code:66,fields:[{name:"challenge",type:"binary",mandatory:!0}]},sasl_response={name:"sasl_response",code:67,fields:[{name:"response",type:"binary",m
andatory:!0}]},sasl_outcome={name:"sasl_outcome",code:68,fields:[{name:"code",type:"ubyte",mandatory:!0},{name:"additional_data",type:"binary"}]};define_frame(frames.TYPE_SASL,sasl_mechanisms),define_frame(frames.TYPE_SASL,sasl_init),define_frame(frames.TYPE_SASL,sasl_challenge),define_frame(frames.TYPE_SASL,sasl_response),define_frame(frames.TYPE_SASL,sasl_outcome),module.exports=frames;
-},{"./types.js":12}],4:[function(require,module,exports){
-"use strict";function auto_settle(e){e.delivery.settled=!0}function auto_accept(e){e.delivery.update(!0,message.accepted().described())}function is_internal(e){switch(e){case"handle":case"role":case"initial_delivery_count":return!0;default:return!1}}var frames=require("./frames.js"),log=require("./log.js"),message=require("./message.js"),terminus=require("./terminus.js"),types=require("./types.js"),EndpointState=require("./endpoint.js"),FlowController=function(e){this.window=e};FlowController.prototype.update=function(e){var t=this.window-e.receiver.credit;e.receiver.flow(t)};var EventEmitter=require("events").EventEmitter,link=Object.create(EventEmitter.prototype);link.dispatch=function(e,t){log.events("Link got event: "+e),EventEmitter.prototype.emit.apply(this.observers,arguments),this.listeners(e).length?EventEmitter.prototype.emit.apply(this,arguments):this.session.dispatch.apply(this.session,arguments)},link.set_source=function(e){this.local.attach.source=terminus.source(e).de
scribed()},link.set_target=function(e){this.local.attach.target=terminus.target(e).described()},link.attach=function(){this.state.open()&&this.connection._register()},link.open=link.attach,link.detach=function(){this.local.detach.closed=!1,this.state.close()&&this.connection._register()},link.close=function(){this.local.detach.closed=!0,this.state.close()&&this.connection._register()},link.is_open=function(){return this.session.is_open()&&this.state.is_open()},link.is_closed=function(){return this.session.is_closed()||this.state.is_closed()},link._process=function(){do this.state.need_open()&&this.session.output(this.local.attach.described()),this.issue_flow&&(this.session._write_flow(this),this.issue_flow=!1),this.state.need_close()&&this.session.output(this.local.detach.described());while(!this.state.has_settled())},link.on_attach=function(e){if(!this.state.remote_opened())throw Error("Attach already received");this.remote.handle||(this.remote.handle=e.handle),e.performative.sourc
e=terminus.unwrap(e.performative.source),e.performative.target=terminus.unwrap(e.performative.target),this.remote.attach=e.performative,this.open(),this.dispatch(this.is_receiver()?"receiver_open":"sender_open",this._context())},link.on_detach=function(e){if(!this.state.remote_closed())throw Error("Detach already received");this.remote.detach=e.performative,this.close(),this.dispatch(this.local.attach.role?"receiver_close":"sender_close",this._context())},link.init=function(e,t,i,s,n){this.session=e,this.connection=e.connection,this.name=t,this.options=void 0===s?{}:s,this.state=new EndpointState,this.issue_flow=!1,this.local={handle:i},this.local.attach=frames.attach({handle:i,name:t,role:n});for(var o in this.local.attach)is_internal(o)||void 0===this.options[o]||(this.local.attach[o]=this.options[o]);this.local.detach=frames.detach({handle:i,closed:!0}),this.remote={handle:void 0},this.delivery_count=0,this.credit=0,this.observers=new EventEmitter},link.reset=function(){this.stat
e.disconnected(),this.remote={handle:void 0},this.delivery_count=0,this.credit=0},link.has_credit=function(){return this.credit>0},link.is_receiver=function(){return this.local.attach.role},link._context=function(e){var t=e?e:{};return this.is_receiver()?t.receiver=this:t.sender=this,this.session._context(t)},link.get_option=function(e,t){return void 0!==this.options[e]?this.options[e]:this.session.get_option(e,t)};var Sender=function(e,t,i,s){this.init(e,t,i,s,!1),this.local.attach.initial_delivery_count=0,this.tag=0,this.get_option("autosettle",!0)&&this.observers.on("settled",auto_settle)};Sender.prototype=Object.create(link),Sender.prototype.constructor=Sender,Sender.prototype.next_tag=function(){return new String(this.tag++)},Sender.prototype.sendable=function(e){return this.credit&&this.session.outgoing.available()},Sender.prototype.on_flow=function(e){var t=e.performative;this.credit=t.delivery_count+t.link_credit-this.delivery_count,this.is_open()&&(this.dispatch("sender_flo
w",this._context()),this.sendable()&&this.dispatch("sendable",this._context()))},Sender.prototype.on_transfer=function(e){throw Error("got transfer on sending link")},Sender.prototype.send=function(e,t){return this.session.send(this,t?t:this.next_tag(),message.encode(e),0)};var Receiver=function(e,t,i,s){this.init(e,t,i,s,!0),this.set_prefetch(this.get_option("prefetch",100)),this.get_option("autoaccept",!0)&&this.observers.on("message",auto_accept)};Receiver.prototype=Object.create(link),Receiver.prototype.constructor=Receiver,Receiver.prototype.on_flow=function(e){this.dispatch("receiver_flow",this._context())},Receiver.prototype.flow=function(e){e>0&&(this.credit+=e,this.issue_flow=!0,this.connection._register())},Receiver.prototype.set_prefetch=function(e){if(e>0){var t=new FlowController(e),i=t.update.bind(t);this.observers.on("message",i),this.observers.on("receiver_open",i)}},module.exports={Sender:Sender,Receiver:Receiver};
-},{"./endpoint.js":2,"./frames.js":3,"./log.js":5,"./message.js":6,"./terminus.js":10,"./types.js":12,"events":23}],5:[function(require,module,exports){
-"use strict";var debug=require("debug");module.exports={frames:debug("rhea:frames"),raw:debug("rhea:raw"),reconnect:debug("rhea:reconnect"),events:debug("rhea:events"),message:debug("rhea:message"),flow:debug("rhea:flow"),io:debug("rhea:io")};
-},{"debug":15}],6:[function(require,module,exports){
-"use strict";function define_section(e,n,t){n.descriptor=e,unwrappers[e.symbolic]=n,unwrappers[Number(e.numeric).toString(10)]=n,t&&wrappers.push(t)}function define_composite_section(e){var n=types.define_composite(e);message[e.name]=n.create,by_descriptor[Number(n.descriptor.numeric).toString(10)]=n,by_descriptor[n.descriptor.symbolic]=n;var t=function(t,o){t[e.name]=new n(o.value)},o=function(t,o){o[e.name]&&(o[e.name].described?t.push(o[e.name].described()):t.push(n.create(o[e.name]).described()))};define_section(n.descriptor,t,o)}function define_map_section(e){var n={numeric:e.code};n.symbolic="amqp:"+e.name.replace(/_/g,"-")+":map";var t=function(n,t){n[e.name]=types.unwrap(t)},o=function(t,o){o[e.name]&&t.push(types.described(types.wrap_ulong(n.numeric),types.wrap_map(o[e.name])))};define_section(n,t,o)}function define_outcome(e){var n=types.define_composite(e);n.composite_type=e.name,message[e.name]=n.create,outcomes[Number(n.descriptor.numeric).toString(10)]=n,outcomes[n.des
criptor.symbolic]=n,message["is_"+e.name]=function(n){if(n&&n.descriptor){var t=outcomes[n.descriptor.value];if(t)return t.descriptor.numeric==e.code}return!1}}var log=require("./log.js"),types=require("./types.js"),by_descriptor={},unwrappers={},wrappers=[],message={};define_composite_section({name:"header",code:112,fields:[{name:"durable",type:"boolean",default_value:!1},{name:"priority",type:"ubyte",default_value:4},{name:"ttl",type:"uint"},{name:"first_acquirer",type:"boolean",default_value:!1},{name:"delivery_count",type:"uint",default_value:0}]}),define_map_section({name:"delivery_annotations",code:113}),define_map_section({name:"message_annotations",code:114}),define_composite_section({name:"properties",code:115,fields:[{name:"message_id",type:"message_id"},{name:"user_id",type:"binary"},{name:"to",type:"string"},{name:"subject",type:"string"},{name:"reply_to",type:"string"},{name:"correlation_id",type:"message_id"},{name:"content_type",type:"symbol"},{name:"content_encoding"
,type:"symbol"},{name:"absolute_expiry_time",type:"timestamp"},{name:"creation_time",type:"timestamp"},{name:"group_id",type:"string"},{name:"group_sequence",type:"uint"},{name:"reply_to_group_id",type:"string"}]}),define_map_section({name:"application_properties",code:116}),define_section({numeric:119,symbolic:"amqp:value:*"},function(e,n){e.body=types.unwrap(n)},function(e,n){e.push(types.described(types.wrap_ulong(119),types.wrap(n.body)))}),define_map_section({name:"footer",code:120}),message.encode=function(e){var n=[];wrappers.forEach(function(t){t(n,e)});for(var t=new types.Writer,o=0;o<n.length;o++)log.message("Encoding section "+(o+1)+" of "+n.length+": "+n[o]),t.write(n[o]);var i=t.toBuffer();return log.message("encoded "+i.length+" bytes"),i},message.decode=function(e){for(var n={},t=new types.Reader(e);t.remaining();){var o=t.read();if(log.message("decoding section: "+JSON.stringify(o)+" of type: "+JSON.stringify(o.descriptor)),o.descriptor){var i=unwrappers[o.descriptor
.value];i?i(n,o):console.log("WARNING: did not recognise message section with descriptor "+o.descriptor)}else console.log("WARNING: expected described message section got "+JSON.stringify(o))}return n};var outcomes={};message.unwrap_outcome=function(e){if(e&&e.descriptor){var n=outcomes[e.descriptor.value];if(n)return new n(e)}return console.log("unrecognised outcome"),e},message.are_outcomes_equivalent=function(e,n){return void 0===e&&void 0===n?!0:void 0===e||void 0===n?!1:e.descriptor.value==n.descriptor.value&&JSON.stringify(e)==JSON.stringify(n)},define_outcome({name:"received",code:35,fields:[{name:"section-number",type:"uint",mandatory:!0},{name:"section-offset",type:"ulong",mandatory:!0}]}),define_outcome({name:"accepted",code:36,fields:[]}),define_outcome({name:"rejected",code:37,fields:[{name:"error",type:"error"}]}),define_outcome({name:"released",code:38,fields:[]}),define_outcome({name:"modified",code:39,fields:[{name:"delivery-failed",type:"boolean"},{name:"undeliverab
le-here",type:"boolean"},{name:"message-annotations",type:"fields"}]}),module.exports=message;
-},{"./log.js":5,"./types.js":12}],7:[function(require,module,exports){
-"use strict";function match(e,t){return t?Array.isArray(t)?t.indexOf(e)>-1:e===t:!1}var url=require("url"),simple_id_generator={counter:1,next:function(){return this.counter++}},Client=function(e,t){var i=url.parse(t);this.connection=e.connect({host:i.hostname,port:i.port}),this.connection.on("message",this._response.bind(this)),this.connection.on("receiver_open",this._ready.bind(this)),this.sender=this.connection.attach_sender(i.path.substr(1)),this.receiver=this.connection.attach_receiver({source:{dynamic:!0}}),this.id_generator=simple_id_generator,this.pending=[],this.outstanding={}};Client.prototype._request=function(e,t,i,n){var s={properties:{}};s.properties.subject=t,s.body=i,s.properties.message_id=e,s.properties.reply_to=this.receiver.remote.attach.source.address,this.outstanding[e]=n,this.sender.send(s)},Client.prototype._response=function(e){var t=e.message.properties.correlation_id,i=this.outstanding[t];i?"ok"===e.message.properties.subject?i(e.message.body):i(void 0,{na
me:e.message.properties.subject,description:e.message.body}):console.log("no request pending for "+t+", ignoring response")},Client.prototype._ready=function(e){this._process_pending()},Client.prototype._process_pending=function(){for(var e=0;e<this.pending.length;e++){var t=this.pending[e];this._request(t.id,t.name,t.args,t.callback)}this.pending=[]},Client.prototype.call=function(e,t,i){var n=this.id_generator.next();this.receiver.is_open()&&0===this.pending.length?this._request(n,e,t,i):this.pending.push({name:e,args:t,callback:i,id:n})},Client.prototype.close=function(){this.receiver.close(),this.sender.close(),this.connection.close()},Client.prototype.define=function(e){this[e]=function(t,i){this.call(e,t,i)}};var Cache=function(e,t){this.ttl=e,this.purged=t,this.entries={},this.timeout=void 0};Cache.prototype.clear=function(){this.timeout&&clearTimeout(this.timeout),this.entries={}},Cache.prototype.put=function(e,t){this.entries[e]={value:t,last_accessed:Date.now()},this.timeo
ut||(this.timeout=setTimeout(this.purge.bind(this),this.ttl))},Cache.prototype.get=function(e){var t=this.entries[e];return t?(t.last_accessed=Date.now(),t.value):void 0},Cache.prototype.purge=function(){var e=Date.now(),t=[],i=0;for(var n in this.entries)e-this.entries[n].last_accessed>=this.ttl?t.push(n):i++;for(var s=0;s<t.length;s++){var o=this.entries[t[s]];delete this.entries[t[s]],this.purged(o.value)}i&&!this.timeout&&(this.timeout=setTimeout(this.purge.bind(this),this.ttl))};var LinkCache=function(e,t){this.factory=e,this.cache=new Cache(t,function(e){e.close()})};LinkCache.prototype.clear=function(){this.cache.clear()},LinkCache.prototype.get=function(e){var t=this.cache.get(e);return void 0===t&&(t=this.factory(e),this.cache.put(e,t)),t};var Server=function(e,t,i){this.options=i||{};var n=url.parse(t);this.connection=e.connect({host:n.hostname,port:n.port}),this.connection.on("connection_open",this._connection_open.bind(this)),this.connection.on("message",this._request.bi
nd(this)),this.receiver=this.connection.attach_receiver(n.path.substr(1)),this.callbacks={},this._send=void 0,this._clear=void 0};Server.prototype._connection_open=function(e){if(match("ANONYMOUS-RELAY",this.connection.remote.open.offered_capabilities)){var t=this.connection.attach_sender({target:{}});this._send=function(e){t.send(e)}}else{var i=new LinkCache(this.connection.attach_sender.bind(this.connection),this.options.cache_ttl||6e4);this._send=function(e){var t=i.get(e.properties.to);t&&t.send(e)},this._clear=function(){i.clear()}}},Server.prototype._respond=function(e){var t=this;return function(i,n){n?(e.properties.subject=n.name||"error",e.body=n.description||n):(e.properties.subject="ok",e.body=i),t._send(e)}},Server.prototype._request=function(e){var t=e.message,i={properties:{}};i.properties.to=t.properties.reply_to,i.properties.correlation_id=t.properties.message_id;var n=this.callbacks[t.properties.subject];n?n(t.body,this._respond(i)):(i.properties.subject="bad-method
",i.body="Unrecognised method "+t.properties.subject,this._send(i))},Server.prototype.bind_sync=function(e,t){this.callbacks[t||e.name]=function(t,i){var n=e(t);i(n)}},Server.prototype.bind=function(e,t){this.callbacks[t||e.name]=e},Server.prototype.close=function(){this._clear&&this._clear(),this.receiver.close(),this.connection.close()},module.exports={server:function(e,t,i){return new Server(e,t,i)},client:function(e,t){return new Client(e,t)}};
-},{"url":29}],8:[function(require,module,exports){
-(function (Buffer){
-"use strict";function intersection(e,t){return e.filter(function(e){return t.indexOf(e)>=0})}function extract(e){for(var t=[],s=0,n=0;n<e.length;)0===e[n]?(n>s?t.push(e.toString("utf8",s,n)):t.push(null),s=++n):++n;return n>s?t.push(e.toString("utf8",s,n)):t.push(null),t}var frames=require("./frames.js"),log=require("./log.js"),Transport=require("./transport.js"),sasl_codes={OK:0,AUTH:1,SYS:2,SYS_PERM:3,SYS_TEMP:4},SASL_PROTOCOL_ID=3,PlainServer=function(e){this.callback=e,this.outcome=void 0,this.username=void 0};PlainServer.prototype.start=function(e){var t=extract(e);3!==t.length&&this.connection.sasl_failed("Unexpected response in PLAIN, got "+t.length+" fields, expected 3"),this.callback(t[1],t[2])?(this.outcome=!0,this.username=t[1]):this.outcome=!1};var PlainClient=function(e,t){this.username=e,this.password=t};PlainClient.prototype.start=function(){var e=new Buffer(1+this.username.length+1+this.password.length);return e.writeUInt8(0,0),e.write(this.username,1),e.writeUInt8(0
,1+this.username.length),e.write(this.password,1+this.username.length+1),e};var AnonymousServer=function(){this.outcome=void 0,this.username=void 0};AnonymousServer.prototype.start=function(e){this.outcome=!0,this.username=e?e.toString("utf8"):"anonymous"};var AnonymousClient=function(e){this.username=e?e:"anonymous"};AnonymousClient.prototype.start=function(){var e=new Buffer(1+this.username.length);return e.writeUInt8(0,0),e.write(this.username,1),e};var ExternalServer=function(){this.outcome=void 0,this.username=void 0};ExternalServer.prototype.start=function(e){this.outcome=!0};var ExternalClient=function(){this.username=void 0};ExternalClient.prototype.start=function(){return null};var SaslServer=function(e,t){this.connection=e,this.transport=new Transport(e.amqp_transport.identifier,SASL_PROTOCOL_ID,frames.TYPE_SASL,this),this.next=e.amqp_transport,this.mechanisms=t,this.mechanism=void 0,this.outcome=void 0,this.username=void 0;var s=Object.getOwnPropertyNames(t);this.transpor
t.encode(frames.sasl_frame(frames.sasl_mechanisms({sasl_server_mechanisms:s}).described()))};SaslServer.prototype.do_step=function(e){void 0===this.mechanism.outcome?this.transport.encode(frames.sasl_frame(frames.sasl_challenge({challenge:e}).described())):(this.outcome=this.mechanism.outcome?sasl_codes.OK:sasl_codes.AUTH,this.transport.encode(frames.sasl_frame(frames.sasl_outcome({code:this.outcome}).described())),this.outcome===sasl_codes.OK&&(this.username=this.mechanism.username,this.transport.write_complete=!0,this.transport.read_complete=!0))},SaslServer.prototype.on_sasl_init=function(e){var t=this.mechanisms[e.performative.mechanism];if(t){this.mechanism=t();var s=this.mechanism.start(e.performative.initial_response);this.do_step(s)}else this.outcome=sasl_codes.AUTH,this.transport.encode(frames.sasl_frame(frames.sasl_outcome({code:this.outcome}).described()))},SaslServer.prototype.on_sasl_response=function(e){this.do_step(this.mechanism.step(e.performative.response))},SaslSe
rver.prototype.has_writes_pending=function(){return this.transport.has_writes_pending()||this.next.has_writes_pending()},SaslServer.prototype.write=function(e){return this.transport.write_complete&&0===this.transport.pending.length?this.next.write(e):this.transport.write(e)},SaslServer.prototype.read=function(e){return this.transport.read_complete?this.next.read(e):this.transport.read(e)};var SaslClient=function(e,t){this.connection=e,this.transport=new Transport(e.amqp_transport.identifier,SASL_PROTOCOL_ID,frames.TYPE_SASL,this),this.next=e.amqp_transport,this.mechanisms=t,this.mechanism=void 0,this.mechanism_name=void 0,this.failed=!1};SaslClient.prototype.on_sasl_mechanisms=function(e){for(var t=0;void 0===this.mechanism&&t<e.performative.sasl_server_mechanisms.length;t++){var s=e.performative.sasl_server_mechanisms[t],n=this.mechanisms[s];n&&(this.mechanism=n(),this.mechanism_name=s)}if(this.mechanism){var r=this.mechanism.start();this.transport.encode(frames.sasl_frame(frames.s
asl_init({mechanism:this.mechanism_name,initial_response:r}).described()))}else this.failed=!0,this.connection.sasl_failed("No suitable mechanism; server supports "+e.performative.sasl_server_mechanisms)},SaslClient.prototype.on_sasl_challenge=function(e){var t=this.mechanism.step(e.performative.challenge);this.transport.encode(frames.sasl_frame(frames.sasl_response({response:t}).described()))},SaslClient.prototype.on_sasl_outcome=function(e){switch(e.performative.code){case sasl_codes.OK:this.transport.read_complete=!0,this.transport.write_complete=!0;break;default:this.transport.write_complete=!0,this.connection.sasl_failed("Failed to authenticate: "+e.performative.code)}},SaslClient.prototype.has_writes_pending=function(){return this.transport.has_writes_pending()||this.next.has_writes_pending()},SaslClient.prototype.write=function(e){return this.transport.write_complete?this.next.write(e):this.transport.write(e)},SaslClient.prototype.read=function(e){return this.transport.read_c
omplete?this.next.read(e):this.transport.read(e)};var default_server_mechanisms={enable_anonymous:function(){this.ANONYMOUS=function(){return new AnonymousServer}},enable_plain:function(e){this.PLAIN=function(){return new PlainServer(e)}}},default_client_mechanisms={enable_anonymous:function(e){this.ANONYMOUS=function(){return new AnonymousClient(e)}},enable_plain:function(e,t){this.PLAIN=function(){return new PlainClient(e,t)}},enable_external:function(){this.EXTERNAL=function(){return new ExternalClient}}};module.exports={Client:SaslClient,Server:SaslServer,server_mechanisms:function(){return Object.create(default_server_mechanisms)},client_mechanisms:function(){return Object.create(default_client_mechanisms)},server_add_external:function(e){return e.EXTERNAL=function(){return new ExternalServer},e}};
-}).call(this,require("buffer").Buffer)
-
-},{"./frames.js":3,"./log.js":5,"./transport.js":11,"buffer":19}],9:[function(require,module,exports){
-(function (Buffer){
-"use strict";function attach(e,t,i){var o=t?t:{};"string"==typeof t&&(o={},o[i]=t),o.name||(o.name=util.generate_uuid());var n=e(o.name,o);for(var s in{source:0,target:0})o[s]&&("string"==typeof o[s]&&(o[s]={address:o[s]}),n["set_"+s](o[s]));return n.attach(),n}var frames=require("./frames.js"),link=require("./link.js"),log=require("./log.js"),message=require("./message.js"),types=require("./types.js"),util=require("./util.js"),EndpointState=require("./endpoint.js"),EventEmitter=require("events").EventEmitter,CircularBuffer=function(e){this.capacity=e,this.size=0,this.head=0,this.tail=0,this.entries=[]};CircularBuffer.prototype.available=function(){return this.capacity-this.size},CircularBuffer.prototype.push=function(e){if(!(this.size<this.capacity))throw Error("circular buffer overflow: head="+this.head+" tail="+this.tail+" size="+this.size+" capacity="+this.capacity);this.entries[this.tail]=e,this.tail=(this.tail+1)%this.capacity,this.size++},CircularBuffer.prototype.pop_if=funct
ion(e){for(var t=0;this.size&&e(this.entries[this.head]);)this.entries[this.head]=void 0,this.head=(this.head+1)%this.capacity,this.size--,t++;return t},CircularBuffer.prototype.by_id=function(e){if(this.size>0){var t=e-this.entries[this.head].id;if(t<this.size)return this.entries[(this.head+t)%this.capacity]}},CircularBuffer.prototype.get_head=function(e){return this.size>0?this.entries[this.head]:void 0};var Outgoing=function(){this.deliveries=new CircularBuffer(2048),this.updated=[],this.next_delivery_id=0,this.next_pending_delivery=0,this.next_transfer_id=0,this.window=types.MAX_UINT,this.remote_next_transfer_id=void 0,this.remote_window=void 0};Outgoing.prototype.available=function(){return this.deliveries.available()},Outgoing.prototype.send=function(e,t,i,o){var n={id:this.next_delivery_id++,tag:t,link:e,data:i,format:o?o:0,sent:!1,settled:!1,state:void 0,remote_settled:!1,remote_state:void 0};return this.deliveries.push(n),n},Outgoing.prototype.on_begin=function(e){this.remo
te_window=e.incoming_window},Outgoing.prototype.on_flow=function(e){this.remote_next_transfer_id=e.next_incoming_id,this.remote_window=e.incoming_window},Outgoing.prototype.on_disposition=function(e){for(var t=e.last?e.last:e.first,i=e.first;t>=i;i++){var o=this.deliveries.by_id(i);if(o||console.log("Could not find delivery for "+i+" ["+JSON.stringify(e)+"]"),o&&!o.remote_settled){var n=!1;e.settled&&(o.remote_settled=e.settled,n=!0),e.state&&e.state!==o.remote_state&&(o.remote_state=e.state,n=!0),n&&this.updated.push(o)}}},Outgoing.prototype.transfer_window=function(){return this.remote_window?this.remote_window-(this.next_transfer_id-this.remote_next_transfer_id):void 0},Outgoing.prototype.process=function(){for(;this.next_pending_delivery<this.next_delivery_id;){var e=this.deliveries.by_id(this.next_pending_delivery);if(!e){console.log("ERROR: Next pending delivery not found: "+this.next_pending_delivery);break}if(!e.link.has_credit()){log.flow("Link has no credit");break}if(e.li
nk.delivery_count++,e.transfers_required=1,!(this.transfer_window()>=e.transfers_required)){log.flow("Incoming window of peer preventing sending further transfers: remote_window="+this.remote_window+", remote_next_transfer_id="+this.remote_next_transfer_id+", next_transfer_id="+this.next_transfer_id);break}this.next_transfer_id+=e.transfers_required,this.window-=e.transfers_required,e.link.session.output(frames.transfer({handle:e.link.local.handle,message_format:e.format,delivery_id:e.id,delivery_tag:e.tag}).described(),e.data),e.link.credit--,this.next_pending_delivery++}for(var t=0;t<this.updated.length;t++){var e=this.updated[t];e.remote_state&&(e.remote_state=message.unwrap_outcome(e.remote_state),e.remote_state&&e.remote_state.constructor.composite_type&&e.link.dispatch(e.remote_state.constructor.composite_type,e.link._context({delivery:e}))),e.remote_settled&&e.link.dispatch("settled",e.link._context({delivery:e}))}this.updated=[],this.deliveries.pop_if(function(e){return e.se
ttled&&e.remote_settled})};var Incoming=function(){this.deliveries=new CircularBuffer(2048),this.updated=[],this.next_transfer_id=0,this.next_delivery_id=void 0,this.window=2048,this.remote_next_transfer_id=void 0,this.remote_window=void 0};Incoming.prototype.update=function(e,t,i){e&&(e.settled=t,void 0!==i&&(e.state=i),e.remote_settled||this.updated.push(e),e.link.connection._register())},Incoming.prototype.on_transfer=function(e,t){if(this.next_transfer_id++,t.is_open()){void 0===this.next_delivery_id&&(this.next_delivery_id=e.performative.delivery_id);var i,o,n=this.deliveries.get_head();if(n&&n.incomplete){if(void 0!==e.performative.delivery_id&&this.next_delivery_id!=e.performative.delivery_id)throw Error("frame sequence error: delivery "+this.next_delivery_id+" not complete, got "+e.performative.delivery_id);i=n,o=Buffer.concat([i.data,e.payload],i.data.size()+e.payload.size())}else{if(this.next_delivery_id!==e.performative.delivery_id)throw Error("frame sequence error: expec
ted "+this.next_delivery_id+", got "+e.performative.delivery_id);i={id:e.performative.delivery_id,tag:e.performative.delivery_tag,link:t,settled:!1,state:void 0,remote_settled:e.performative.settled,remote_state:void 0};var s=this;i.update=function(e,t){s.update(i,e,t)},this.deliveries.push(i),o=e.payload}i.incomplete=e.performative.more,i.incomplete?i.data=o:(t.credit--,t.delivery_count++,this.next_delivery_id++,t.dispatch("message",t._context({message:message.decode(o),delivery:i})))}},Incoming.prototype.process=function(){if(this.updated.length>0){for(var e,t,i,o=0;o<this.updated.length;o++){var n=this.updated[o];void 0===e&&(e=n,t=n,i=n.id),message.are_outcomes_equivalent(t.state,n.state)&&t.settled===n.settled&&i===n.id?(t.id!==n.id&&(t=n),i++):(e.link.session.output(frames.disposition({role:!0,first:e.id,last:t.id,state:e.state,settled:e.settled}).described()),e=n,t=n,i=n.id)}void 0!==e&&void 0!==t&&e.link.session.output(frames.disposition({role:!0,first:e.id,last:t.id,state:e
.state,settled:e.settled}).described()),this.updated=[]}this.deliveries.pop_if(function(e){return e.settled})},Incoming.prototype.on_begin=function(e){this.remote_window=e.outgoing_window},Incoming.prototype.on_flow=function(e){this.remote_next_transfer_id=e.next_outgoing_id,this.remote_window=e.outgoing_window},Incoming.prototype.on_disposition=function(e){for(var t=e.last?e.last:e.first,i=e.first;t>=i;i++){var o=this.deliveries.by_id(i);if(o||console.log("Could not find delivery for "+i),o&&!o.remote_settled){var n=!1;e.settled&&(o.remote_settled=e.settled,n=!0),e.state&&e.state!==o.remote_state&&(o.remote_state=e.state,n=!0),n&&(console.log(o.link.connection.options.id+" added delivery to updated list following receipt of disposition for incoming deliveries"),this.updated.push(o))}}};var Session=function(e,t){this.connection=e,this.outgoing=new Outgoing,this.incoming=new Incoming,this.state=new EndpointState,this.local={channel:t,handles:{}},this.local.begin=frames.begin({next_ou
tgoing_id:this.outgoing.next_transfer_id,incoming_window:this.incoming.window,outgoing_window:this.outgoing.window}),this.local.end=frames.end(),this.remote={handles:{}},this.links={},this.options={}};Session.prototype=Object.create(EventEmitter.prototype),Session.prototype.constructor=Session,Session.prototype.reset=function(){this.state.disconnected(),this.outgoing=new Outgoing,this.incoming=new Incoming,this.remote={handles:{}};for(var e in this.links)this.links[e].reset()},Session.prototype.dispatch=function(e,t){log.events("Session got event: "+e),this.listeners(e).length?EventEmitter.prototype.emit.apply(this,arguments):this.connection.dispatch.apply(this.connection,arguments)},Session.prototype.output=function(e,t){this.connection._write_frame(this.local.channel,e,t)},Session.prototype.create_sender=function(e,t){return this.create_link(e,link.Sender,t)},Session.prototype.create_receiver=function(e,t){return this.create_link(e,link.Receiver,t)},Session.prototype.get_option=fu
nction(e,t){return void 0!==this.options[e]?this.options[e]:this.connection.get_option(e,t)},Session.prototype.attach_sender=function(e){return attach(this.create_sender.bind(this),e,"target")},Session.prototype.open_sender=Session.prototype.attach_sender,Session.prototype.attach_receiver=function(e){return attach(this.create_receiver.bind(this),e,"source")},Session.prototype.open_receiver=Session.prototype.attach_receiver,Session.prototype.create_link=function(e,t,i){for(var o=0;this.local.handles[o];)o++;var n=new t(this,e,o,i);return this.links[e]=n,this.local.handles[o]=n,n},Session.prototype.begin=function(){this.state.open()&&this.connection._register()},Session.prototype.open=Session.prototype.begin,Session.prototype.end=function(){this.state.close()&&this.connection._register()},Session.prototype.close=Session.prototype.end,Session.prototype.is_open=function(){return this.connection.is_open()&&this.state.is_open()},Session.prototype.is_closed=function(){return this.connectio
n.is_closed()||this.state.is_closed()},Session.prototype._process=function(){do{this.state.need_open()&&this.output(this.local.begin.described()),this.outgoing.process(),this.incoming.process();for(var e in this.links)this.links[e]._process();this.state.need_close()&&this.output(this.local.end.described())}while(!this.state.has_settled())},Session.prototype.send=function(e,t,i,o){var n=this.outgoing.send(e,t,i,o);return this.connection._register(),n},Session.prototype._write_flow=function(e){var t={next_incoming_id:this.incoming.next_transfer_id,incoming_window:this.incoming.window,next_outgoing_id:this.outgoing.next_transfer_id,outgoing_window:this.outgoing.window};e&&(t.delivery_count=e.delivery_count,t.handle=e.local.handle,t.link_credit=e.credit),this.output(frames.flow(t).described())},Session.prototype.on_begin=function(e){if(!this.state.remote_opened())throw Error("Begin already received");this.remote.channel||(this.remote.channel=e.channel),this.remote.begin=e.performative,t
his.outgoing.on_begin(e.performative),this.incoming.on_begin(e.performative),this.open(),this.dispatch("session_open",this._context())},Session.prototype.on_end=function(e){if(!this.state.remote_closed())throw Error("End already received");this.remote.end=e.performative,this.close(),this.dispatch("session_close",this._context())},Session.prototype.on_attach=function(e){var t=e.performative.name,i=this.links[t];i||(i=e.performative.role?this.create_sender(t):this.create_receiver(t)),this.remote.handles[e.performative.handle]=i,i.on_attach(e),i.remote.attach=e.performative},Session.prototype.on_disposition=function(e){e.performative.role?(log.events("Received disposition for outgoing transfers"),this.outgoing.on_disposition(e.performative)):(log.events("Received disposition for incoming transfers"),this.incoming.on_disposition(e.performative)),this.connection._register()},Session.prototype.on_flow=function(e){this.outgoing.on_flow(e.performative),this.incoming.on_flow(e.performative),
void 0!==e.performative.handle&&this._get_link(e).on_flow(e),this.connection._register()},Session.prototype._context=function(e){var t=e?e:{};return t.session=this,this.connection._context(t)},Session.prototype._get_link=function(e){var t=e.performative.handle,i=this.remote.handles[t];if(!i)throw Error("Invalid handle "+t);return i},Session.prototype.on_detach=function(e){this._get_link(e).on_detach(e);var t=e.performative.handle,i=this.remote.handles[t];delete this.remote.handles[t],delete this.local.handles[i.local.handle],delete this.links[i.name]},Session.prototype.on_transfer=function(e){this.incoming.on_transfer(e,this._get_link(e))},module.exports=Session;
-}).call(this,require("buffer").Buffer)
-
-},{"./endpoint.js":2,"./frames.js":3,"./link.js":4,"./log.js":5,"./message.js":6,"./types.js":12,"./util.js":13,"buffer":19,"events":23}],10:[function(require,module,exports){
-"use strict";function define_terminus(e){var t=types.define_composite(e);terminus[e.name]=t.create,by_descriptor[Number(t.descriptor.numeric).toString(10)]=t,by_descriptor[t.descriptor.symbolic]=t}var types=require("./types.js"),terminus={},by_descriptor={};terminus.unwrap=function(e){if(e&&e.descriptor){var t=by_descriptor[e.descriptor.value];if(t)return new t(e.value);console.log("Unknown terminus: "+e.descriptor)}return null},define_terminus({name:"source",code:40,fields:[{name:"address",type:"string"},{name:"durable",type:"uint",default_value:0},{name:"expiry_policy",type:"symbol",default_value:"session-end"},{name:"timeout",type:"uint",default_value:0},{name:"dynamic",type:"boolean",default_value:!1},{name:"dynamic_node_properties",type:"symbolic_map"},{name:"distribution_mode",type:"symbol"},{name:"filter",type:"symbolic_map"},{name:"default_outcome",type:"*"},{name:"outcomes",type:"symbol",multiple:!0},{name:"capabilities",type:"symbol",multiple:!0}]}),define_terminus({name:"
target",code:41,fields:[{name:"address",type:"string"},{name:"durable",type:"uint",default_value:0},{name:"expiry_policy",type:"symbol",default_value:"session-end"},{name:"timeout",type:"uint",default_value:0},{name:"dynamic",type:"boolean",default_value:!1},{name:"dynamic_node_properties",type:"symbolic_map"},{name:"capabilities",type:"symbol",multiple:!0}]}),module.exports=terminus;
-},{"./types.js":12}],11:[function(require,module,exports){
-(function (Buffer){
-"use strict";var frames=require("./frames.js"),log=require("./log.js"),Transport=function(e,i,r,t){this.identifier=e,this.protocol_id=i,this.frame_type=r,this.handler=t,this.pending=[],this.header_sent=void 0,this.header_received=void 0,this.write_complete=!1,this.read_complete=!1};Transport.prototype.has_writes_pending=function(){return this.pending.length>0},Transport.prototype.encode=function(e){var i=frames.write_frame(e);log.frames("["+this.identifier+"] PENDING: "+JSON.stringify(e)),this.pending.push(i)},Transport.prototype.write=function(e){if(!this.header_sent){var i=new Buffer(8),r={protocol_id:this.protocol_id,major:1,minor:0,revision:0};frames.write_header(i,r),e.write(i),this.header_sent=r}for(var t=0;t<this.pending.length;t++)e.write(this.pending[t]),log.raw("["+this.identifier+"] SENT: "+JSON.stringify(this.pending[t]));this.pending=[]},Transport.prototype.read=function(e){var i=0;if(!this.header_received){if(e.length<8)return i;if(this.header_received=frames.read_head
er(e),log.frames("["+this.identifier+"] RECV: "+JSON.stringify(this.header_received)),this.header_received.protocol_id!==this.protocol_id)throw Error("Invalid AMQP protocol id "+this.header_received.protocol_id+" expecting: "+this.protocol_id);i=8}for(;i<e.length&&!this.read_complete;){var r=e.readUInt32BE(i);if(log.io("["+this.identifier+"] got frame of size "+r),e.length<i+r){log.io("["+this.identifier+"] incomplete frame; have only "+(e.length-i)+" of "+r);break}var t=frames.read_frame(e.slice(i,i+r));if(log.frames("["+this.identifier+"] RECV: "+JSON.stringify(t)),t.type!==this.frame_type)throw Error("Invalid frame type: "+t.type);i+=r,t.performative&&t.performative.dispatch(this.handler,t)}return i},module.exports=Transport;
-}).call(this,require("buffer").Buffer)
-
-},{"./frames.js":3,"./log.js":5,"buffer":19}],12:[function(require,module,exports){
-(function (Buffer){
-"use strict";function Typed(t,e){this.type=t,this.value=e}function hex(t){return Number(t).toString(16)}function define_type(t,e,r,i){var n,o=e>>>4;switch(n=4===o?function(){this.type=n,this.value=i}:14===o||15===o?function(t,e,r){this.type=n,this.value=t,this.array_constructor={typecode:e},r&&(this.array_constructor.descriptor=r)}:function(t){this.type=n,this.value=t},n.typecode=e,n.prototype=Object.create(Typed.prototype),n.toString=function(){return t+"#"+hex(e)},o){case 4:n.width=0,n.category="fixed";break;case 5:n.width=1,n.category="fixed";break;case 6:n.width=2,n.category="fixed";break;case 7:n.width=4,n.category="fixed";break;case 8:n.width=8,n.category="fixed";break;case 9:n.width=16,n.category="fixed";break;case 10:n.width=1,n.category="variable";break;case 11:n.width=4,n.category="variable";break;case 12:n.width=1,n.category="compound";break;case 13:n.width=4,n.category="compound";break;case 14:n.width=1,n.category="array";break;case 15:n.width=4,n.category="array"}if(r)f
or(var s in r)n[s]=r[s];return types.by_code[n.typecode]=n,types[t]=n,n}function buffer_ops(t){return{read:function(e,r){return e["read"+t](r)},write:function(e,r,i){e["write"+t](r,i)}}}function write_ulong(t,e,r){if("number"==typeof e||e instanceof Number){var i=e/MAX_UINT,n=e%MAX_UINT;t.writeUInt32BE(i,r),t.writeUInt32BE(n,r+4)}else e.copy(t,r)}function read_ulong(t,e){var r=t.readUInt32BE(e),i=t.readUInt32BE(e+4);return 2097153>r?r*MAX_UINT+i:t.slice(e,e+8)}function write_long(t,e,r){if("number"==typeof e||e instanceof Number){var i=Math.abs(e),n=i/MAX_UINT,o=i%MAX_UINT;if(t.writeInt32BE(n,r),t.writeUInt32BE(o,r+4),0>e)for(var s=1,p=0;8>p;p++){var a=r+(7-p),e=(255^t[a])+s;t[a]=255&e,s=e>>8}}else e.copy(t,r)}function read_long(t,e){var r=t.readInt32BE(e),i=t.readUInt32BE(e+4);return 2097153>r&&r>-2097153?r*MAX_UINT+i:t.slice(e,e+8)}function is_one_of(t,e){for(var r=0;r<e.length;r++)if(t.type.typecode===e[r].typecode)return!0;return!1}function mapify(t){for(var e={},r=0;r+1<t.lengt
h;)e[t[r++]]=t[r++];return e}function get_type(t){var e=types.by_code[t];if(!e)throw Error("Unrecognised typecode: "+hex(t));return e}function max(t,e){return t>e?t:e}function get_constructor(t){if("symbol"===t)return{typecode:types.Sym8.typecode};throw Error("TODO: Array of type "+t+" not yet supported")}function wrap_field(t,e){if(void 0!==e&&null!==e){if(Array.isArray(e)){if(!t.multiple)throw Error("Field "+t.name+" does not support multiple values, got "+JSON.stringify(e));var r=get_constructor(t.type);return types.wrap_array(e,r.typecode,r.descriptor)}if("*"===t.type)return e;var i=types["wrap_"+t.type];if(i)return i(e);throw Error("No wrapper for field "+t.name+" of type "+t.type)}if(t.mandatory)throw Error("Field "+t.name+" is mandatory");return new types.Null}function get_accessors(t,e){var r=function(){return"*"===e.type?this.value[t]:types.unwrap(this.value[t])},i=function(r){this.value[t]=wrap_field(e,r)};return{get:r,set:i,enumerable:!0,configurable:!1}}function add_type
(t){var e=types.define_composite(t);types["wrap_"+t.name]=function(t){return e.create(t).described()},by_descriptor[Number(e.descriptor.numeric).toString(10)]=e,by_descriptor[e.descriptor.symbolic]=e}Typed.prototype.toString=function(){return this.value?this.value.toString():null},Typed.prototype.toLocaleString=function(){return this.value?this.value.toLocaleString():null},Typed.prototype.valueOf=function(){return this.value},Typed.prototype.toJSON=function(){return this.value&&this.value.toJSON?this.value.toJSON():this.value};var types={by_code:{}};Object.defineProperty(types,"MAX_UINT",{value:4294967295,writable:!1,configurable:!1}),Object.defineProperty(types,"MAX_USHORT",{value:65535,writable:!1,configurable:!1});var MAX_UINT=4294967296;define_type("Null",64,void 0,null),define_type("Boolean",86,buffer_ops("UInt8")),define_type("True",65,void 0,!0),define_type("False",66,void 0,!1),define_type("Ubyte",80,buffer_ops("UInt8")),define_type("Ushort",96,buffer_ops("UInt16BE")),define
_type("Uint",112,buffer_ops("UInt32BE")),define_type("SmallUint",82,buffer_ops("UInt8")),define_type("Uint0",67,void 0,0),define_type("Ulong",128,{write:write_ulong,read:read_ulong}),define_type("SmallUlong",83,buffer_ops("UInt8")),define_type("Ulong0",68,void 0,0),define_type("Byte",81,buffer_ops("Int8")),define_type("Short",97,buffer_ops("Int16BE")),define_type("Int",113,buffer_ops("Int32BE")),define_type("SmallInt",84,buffer_ops("Int8")),define_type("Long",129,{write:write_long,read:read_long}),define_type("SmallLong",85,buffer_ops("Int8")),define_type("Float",114,buffer_ops("Float")),define_type("Double",130,buffer_ops("Double")),define_type("Decimal32",116),define_type("Decimal64",132),define_type("Decimal128",148),define_type("CharUTF32",115),define_type("Timestamp",131),define_type("Uuid",152),define_type("Vbin8",160),define_type("Vbin32",176),define_type("Str8",161,{encoding:"utf8"}),define_type("Str32",177,{encoding:"utf8"}),define_type("Sym8",163,{encoding:"ascii"}),define
_type("Sym32",179,{encoding:"ascii"}),define_type("List0",69,void 0,[]),define_type("List8",192),define_type("List32",208),define_type("Map8",193),define_type("Map32",209),define_type("Array8",224),define_type("Array32",240),types.is_ulong=function(t){return is_one_of(t,[types.Ulong,types.Ulong0,types.SmallUlong])},types.is_string=function(t){return is_one_of(t,[types.Str8,types.Str32])},types.is_symbol=function(t){return is_one_of(t,[types.Sym8,types.Sym32])},types.is_list=function(t){return is_one_of(t,[types.List0,types.List8,types.List32])},types.is_map=function(t){return is_one_of(t,[types.Map8,types.Map32])},types.wrap_boolean=function(t){return new types.Boolean(t)},types.wrap_ulong=function(t){return 0===t?new types.Ulong0:t>255?new types.Ulong(t):new types.SmallUlong(t)},types.wrap_uint=function(t){return 0===t?new types.Uint0:t>255?new types.Uint(t):new types.SmallUint(t)},types.wrap_ushort=function(t){return new types.Ushort(t)},types.wrap_ubyte=function(t){return new typ
es.Ubyte(t)},types.wrap_long=function(t){return t>127||-128>t?new types.Long(t):new types.SmallLong(t)},types.wrap_int=function(t){return t>127||-128>t?new types.Int(t):new types.SmallInt(t)},types.wrap_short=function(t){return new types.Short(t)},types.wrap_byte=function(t){return new types.Byte(t)},types.wrap_float=function(t){return new types.Float(t)},types.wrap_double=function(t){return new types.Double(t)},types.wrap_timestamp=function(t){return new types.Timestamp(t)},types.wrap_binary=function(t){return t.length>255?new types.Vbin32(t):new types.Vbin8(t)},types.wrap_string=function(t){return t.length>255?new types.Str32(t):new types.Str8(t)},types.wrap_symbol=function(t){return t.length>255?new types.Sym32(t):new types.Sym8(t)},types.wrap_list=function(t){if(0===t.length)return new types.List0;var e=t.map(types.wrap);return new types.List32(e)},types.wrap_map=function(t,e){var r=[];for(var i in t)r.push(e?e(i):types.wrap(i)),r.push(types.wrap(t[i]));return new types.Map32(r)
},types.wrap_symbolic_map=function(t){return types.wrap_map(t,types.wrap_symbol)},types.wrap_array=function(t,e,r){if(e)return new types.Array32(t,e,r);throw Error("An array must specify a type for its elements")},types.wrap=function(t){var e=typeof t;if("string"===e)return types.wrap_string(t);if("boolean"==e)return t?new types.True:new types.False;if("number"==e||t instanceof Number){if(isNaN(t))throw Error("Cannot wrap NaN! "+t);return Math.floor(t)-t!==0?new types.Double(t):t>0?types.wrap_uint(t):types.wrap_int(t)}return t instanceof Date?void 0:t instanceof Typed?t:"undefined"==e||null===t?new types.Null:Array.isArray(t)?types.wrap_list(t):types.wrap_map(t)},types.wrap_described=function(t,e){var r=types.wrap(t);return e&&("string"==typeof e?r=types.described(types.wrap_string(e),r):("number"==typeof e||e instanceof Number)&&(r=types.described(types.wrap_ulong(e),r))),r},types.wrap_message_id=function(t){var e=typeof t;if("string"===e)return types.wrap_string(t);if("number"==e|
|t instanceof Number)return types.wrap_ulong(t);throw Error("invalid message id:"+t)},types.wrap_delivery_state=function(t){return new Null};var by_descriptor={};types.unwrap=function(t,e){if(t instanceof Typed){if(t.descriptor){var r=by_descriptor[t.descriptor.value];if(r)return new r(t.value);if(e)return t}var i=types.unwrap(t.value,!0);return types.is_map(t)?mapify(i):i}return Array.isArray(t)?t.map(function(t){return types.unwrap(t,!0)}):t},types.described=function(t,e){var r=Object.create(e);return t.length?(r.descriptor=t.shift(),described(t,r)):(r.descriptor=t,r)},types.Reader=function(t){this.buffer=t,this.position=0},types.Reader.prototype.read_typecode=function(){return this.read_uint(1)},types.Reader.prototype.read_uint=function(t){var e=this.position;this.position+=t;var r=t>1?"readUInt"+8*t+"BE":"readUInt8";return this.buffer[r](e)},types.Reader.prototype.read_fixed_width=function(t){var e=this.position;return this.position+=t.width,t.read?t.read(this.buffer,e):this.buf
fer.slice(e,this.position)},types.Reader.prototype.read_variable_width=function(t){var e=this.read_uint(t.width),r=this.read_bytes(e);return t.encoding?r.toString(t.encoding):r},types.Reader.prototype.read=function(){var t=this.read_constructor(),e=this.read_value(get_type(t.typecode));return t.descriptor?types.described(t.descriptor,e):e},types.Reader.prototype.read_constructor=function(){var t=this.read_typecode();if(0===t){var e=[];e.push(this.read());for(var r=this.read_constructor();r.descriptor;)e.push(r.descriptor),r=this.read_constructor();return{typecode:r.typecode,descriptor:1==e.length?e[0]:e}}return{typecode:t}},types.Reader.prototype.read_value=function(t){if(0===t.width)return new t;if("fixed"===t.category)return new t(this.read_fixed_width(t));if("variable"===t.category)return new t(this.read_variable_width(t));if("compound"===t.category)return this.read_compound(t);if("array"===t.category)return this.read_array(t);throw Error("Invalid category for type: "+t)},types.R
eader.prototype.read_multiple=function(t,e){for(var r=e?e:this.read.bind(this),i=[];i.length<t;)i.push(r.apply(this));return i},types.Reader.prototype.read_size_count=function(t){return{size:this.read_uint(t),count:this.read_uint(t)}},types.Reader.prototype.read_compound=function(t){var e=this.read_size_count(t.width);return new t(this.read_multiple(e.count))},types.Reader.prototype.read_array=function(t){var e=this.read_size_count(t.width),r=this.read_constructor(),i=new t(this.read_multiple(e.count,this.read_value.bind(this,get_type(r.typecode))),r.typecode,r.descriptor);return i},types.Reader.prototype.toString=function(){var t="buffer@"+this.position;this.position&&(t+=": ");for(var e=this.position;e<this.buffer.length;e++)e>0&&(t+=","),t+="0x"+Number(this.buffer[e]).toString(16);return t},types.Reader.prototype.reset=function(){this.position=0},types.Reader.prototype.skip=function(t){this.position+=t},types.Reader.prototype.read_bytes=function(t){var e=this.position;return this
.position+=t,this.buffer.slice(e,this.position)},types.Reader.prototype.remaining=function(){return this.buffer.length-this.position},types.Writer=function(t){this.buffer=t?t:new Buffer(1024),this.position=0},types.Writer.prototype.toBuffer=function(){return this.buffer.slice(0,this.position)},types.Writer.prototype.ensure=function(t){if(this.buffer.length<t){var e=new Buffer(max(2*this.buffer.length,t));this.buffer.copy(e),this.buffer=e}},types.Writer.prototype.write_typecode=function(t){this.write_uint(t,1)},types.Writer.prototype.write_uint=function(t,e){var r=this.position;this.ensure(this.position+e),this.position+=e;var i=e>1?"writeUInt"+8*e+"BE":"writeUInt8";if(!this.buffer[i])throw Error("Buffer doesn't define "+i);return this.buffer[i](t,r)},types.Writer.prototype.write_fixed_width=function(t,e){var r=this.position;if(this.ensure(this.position+t.width),this.position+=t.width,t.write)t.write(this.buffer,e,r);else{if(!e.copy)throw Error("Can't handle write for "+t);e.copy(thi
s.buffer,r)}},types.Writer.prototype.write_variable_width=function(t,e){var r=t.encoding?new Buffer(e,t.encoding):new Buffer(e);this.write_uint(r.length,t.width),this.write_bytes(r)},types.Writer.prototype.write_bytes=function(t){var e=this.position;this.ensure(this.position+t.length),this.position+=t.length,t.copy(this.buffer,e)},types.Writer.prototype.write_constructor=function(t,e){e&&(this.write_typecode(0),this.write(e)),this.write_typecode(t)},types.Writer.prototype.write=function(t){if(!(t instanceof Typed))throw Error("Can't write "+JSON.stringify(t));this.write_constructor(t.type.typecode,t.descriptor),this.write_value(t.type,t.value,t.array_constructor)},types.Writer.prototype.write_value=function(t,e,r){if(0!==t.width)if("fixed"===t.category)this.write_fixed_width(t,e);else if("variable"===t.category)this.write_variable_width(t,e);else if("compound"===t.category)this.write_compound(t,e);else{if("array"!==t.category)throw Error("Invalid category "+t.category+" for type: "+
t);this.write_array(t,e,r)}},types.Writer.prototype.backfill_size=function(t,e){var r=this.position-e;this.position=e,this.write_uint(r-t,t),this.position+=r-t},types.Writer.prototype.write_compound=function(t,e){var r=this.position;this.position+=t.width,this.write_uint(e.length,t.width);for(var i=0;i<e.length;i++)void 0===e[i]||null===e[i]?this.write(new types.Null):this.write(e[i]);this.backfill_size(t.width,r)},types.Writer.prototype.write_array=function(t,e,r){var i=this.position;this.position+=t.width,this.write_uint(e.length,t.width),this.write_constructor(r.typecode,r.descriptor);for(var t=get_type(r.typecode),n=0;n<e.length;n++)this.write_value(t,e[n]);this.backfill_size(t.width,i)},types.Writer.prototype.toString=function(){var t="buffer@"+this.position;this.position&&(t+=": ");for(var e=0;e<this.position;e++)e>0&&(t+=","),t+=("00"+Number(this.buffer[e]).toString(16)).slice(-2);return t},types.Writer.prototype.skip=function(t){this.ensure(this.position+t),this.position+=t}
,types.Writer.prototype.clear=function(){this.buffer.fill(0),this.position=0},types.Writer.prototype.remaining=function(){return this.buffer.length-this.position},types.define_composite=function(t){var e=function(t){this.value=t?t:[]};e.descriptor={numeric:t.code,symbolic:"amqp:"+t.name+":list"},e.prototype.dispatch=function(e,r){e["on_"+t.name](r)};for(var r=0;r<t.fields.length;r++){var i=t.fields[r];Object.defineProperty(e.prototype,i.name,get_accessors(r,i))}return e.toString=function(){return t.name+"#"+Number(t.code).toString(16)},e.prototype.toJSON=function(){var t={};for(var e in this)"value"!==e&&this[e]&&(t[e]=this[e]);return t},e.create=function(t){var r=new e;for(var i in t)r[i]=t[i];return r},e.prototype.described=function(t){return types.described(types.wrap_ulong(e.descriptor.numeric),types.wrap_list(this.value))},e},add_type({name:"error",code:29,fields:[{name:"condition",type:"symbol",mandatory:!0},{name:"description",type:"string"},{name:"info",type:"map"}]}),module
.exports=types;
-}).call(this,require("buffer").Buffer)
-
-},{"buffer":19}],13:[function(require,module,exports){
-"use strict";var util={};util.generate_uuid=function(){var x="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(x){var t=16*Math.random()|0,r="x"==x?t:3&t|8;return r.toString(16)});return x},util.clone=function(x){for(var t=Object.create(x.prototype||{}),r=Object.getOwnPropertyNames(x),e=0;e<r.length;e++){var n=r[e];t[n]=x[n]}return t},module.exports=util;
-},{}],14:[function(require,module,exports){
-(function (Buffer){
-"use strict";function nulltransform(n){return n}function from_arraybuffer(n){return n instanceof ArrayBuffer?new Buffer(new Uint8Array(n)):new Buffer(n)}function to_typedarray(n){return new Uint8Array(n)}function wrap(n){var r=nulltransform,e=nulltransform;return n.binaryType&&(n.binaryType="arraybuffer",r=from_arraybuffer,e=to_typedarray),{end:function(){n.close()},write:function(r){n.send(e(r),{binary:!0})},on:function(e,t){"data"===e?n.onmessage=function(n){t(r(n.data))}:"end"===e?n.onclose=t:"error"===e?n.onerror=t:console.log("ERROR: Attempt to set unrecognised handler on websocket wrapper: "+e)},get_id_string:function(){return n.url}}}module.exports={connect:function(n){return function(r,e){return function(){return{connect:function(t,o,u,a){var f=new n(r,e);return f.onopen=a,wrap(f)}}}}},wrap:wrap};
-}).call(this,require("buffer").Buffer)
-
-},{"buffer":19}],15:[function(require,module,exports){
-function useColors(){return"WebkitAppearance"in document.documentElement.style||window.console&&(console.firebug||console.exception&&console.table)||navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31}function formatArgs(){var o=arguments,e=this.useColors;if(o[0]=(e?"%c":"")+this.namespace+(e?" %c":" ")+o[0]+(e?"%c ":" ")+"+"+exports.humanize(this.diff),!e)return o;var r="color: "+this.color;o=[o[0],r,"color: inherit"].concat(Array.prototype.slice.call(o,1));var t=0,s=0;return o[0].replace(/%[a-z%]/g,function(o){"%%"!==o&&(t++,"%c"===o&&(s=t))}),o.splice(s,0,r),o}function log(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function save(o){try{null==o?exports.storage.removeItem("debug"):exports.storage.debug=o}catch(e){}}function load(){var o;try{o=exports.storage.debug}catch(e){}return o}function localstorage(){try{return window.localStorage}catch(o){}}exports=module.exports=require("./deb
ug"),exports.log=log,exports.formatArgs=formatArgs,exports.save=save,exports.load=load,exports.useColors=useColors,exports.storage="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:localstorage(),exports.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],exports.formatters.j=function(o){return JSON.stringify(o)},exports.enable(load());
-},{"./debug":16}],16:[function(require,module,exports){
-function selectColor(){return exports.colors[prevColor++%exports.colors.length]}function debug(e){function r(){}function o(){var e=o,r=+new Date,s=r-(prevTime||r);e.diff=s,e.prev=prevTime,e.curr=r,prevTime=r,null==e.useColors&&(e.useColors=exports.useColors()),null==e.color&&e.useColors&&(e.color=selectColor());var t=Array.prototype.slice.call(arguments);t[0]=exports.coerce(t[0]),"string"!=typeof t[0]&&(t=["%o"].concat(t));var n=0;t[0]=t[0].replace(/%([a-z%])/g,function(r,o){if("%%"===r)return r;n++;var s=exports.formatters[o];if("function"==typeof s){var p=t[n];r=s.call(e,p),t.splice(n,1),n--}return r}),"function"==typeof exports.formatArgs&&(t=exports.formatArgs.apply(e,t));var p=o.log||exports.log||console.log.bind(console);p.apply(e,t)}r.enabled=!1,o.enabled=!0;var s=exports.enabled(e)?o:r;return s.namespace=e,s}function enable(e){exports.save(e);for(var r=(e||"").split(/[\s,]+/),o=r.length,s=0;o>s;s++)r[s]&&(e=r[s].replace(/\*/g,".*?"),"-"===e[0]?exports.skips.push(new RegExp("
^"+e.substr(1)+"$")):exports.names.push(new RegExp("^"+e+"$")))}function disable(){exports.enable("")}function enabled(e){var r,o;for(r=0,o=exports.skips.length;o>r;r++)if(exports.skips[r].test(e))return!1;for(r=0,o=exports.names.length;o>r;r++)if(exports.names[r].test(e))return!0;return!1}function coerce(e){return e instanceof Error?e.stack||e.message:e}exports=module.exports=debug,exports.coerce=coerce,exports.disable=disable,exports.enable=enable,exports.enabled=enabled,exports.humanize=require("ms"),exports.names=[],exports.skips=[],exports.formatters={};var prevColor=0,prevTime;
-},{"ms":17}],17:[function(require,module,exports){
-function parse(e){if(e=""+e,!(e.length>1e4)){var a=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(a){var r=parseFloat(a[1]),c=(a[2]||"ms").toLowerCase();switch(c){case"years":case"year":case"yrs":case"yr":case"y":return r*y;case"days":case"day":case"d":return r*d;case"hours":case"hour":case"hrs":case"hr":case"h":return r*h;case"minutes":case"minute":case"mins":case"min":case"m":return r*m;case"seconds":case"second":case"secs":case"sec":case"s":return r*s;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r}}}}function short(e){return e>=d?Math.round(e/d)+"d":e>=h?Math.round(e/h)+"h":e>=m?Math.round(e/m)+"m":e>=s?Math.round(e/s)+"s":e+"ms"}function long(e){return plural(e,d,"day")||plural(e,h,"hour")||plural(e,m,"minute")||plural(e,s,"second")||e+" ms"}function plural(s,e,a){return e>s?void 0:1.5*e>s?Math.floor(s/e)+" "+a:Math.ceil(s/e)+" "+a+"s"}var s=1e3,m=60*s,h=60*m,d=24*h
,y=365.25*d;module.exports=function(s,e){return e=e||{},"string"==typeof s?parse(s):e["long"]?long(s):short(s)};
-},{}],18:[function(require,module,exports){
-
-},{}],19:[function(require,module,exports){
-(function (global){
-"use strict";function typedArraySupport(){try{var t=new Uint8Array(1);return t.foo=function(){return 42},42===t.foo()&&"function"==typeof t.subarray&&0===t.subarray(1,1).byteLength}catch(e){return!1}}function kMaxLength(){return Buffer.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function Buffer(t){return this instanceof Buffer?(Buffer.TYPED_ARRAY_SUPPORT||(this.length=0,this.parent=void 0),"number"==typeof t?fromNumber(this,t):"string"==typeof t?fromString(this,t,arguments.length>1?arguments[1]:"utf8"):fromObject(this,t)):arguments.length>1?new Buffer(t,arguments[1]):new Buffer(t)}function fromNumber(t,e){if(t=allocate(t,0>e?0:0|checked(e)),!Buffer.TYPED_ARRAY_SUPPORT)for(var r=0;e>r;r++)t[r]=0;return t}function fromString(t,e,r){("string"!=typeof r||""===r)&&(r="utf8");var n=0|byteLength(e,r);return t=allocate(t,n),t.write(e,r),t}function fromObject(t,e){if(Buffer.isBuffer(e))return fromBuffer(t,e);if(isArray(e))return fromArray(t,e);if(null==e)throw new TypeError("must start with nu
mber, buffer, array or string");if("undefined"!=typeof ArrayBuffer){if(e.buffer instanceof ArrayBuffer)return fromTypedArray(t,e);if(e instanceof ArrayBuffer)return fromArrayBuffer(t,e)}return e.length?fromArrayLike(t,e):fromJsonObject(t,e)}function fromBuffer(t,e){var r=0|checked(e.length);return t=allocate(t,r),e.copy(t,0,0,r),t}function fromArray(t,e){var r=0|checked(e.length);t=allocate(t,r);for(var n=0;r>n;n+=1)t[n]=255&e[n];return t}function fromTypedArray(t,e){var r=0|checked(e.length);t=allocate(t,r);for(var n=0;r>n;n+=1)t[n]=255&e[n];return t}function fromArrayBuffer(t,e){return e.byteLength,Buffer.TYPED_ARRAY_SUPPORT?(t=new Uint8Array(e),t.__proto__=Buffer.prototype):t=fromTypedArray(t,new Uint8Array(e)),t}function fromArrayLike(t,e){var r=0|checked(e.length);t=allocate(t,r);for(var n=0;r>n;n+=1)t[n]=255&e[n];return t}function fromJsonObject(t,e){var r,n=0;"Buffer"===e.type&&isArray(e.data)&&(r=e.data,n=0|checked(r.length)),t=allocate(t,n);for(var f=0;n>f;f+=1)t[f]=255&r[f
];return t}function allocate(t,e){Buffer.TYPED_ARRAY_SUPPORT?(t=new Uint8Array(e),t.__proto__=Buffer.prototype):t.length=e;var r=0!==e&&e<=Buffer.poolSize>>>1;return r&&(t.parent=rootParent),t}function checked(t){if(t>=kMaxLength())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+kMaxLength().toString(16)+" bytes");return 0|t}function SlowBuffer(t,e){if(!(this instanceof SlowBuffer))return new SlowBuffer(t,e);var r=new Buffer(t,e);return delete r.parent,r}function byteLength(t,e){"string"!=typeof t&&(t=""+t);var r=t.length;if(0===r)return 0;for(var n=!1;;)switch(e){case"ascii":case"binary":case"raw":case"raws":return r;case"utf8":case"utf-8":return utf8ToBytes(t).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return base64ToBytes(t).length;default:if(n)return utf8ToBytes(t).length;e=(""+e).toLowerCase(),n=!0}}function slowToString(t,e,r){var n=!1;if(e=0|e,r=void 0===r||r===1/0?this.length:0|r,t|
|(t="utf8"),0>e&&(e=0),r>this.length&&(r=this.length),e>=r)return"";for(;;)switch(t){case"hex":return hexSlice(this,e,r);case"utf8":case"utf-8":return utf8Slice(this,e,r);case"ascii":return asciiSlice(this,e,r);case"binary":return binarySlice(this,e,r);case"base64":return base64Slice(this,e,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return utf16leSlice(this,e,r);default:if(n)throw new TypeError("Unknown encoding: "+t);t=(t+"").toLowerCase(),n=!0}}function hexWrite(t,e,r,n){r=Number(r)||0;var f=t.length-r;n?(n=Number(n),n>f&&(n=f)):n=f;var i=e.length;if(i%2!==0)throw new Error("Invalid hex string");n>i/2&&(n=i/2);for(var o=0;n>o;o++){var u=parseInt(e.substr(2*o,2),16);if(isNaN(u))throw new Error("Invalid hex string");t[r+o]=u}return o}function utf8Write(t,e,r,n){return blitBuffer(utf8ToBytes(e,t.length-r),t,r,n)}function asciiWrite(t,e,r,n){return blitBuffer(asciiToBytes(e),t,r,n)}function binaryWrite(t,e,r,n){return asciiWrite(t,e,r,n)}function base64Write(t,e,r,n){retur
n blitBuffer(base64ToBytes(e),t,r,n)}function ucs2Write(t,e,r,n){return blitBuffer(utf16leToBytes(e,t.length-r),t,r,n)}function base64Slice(t,e,r){return 0===e&&r===t.length?base64.fromByteArray(t):base64.fromByteArray(t.slice(e,r))}function utf8Slice(t,e,r){r=Math.min(t.length,r);for(var n=[],f=e;r>f;){var i=t[f],o=null,u=i>239?4:i>223?3:i>191?2:1;if(r>=f+u){var s,h,a,c;switch(u){case 1:128>i&&(o=i);break;case 2:s=t[f+1],128===(192&s)&&(c=(31&i)<<6|63&s,c>127&&(o=c));break;case 3:s=t[f+1],h=t[f+2],128===(192&s)&&128===(192&h)&&(c=(15&i)<<12|(63&s)<<6|63&h,c>2047&&(55296>c||c>57343)&&(o=c));break;case 4:s=t[f+1],h=t[f+2],a=t[f+3],128===(192&s)&&128===(192&h)&&128===(192&a)&&(c=(15&i)<<18|(63&s)<<12|(63&h)<<6|63&a,c>65535&&1114112>c&&(o=c))}}null===o?(o=65533,u=1):o>65535&&(o-=65536,n.push(o>>>10&1023|55296),o=56320|1023&o),n.push(o),f+=u}return decodeCodePointsArray(n)}function decodeCodePointsArray(t){var e=t.length;if(MAX_ARGUMENTS_LENGTH>=e)return String.fromCharCode.apply(String
,t);for(var r="",n=0;e>n;)r+=String.fromCharCode.apply(String,t.slice(n,n+=MAX_ARGUMENTS_LENGTH));return r}function asciiSlice(t,e,r){var n="";r=Math.min(t.length,r);for(var f=e;r>f;f++)n+=String.fromCharCode(127&t[f]);return n}function binarySlice(t,e,r){var n="";r=Math.min(t.length,r);for(var f=e;r>f;f++)n+=String.fromCharCode(t[f]);return n}function hexSlice(t,e,r){var n=t.length;(!e||0>e)&&(e=0),(!r||0>r||r>n)&&(r=n);for(var f="",i=e;r>i;i++)f+=toHex(t[i]);return f}function utf16leSlice(t,e,r){for(var n=t.slice(e,r),f="",i=0;i<n.length;i+=2)f+=String.fromCharCode(n[i]+256*n[i+1]);return f}function checkOffset(t,e,r){if(t%1!==0||0>t)throw new RangeError("offset is not uint");if(t+e>r)throw new RangeError("Trying to access beyond buffer length")}function checkInt(t,e,r,n,f,i){if(!Buffer.isBuffer(t))throw new TypeError("buffer must be a Buffer instance");if(e>f||i>e)throw new RangeError("value is out of bounds");if(r+n>t.length)throw new RangeError("index out of range")}function ob
jectWriteUInt16(t,e,r,n){0>e&&(e=65535+e+1);for(var f=0,i=Math.min(t.length-r,2);i>f;f++)t[r+f]=(e&255<<8*(n?f:1-f))>>>8*(n?f:1-f)}function objectWriteUInt32(t,e,r,n){0>e&&(e=4294967295+e+1);for(var f=0,i=Math.min(t.length-r,4);i>f;f++)t[r+f]=e>>>8*(n?f:3-f)&255}function checkIEEE754(t,e,r,n,f,i){if(e>f||i>e)throw new RangeError("value is out of bounds");if(r+n>t.length)throw new RangeError("index out of range");if(0>r)throw new RangeError("index out of range")}function writeFloat(t,e,r,n,f){return f||checkIEEE754(t,e,r,4,3.4028234663852886e38,-3.4028234663852886e38),ieee754.write(t,e,r,n,23,4),r+4}function writeDouble(t,e,r,n,f){return f||checkIEEE754(t,e,r,8,1.7976931348623157e308,-1.7976931348623157e308),ieee754.write(t,e,r,n,52,8),r+8}function base64clean(t){if(t=stringtrim(t).replace(INVALID_BASE64_RE,""),t.length<2)return"";for(;t.length%4!==0;)t+="=";return t}function stringtrim(t){return t.trim?t.trim():t.replace(/^\s+|\s+$/g,"")}function toHex(t){return 16>t?"0"+t.toString(
16):t.toString(16)}function utf8ToBytes(t,e){e=e||1/0;for(var r,n=t.length,f=null,i=[],o=0;n>o;o++){if(r=t.charCodeAt(o),r>55295&&57344>r){if(!f){if(r>56319){(e-=3)>-1&&i.push(239,191,189);continue}if(o+1===n){(e-=3)>-1&&i.push(239,191,189);continue}f=r;continue}if(56320>r){(e-=3)>-1&&i.push(239,191,189),f=r;continue}r=(f-55296<<10|r-56320)+65536}else f&&(e-=3)>-1&&i.push(239,191,189);if(f=null,128>r){if((e-=1)<0)break;i.push(r)}else if(2048>r){if((e-=2)<0)break;i.push(r>>6|192,63&r|128)}else if(65536>r){if((e-=3)<0)break;i.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(1114112>r))throw new Error("Invalid code point");if((e-=4)<0)break;i.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return i}function asciiToBytes(t){for(var e=[],r=0;r<t.length;r++)e.push(255&t.charCodeAt(r));return e}function utf16leToBytes(t,e){for(var r,n,f,i=[],o=0;o<t.length&&!((e-=2)<0);o++)r=t.charCodeAt(o),n=r>>8,f=r%256,i.push(f),i.push(n);return i}function base64ToBytes(t){return base64.toByteArray(bas
e64clean(t))}function blitBuffer(t,e,r,n){for(var f=0;n>f&&!(f+r>=e.length||f>=t.length);f++)e[f+r]=t[f];return f}var base64=require("base64-js"),ieee754=require("ieee754"),isArray=require("isarray");exports.Buffer=Buffer,exports.SlowBuffer=SlowBuffer,exports.INSPECT_MAX_BYTES=50,Buffer.poolSize=8192;var rootParent={};Buffer.TYPED_ARRAY_SUPPORT=void 0!==global.TYPED_ARRAY_SUPPORT?global.TYPED_ARRAY_SUPPORT:typedArraySupport(),Buffer.TYPED_ARRAY_SUPPORT?(Buffer.prototype.__proto__=Uint8Array.prototype,Buffer.__proto__=Uint8Array):(Buffer.prototype.length=void 0,Buffer.prototype.parent=void 0),Buffer.isBuffer=function(t){return!(null==t||!t._isBuffer)},Buffer.compare=function(t,e){if(!Buffer.isBuffer(t)||!Buffer.isBuffer(e))throw new TypeError("Arguments must be Buffers");if(t===e)return 0;for(var r=t.length,n=e.length,f=0,i=Math.min(r,n);i>f&&t[f]===e[f];)++f;return f!==i&&(r=t[f],n=e[f]),n>r?-1:r>n?1:0},Buffer.isEncoding=function(t){switch(String(t).toLowerCase()){case"hex":case"utf
8":case"utf-8":case"ascii":case"binary":case"base64":case"raw":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return!0;default:return!1}},Buffer.concat=function(t,e){if(!isArray(t))throw new TypeError("list argument must be an Array of Buffers.");if(0===t.length)return new Buffer(0);var r;if(void 0===e)for(e=0,r=0;r<t.length;r++)e+=t[r].length;var n=new Buffer(e),f=0;for(r=0;r<t.length;r++){var i=t[r];i.copy(n,f),f+=i.length}return n},Buffer.byteLength=byteLength,Buffer.prototype._isBuffer=!0,Buffer.prototype.toString=function(){var t=0|this.length;return 0===t?"":0===arguments.length?utf8Slice(this,0,t):slowToString.apply(this,arguments)},Buffer.prototype.equals=function(t){if(!Buffer.isBuffer(t))throw new TypeError("Argument must be a Buffer");return this===t?!0:0===Buffer.compare(this,t)},Buffer.prototype.inspect=function(){var t="",e=exports.INSPECT_MAX_BYTES;return this.length>0&&(t=this.toString("hex",0,e).match(/.{2}/g).join(" "),this.length>e&&(t+=" ... ")),"<Buffer "+t
+">"},Buffer.prototype.compare=function(t){if(!Buffer.isBuffer(t))throw new TypeError("Argument must be a Buffer");return this===t?0:Buffer.compare(this,t)},Buffer.prototype.indexOf=function(t,e){function r(t,e,r){for(var n=-1,f=0;r+f<t.length;f++)if(t[r+f]===e[-1===n?0:f-n]){if(-1===n&&(n=f),f-n+1===e.length)return r+n}else n=-1;return-1}if(e>2147483647?e=2147483647:-2147483648>e&&(e=-2147483648),e>>=0,0===this.length)return-1;if(e>=this.length)return-1;if(0>e&&(e=Math.max(this.length+e,0)),"string"==typeof t)return 0===t.length?-1:String.prototype.indexOf.call(this,t,e);if(Buffer.isBuffer(t))return r(this,t,e);if("number"==typeof t)return Buffer.TYPED_ARRAY_SUPPORT&&"function"===Uint8Array.prototype.indexOf?Uint8Array.prototype.indexOf.call(this,t,e):r(this,[t],e);throw new TypeError("val must be string, number or Buffer")},Buffer.prototype.write=function(t,e,r,n){if(void 0===e)n="utf8",r=this.length,e=0;else if(void 0===r&&"string"==typeof e)n=e,r=this.length,e=0;else if(isFinite
(e))e=0|e,isFinite(r)?(r=0|r,void 0===n&&(n="utf8")):(n=r,r=void 0);else{var f=n;n=e,e=0|r,r=f}var i=this.length-e;if((void 0===r||r>i)&&(r=i),t.length>0&&(0>r||0>e)||e>this.length)throw new RangeError("attempt to write outside buffer bounds");n||(n="utf8");for(var o=!1;;)switch(n){case"hex":return hexWrite(this,t,e,r);case"utf8":case"utf-8":return utf8Write(this,t,e,r);case"ascii":return asciiWrite(this,t,e,r);case"binary":return binaryWrite(this,t,e,r);case"base64":return base64Write(this,t,e,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return ucs2Write(this,t,e,r);default:if(o)throw new TypeError("Unknown encoding: "+n);n=(""+n).toLowerCase(),o=!0}},Buffer.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var MAX_ARGUMENTS_LENGTH=4096;Buffer.prototype.slice=function(t,e){var r=this.length;t=~~t,e=void 0===e?r:~~e,0>t?(t+=r,0>t&&(t=0)):t>r&&(t=r),0>e?(e+=r,0>e&&(e=0)):e>r&&(e=r),t>e&&(e=t);var n;if(Buffer.TYPED_ARRAY_SU
PPORT)n=this.subarray(t,e),n.__proto__=Buffer.prototype;else{var f=e-t;n=new Buffer(f,void 0);for(var i=0;f>i;i++)n[i]=this[i+t]}return n.length&&(n.parent=this.parent||this),n},Buffer.prototype.readUIntLE=function(t,e,r){t=0|t,e=0|e,r||checkOffset(t,e,this.length);for(var n=this[t],f=1,i=0;++i<e&&(f*=256);)n+=this[t+i]*f;return n},Buffer.prototype.readUIntBE=function(t,e,r){t=0|t,e=0|e,r||checkOffset(t,e,this.length);for(var n=this[t+--e],f=1;e>0&&(f*=256);)n+=this[t+--e]*f;return n},Buffer.prototype.readUInt8=function(t,e){return e||checkOffset(t,1,this.length),this[t]},Buffer.prototype.readUInt16LE=function(t,e){return e||checkOffset(t,2,this.length),this[t]|this[t+1]<<8},Buffer.prototype.readUInt16BE=function(t,e){return e||checkOffset(t,2,this.length),this[t]<<8|this[t+1]},Buffer.prototype.readUInt32LE=function(t,e){return e||checkOffset(t,4,this.length),(this[t]|this[t+1]<<8|this[t+2]<<16)+16777216*this[t+3]},Buffer.prototype.readUInt32BE=function(t,e){return e||checkOffset(t,
4,this.length),16777216*this[t]+(this[t+1]<<16|this[t+2]<<8|this[t+3])},Buffer.prototype.readIntLE=function(t,e,r){t=0|t,e=0|e,r||checkOffset(t,e,this.length);for(var n=this[t],f=1,i=0;++i<e&&(f*=256);)n+=this[t+i]*f;return f*=128,n>=f&&(n-=Math.pow(2,8*e)),n},Buffer.prototype.readIntBE=function(t,e,r){t=0|t,e=0|e,r||checkOffset(t,e,this.length);for(var n=e,f=1,i=this[t+--n];n>0&&(f*=256);)i+=this[t+--n]*f;return f*=128,i>=f&&(i-=Math.pow(2,8*e)),i},Buffer.prototype.readInt8=function(t,e){return e||checkOffset(t,1,this.length),128&this[t]?-1*(255-this[t]+1):this[t]},Buffer.prototype.readInt16LE=function(t,e){e||checkOffset(t,2,this.length);var r=thi
<TRUNCATED>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[08/11] qpid-dispatch git commit: DISPATCH-316 Hawtio and stand-alone
consoles now use common code
Posted by ea...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/js/qdrSettings.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrSettings.js b/console/hawtio/src/main/webapp/plugin/js/qdrSettings.js
deleted file mode 100644
index e81463a..0000000
--- a/console/hawtio/src/main/webapp/plugin/js/qdrSettings.js
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
-*/
-/**
- * @module QDR
- */
-var QDR = (function (QDR) {
-
- /**
- * @method SettingsController
- * @param $scope
- * @param QDRServer
- *
- * Controller that handles the QDR settings page
- */
-
- QDR.module.controller("QDR.SettingsController", ['$scope', 'QDRService', '$timeout', '$location', function($scope, QDRService, $timeout, $location) {
-
- $scope.connecting = false;
- $scope.connectionError = false;
- $scope.connectionErrorText = undefined;
- $scope.forms = {};
-
- $scope.formEntity = angular.fromJson(localStorage[QDR.SETTINGS_KEY]) || {address: '', port: '', username: '', password: '', autostart: false};
-
- $scope.$watch('formEntity', function(newValue, oldValue) {
- if (newValue !== oldValue) {
- localStorage[QDR.SETTINGS_KEY] = angular.toJson(newValue);
- }
- }, true);
-
- $scope.buttonText = function() {
- if (QDRService.isConnected()) {
- return "Disconnect";
- } else {
- return "Connect";
- }
- };
-
- $scope.connect = function() {
- if (QDRService.connected) {
- QDRService.disconnect();
- return;
- }
-
- if ($scope.settings.$valid) {
- $scope.connectionError = false;
- $scope.connecting = true;
- $timeout( doConnect ) // timeout so connecting animation can display
- }
- }
-
- var doConnect = function () {
- if (!$scope.formEntity.address)
- $scope.formEntity.address = "localhost"
-
- console.log("attempting to connect to " + $scope.formEntity.address + ':' + $scope.formEntity.port);
- QDRService.addDisconnectAction(function () {
- $timeout( function () {
- QDR.log.debug("disconnect action called");
- $scope.connecting = false;
- $scope.connectionErrorText = QDRService.errorText;
- $scope.connectionError = true;
- })
- });
- QDRService.addConnectAction(function() {
- //QDR.log.debug("got connection notification");
- $timeout( function () {
- $scope.connecting = false;
- })
- });
- QDRService.connect($scope.formEntity);
- }
-
- }]);
-
-
-QDR.module.directive('posint', function (){
- return {
- require: 'ngModel',
-
- link: function(scope, elem, attr, ctrl) {
- // input type number allows + and - but we don't want them so filter them out
- elem.bind('keypress', function (event) {
- var nkey = !event.charCode ? event.which : event.charCode;
- var skey = String.fromCharCode(nkey);
- var nono = "-+.,"
- if (nono.indexOf(skey) >= 0) {
- event.preventDefault();
- return false;
- }
- // firefox doesn't filter out non-numeric input. it just sets the ctrl to invalid
- if (/[\!\@\#\$\%^&*\(\)]/.test(skey) && event.shiftKey || // prevent shift numbers
- !( // prevent all but the following
- nkey <= 0 || // arrows
- nkey == 8 || // delete|backspace
- nkey == 13 || // enter
- (nkey >= 37 && nkey <=40) || // arrows
- event.ctrlKey || event.altKey || // ctrl-v, etc.
- /[0-9]/.test(skey)) // numbers
- ) {
- event.preventDefault();
- return false;
- }
- })
- // check the current value of input
- var _isPortInvalid = function (value) {
- var port = value + ''
- var isErrRange = false;
- // empty string is valid
- if (port.length !== 0) {
- var n = ~~Number(port);
- if (n < 1 || n > 65535) {
- isErrRange = true;
- }
- }
- ctrl.$setValidity('range', !isErrRange)
- return isErrRange;
- }
-
- //For DOM -> model validation
- ctrl.$parsers.unshift(function(value) {
- return _isPortInvalid(value) ? undefined : value;
- });
-
- //For model -> DOM validation
- ctrl.$formatters.unshift(function(value) {
- _isPortInvalid(value);
- return value;
- });
- }
- };
-});
-
- return QDR;
-}(QDR || {}));
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrSettings.js b/console/hawtio/src/main/webapp/plugin/js/qdrSettings.js
new file mode 120000
index 0000000..6861eb2
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrSettings.js
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/js/qdrSettings.js
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js b/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js
deleted file mode 100644
index 795549a..0000000
--- a/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js
+++ /dev/null
@@ -1,2132 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
-*/
-/**
- * @module QDR
- */
-var QDR = (function (QDR) {
-
-
- QDR.module.controller('QDR.TopologyFormController', function ($scope, QDRService) {
-
- $scope.attributes = []
- var nameTemplate = '<div title="{{row.entity.description}}" class="ngCellText"><span>{{row.entity.attributeName}}</span></div>';
- var valueTemplate = '<div title="{{row.entity.attributeValue}}" class="ngCellText"><span>{{row.entity.attributeValue}}</span></div>';
- $scope.topoGridOptions = {
- data: 'attributes',
- enableColumnResize: true,
- multiSelect: false,
- columnDefs: [
- {
- field: 'attributeName',
- displayName: 'Attribute',
- cellTemplate: nameTemplate
- },
- {
- field: 'attributeValue',
- displayName: 'Value',
- cellTemplate: valueTemplate
- }
- ]
- };
- $scope.form = ''
- $scope.$on('showEntityForm', function (event, args) {
- var attributes = args.attributes;
- var entityTypes = QDRService.schema.entityTypes[args.entity].attributes;
- attributes.forEach( function (attr) {
- if (entityTypes[attr.attributeName] && entityTypes[attr.attributeName].description)
- attr.description = entityTypes[attr.attributeName].description
- })
- $scope.attributes = attributes;
- $scope.form = args.entity;
- })
- $scope.$on('showAddForm', function (event) {
- $scope.form = 'add';
- })
- })
-
-
- /**
- * @method TopologyController
- *
- * Controller that handles the QDR topology page
- */
- QDR.module.controller("QDR.TopologyController", ['$scope', '$rootScope', 'QDRService', '$location', '$timeout', '$dialog',
- function($scope, $rootScope, QDRService, $location, $timeout, $dialog) {
-
- $scope.multiData = []
- $scope.selectedClient = [];
- $scope.quiesceState = {}
- var dontHide = false;
- $scope.quiesceConnection = function (row) {
- var entity = row.entity;
- var state = $scope.quiesceState[entity.connectionId].state;
- if (state === 'enabled') {
- // start quiescing all links
- $scope.quiesceState[entity.connectionId].state = 'quiescing';
- } else if (state === 'quiesced') {
- // start reviving all links
- $scope.quiesceState[entity.connectionId].state = 'reviving';
- }
- $scope.multiDetails.updateState(entity);
- dontHide = true;
- $scope.multiDetails.selectRow(row.rowIndex, true);
- $scope.multiDetails.showLinksList(row)
- }
- $scope.quiesceDisabled = function (row) {
- return $scope.quiesceState[row.entity.connectionId].buttonDisabled;
- }
- $scope.quiesceText = function (row) {
- return $scope.quiesceState[row.entity.connectionId].buttonText;
- }
- $scope.quiesceClass = function (row) {
- var stateClassMap = {
- enabled: 'btn-primary',
- quiescing: 'btn-warning',
- reviving: 'btn-warning',
- quiesced: 'btn-danger'
- }
- return stateClassMap[$scope.quiesceState[row.entity.connectionId].state];
- }
- $scope.multiDetails = {
- data: 'multiData',
- selectedItems: $scope.selectedClient,
- multiSelect: false,
- afterSelectionChange: function (obj) {
- if (obj.selected && obj.orig) {
- var detailsDiv = d3.select('#link_details')
- var isVis = detailsDiv.style('display') === 'block';
- if (!dontHide && isVis && $scope.connectionId === obj.entity.connectionId) {
- hideLinkDetails();
- return;
- }
- dontHide = false;
- $scope.multiDetails.showLinksList(obj)
- }
- },
- showLinksList: function (obj) {
- $scope.linkData = obj.entity.linkData;
- $scope.connectionId = obj.entity.connectionId;
- var visibleLen = Math.min(obj.entity.linkData.length, 10)
- var left = parseInt(d3.select('#multiple_details').style("left"))
- var detailsDiv = d3.select('#link_details')
- detailsDiv
- .style({
- display: 'block',
- opacity: 1,
- left: (left + 20) + "px",
- top: (mouseY + 20 + $(document).scrollTop()) + "px",
- height: (visibleLen + 1) * 30 + "px", // +1 for the header row
- 'overflow-y': obj.entity.linkData > 10 ? 'scroll' : 'hidden'})
- },
- updateState: function (entity) {
- var state = $scope.quiesceState[entity.connectionId].state
-
- // count enabled and disabled links for this connection
- var enabled = 0, disabled = 0;
- entity.linkData.forEach ( function (link) {
- if (link.adminStatus === 'enabled')
- ++enabled;
- if (link.adminStatus === 'disabled')
- ++disabled;
- })
-
- var linkCount = entity.linkData.length;
- // if state is quiescing and any links are enabled, button should say 'Quiescing' and be disabled
- if (state === 'quiescing' && (enabled > 0)) {
- $scope.quiesceState[entity.connectionId].buttonText = 'Quiescing';
- $scope.quiesceState[entity.connectionId].buttonDisabled = true;
- } else
- // if state is enabled and all links are disabled, button should say Revive and be enabled. set state to quisced
- // if state is quiescing and all links are disabled, button should say 'Revive' and be enabled. set state to quiesced
- if ((state === 'quiescing' || state === 'enabled') && (disabled === linkCount)) {
- $scope.quiesceState[entity.connectionId].buttonText = 'Revive';
- $scope.quiesceState[entity.connectionId].buttonDisabled = false;
- $scope.quiesceState[entity.connectionId].state = 'quiesced'
- } else
- // if state is reviving and any links are disabled, button should say 'Reviving' and be disabled
- if (state === 'reviving' && (disabled > 0)) {
- $scope.quiesceState[entity.connectionId].buttonText = 'Reviving';
- $scope.quiesceState[entity.connectionId].buttonDisabled = true;
- } else
- // if state is reviving or quiesced and all links are enabled, button should say 'Quiesce' and be enabled. set state to enabled
- if ((state === 'reviving' || state === 'quiesced') && (enabled === linkCount)) {
- $scope.quiesceState[entity.connectionId].buttonText = 'Quiesce';
- $scope.quiesceState[entity.connectionId].buttonDisabled = false;
- $scope.quiesceState[entity.connectionId].state = 'enabled'
- }
- },
- columnDefs: [
- {
- field: 'host',
- cellTemplate: "titleCellTemplate.html",
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- displayName: 'Connection host'
- },
- {
- field: 'user',
- cellTemplate: "titleCellTemplate.html",
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- displayName: 'User'
- },
- {
- field: 'properties',
- cellTemplate: "titleCellTemplate.html",
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- displayName: 'Properties'
- }/*,
- {
- cellClass: 'gridCellButton',
- cellTemplate: '<button title="{{quiesceText(row)}} the links" type="button" ng-class="quiesceClass(row)" class="btn" ng-click="$event.stopPropagation();quiesceConnection(row)" ng-disabled="quiesceDisabled(row)">{{quiesceText(row)}}</button>'
- }*/
- ]
- };
- $scope.linkData = [];
- $scope.quiesceLinkClass = function (row) {
- var stateClassMap = {
- enabled: 'btn-primary',
- disabled: 'btn-danger'
- }
- return stateClassMap[row.entity.adminStatus]
- //return stateClassMap[$scope.quiesceState[row.entity.connectionId].linkStates[row.entity.identity]];
- }
- $scope.quiesceLink = function (row) {
- var state = row.entity.adminStatus === 'enabled' ? 'disabled' : 'enabled';
- $scope.quiesceState[row.entity.connectionId].linkStates[row.entity.identity] = state;
- }
- $scope.quiesceLinkDisabled = function (row) {
- return false;
- }
- $scope.quiesceLinkText = function (row) {
- return row.entity.adminStatus === 'disabled' ? "Revive" : "Quiesce";
- }
- $scope.linkDetails = {
- data: 'linkData',
- columnDefs: [
- {
- field: 'adminStatus',
- cellTemplate: "titleCellTemplate.html",
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- displayName: 'Admin stat'
- },
- {
- field: 'dir',
- cellTemplate: "titleCellTemplate.html",
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- displayName: 'dir'
- },
- {
- field: 'owningAddr',
- cellTemplate: "titleCellTemplate.html",
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- displayName: 'Address'
- },
- {
- field: 'deliveryCount',
- displayName: 'Delivered',
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- cellClass: 'grid-values'
-
- },
- {
- field: 'undeliveredCount',
- displayName: 'Undelivered',
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- cellClass: 'grid-values'
- },
- {
- field: 'unsettledCount',
- displayName: 'Unsettled',
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- cellClass: 'grid-values'
- }/*,
-
- {
- cellClass: 'gridCellButton',
- cellTemplate: '<button title="{{quiesceLinkText(row)}} this link" type="button" ng-class="quiesceLinkClass(row)" class="btn" ng-click="quiesceLink(row)" ng-disabled="quiesceLinkDisabled(row)">{{quiesceLinkText(row)}}</button>'
- }*/
- ]
- }
-
- if (!QDRService.connected) {
- // we are not connected. we probably got here from a bookmark or manual page reload
- QDRService.redirectWhenConnected("topology");
- return;
- }
- // we are currently connected. setup a handler to get notified if we are ever disconnected
- QDRService.addDisconnectAction( function () {
- QDRService.redirectWhenConnected("topology");
- $scope.$apply();
- })
-
- QDR.log.debug("started QDR.TopologyController with urlPrefix: " + $location.absUrl());
- var urlPrefix = $location.absUrl();
-
- $scope.addingNode = {
- step: 0,
- hasLink: false,
- trigger: ''
- };
-
- $scope.cancel = function () {
- $scope.addingNode.step = 0;
- }
- $scope.editNewRouter = function () {
- $scope.addingNode.trigger = 'editNode';
- }
-
- var NewRouterName = "__NEW__";
- // mouse event vars
- var selected_node = null,
- selected_link = null,
- mousedown_link = null,
- mousedown_node = null,
- mouseup_node = null,
- initial_mouse_down_position = null;
-
- $scope.schema = "Not connected";
-
- $scope.modes = [
- {title: 'Topology view', name: 'Diagram', right: false},
- /* {title: 'Add a new router node', name: 'Add Router', right: true} */
- ];
- $scope.mode = "Diagram";
- $scope.contextNode = null; // node that is associated with the current context menu
-
- $scope.isModeActive = function (name) {
- if ((name == 'Add Router' || name == 'Diagram') && $scope.addingNode.step > 0)
- return true;
- return ($scope.mode == name);
- }
- $scope.selectMode = function (name) {
- if (name == "Add Router") {
- name = 'Diagram';
- if ($scope.addingNode.step > 0) {
- $scope.addingNode.step = 0;
- } else {
- // start adding node mode
- $scope.addingNode.step = 1;
- }
- } else {
- $scope.addingNode.step = 0;
- }
-
- $scope.mode = name;
- }
- $scope.$watch(function () {return $scope.addingNode.step}, function (newValue, oldValue) {
- if (newValue == 0 && oldValue != 0) {
- // we are cancelling the add
-
- // find the New node
- nodes.every(function (n, i) {
- // for the placeholder node, the key will be __internal__
- if (QDRService.nameFromId(n.key) == '__internal__') {
- var newLinks = links.filter(function (e, i) {
- return e.source.id == n.id || e.target.id == n.id;
- })
- // newLinks is an array of links to remove
- newLinks.map(function (e) {
- links.splice(links.indexOf(e), 1);
- })
- // i is the index of the node to remove
- nodes.splice(i, 1);
- force.nodes(nodes).links(links).start();
- restart(false);
- return false; // stop looping
- }
- return true;
- })
- updateForm(Object.keys(QDRService.topology.nodeInfo())[0], 'router', 0);
-
- } else if (newValue > 0) {
- // we are starting the add mode
- $scope.$broadcast('showAddForm')
-
- resetMouseVars();
- selected_node = null;
- selected_link = null;
- // add a new node
- var id = "amqp:/_topo/0/__internal__/$management";
- var x = radiusNormal * 4;
- var y = x;;
- if (newValue > 1) { // add at current mouse position
- var offset = jQuery('#topology').offset();
- x = mouseX - offset.left + $(document).scrollLeft();
- y = mouseY - offset.top + $(document).scrollTop();;
- }
- NewRouterName = genNewName();
- nodes.push( aNode(id, NewRouterName, "inter-router", undefined, nodes.length, x, y, undefined, true) );
- force.nodes(nodes).links(links).start();
- restart(false);
- }
-
- })
- $scope.isRight = function (mode) {
- return mode.right;
- }
-
- // for ng-grid that shows details for multiple consoles/clients
- // generate unique name for router and containerName
- var genNewName = function () {
- var nodeInfo = QDRService.topology.nodeInfo();
- var nameIndex = 1;
- var newName = "R." + nameIndex;
-
- var names = [];
- for (key in nodeInfo) {
- var node = nodeInfo[key];
- var router = node['.router'];
- var attrNames = router.attributeNames;
- var name = QDRService.valFor(attrNames, router.results[0], 'routerId')
- if (!name)
- name = QDRService.valFor(attrNames, router.results[0], 'name')
- names.push(name);
- }
-
- while (names.indexOf(newName) >= 0) {
- newName = "R." + nameIndex++;
- }
- return newName;
- }
-
- $scope.$watch(function () {return $scope.addingNode.trigger}, function (newValue, oldValue) {
- if (newValue == 'editNode') {
- $scope.addingNode.trigger = "";
- editNode();
- }
- })
-
- function editNode() {
- doAddDialog(NewRouterName);
- };
- $scope.reverseLink = function () {
- if (!mousedown_link)
- return;
- var d = mousedown_link;
- var tmp = d.left;
- d.left = d.right;;
- d.right = tmp;
- restart(false);
- tick();
- }
- $scope.removeLink = function () {
- if (!mousedown_link)
- return;
- var d = mousedown_link;
- links.every( function (l, i) {
- if (l.source.id == d.source.id && l.target.id == d.target.id) {
- links.splice(i, 1);
- force.links(links).start();
- return false; // exit the 'every' loop
- }
- return true;
- });
- restart(false);
- tick();
- }
- $scope.setFixed = function (b) {
- if ($scope.contextNode) {
- $scope.contextNode.fixed = b;
- }
- restart();
- }
- $scope.isFixed = function () {
- if (!$scope.contextNode)
- return false;
- return ($scope.contextNode.fixed & 0b1);
- }
-
- var mouseX, mouseY;
- // event handlers for popup context menu
- $(document).mousemove(function (e) {
- mouseX = e.clientX;
- mouseY = e.clientY;
- });
- $(document).mousemove();
- $(document).click(function (e) {
- $scope.contextNode = null;
- $(".contextMenu").fadeOut(200);
- });
-
- // set up SVG for D3
- var width, height;
- var tpdiv = $('#topology');
- var colors = {'inter-router': "#EAEAEA", 'normal': "#F0F000", 'on-demand': '#00F000'};
- var gap = 5;
- var radii = {'inter-router': 25, 'normal': 15, 'on-demand': 15};
- var radius = 25;
- var radiusNormal = 15;
- width = tpdiv.width() - gap;
- height = $('#main').height() - $('#topology').position().top - gap;
- if (width < 10 && height < 10) {
- QDR.log.info("page width and height are abynormal: returning before very bad things happen")
- return;
- }
-
- var svg, lsvg;
- var force;
- var animate = false; // should the force graph organize itself when it is displayed
- var path, circle;
- var savedKeys = {};
- var dblckickPos = [0,0];
-
- // set up initial nodes and links
- // - nodes are known by 'id', not by index in array.
- // - selected edges are indicated on the node (as a bold red circle).
- // - links are always source < target; edge directions are set by 'left' and 'right'.
- var nodes = [];
- var links = [];
-
- var aNode = function (id, name, nodeType, nodeInfo, nodeIndex, x, y, resultIndex, fixed, properties) {
- properties = properties || {};
- var routerId;
- if (nodeInfo) {
- var node = nodeInfo[id];
- if (node) {
- var router = node['.router'];
- routerId = QDRService.valFor(router.attributeNames, router.results[0], 'id')
- if (!routerId)
- routerId = QDRService.valFor(router.attributeNames, router.results[0], 'routerId')
- }
- }
- return { key: id,
- name: name,
- nodeType: nodeType,
- properties: properties,
- routerId: routerId,
- x: x,
- y: y,
- id: nodeIndex,
- resultIndex: resultIndex,
- fixed: fixed,
- cls: name == NewRouterName ? 'temp' : ''
- };
- };
-
-
- var initForm = function (attributes, results, entityType, formFields) {
-
- while(formFields.length > 0) {
- // remove all existing attributes
- formFields.pop();
- }
-
- for (var i=0; i<attributes.length; ++i) {
- var name = attributes[i];
- var val = results[i];
- var desc = "";
- if (entityType.attributes[name])
- if (entityType.attributes[name].description)
- desc = entityType.attributes[name].description;
-
- formFields.push({'attributeName': name, 'attributeValue': val, 'description': desc});
- }
- }
-
- // initialize the nodes and links array from the QDRService.topology._nodeInfo object
- var initForceGraph = function () {
- nodes = [];
- links = [];
-
- svg = d3.select('#topology')
- .append('svg')
- .attr("id", "SVG_ID")
- .attr('width', width)
- .attr('height', height)
- .on("contextmenu", function(d) {
- if (d3.event.defaultPrevented)
- return;
- d3.event.preventDefault();
- if ($scope.addingNode.step != 0)
- return;
- if (d3.select('#svg_context_menu').style('display') !== 'block')
- $(document).click();
- d3.select('#svg_context_menu')
- .style('left', (mouseX + $(document).scrollLeft()) + "px")
- .style('top', (mouseY + $(document).scrollTop()) + "px")
- .style('display', 'block');
- })
- .on('click', function (d) {
- removeCrosssection()
- });
-
- $(document).keyup(function(e) {
- if (e.keyCode === 27) {
- removeCrosssection()
- }
- });
-
- // the legend
- lsvg = d3.select("#svg_legend")
- .append('svg')
- .attr('id', 'svglegend')
- lsvg = lsvg.append('svg:g')
- .attr('transform', 'translate('+(radii['inter-router']+2)+','+(radii['inter-router']+2)+')')
- .selectAll('g');
-
- // mouse event vars
- selected_node = null;
- selected_link = null;
- mousedown_link = null;
- mousedown_node = null;
- mouseup_node = null;
-
- // initialize the list of nodes
- var yInit = 10;
- var nodeInfo = QDRService.topology.nodeInfo();
- var nodeCount = Object.keys(nodeInfo).length;
- for (var id in nodeInfo) {
- var name = QDRService.nameFromId(id);
- // if we have any new nodes, animate the force graph to position them
- var position = angular.fromJson(localStorage[name]);
- if (!angular.isDefined(position)) {
- animate = true;
- position = {x: width / 4 + ((width / 2)/nodeCount) * nodes.length,
- y: 200 + yInit,
- fixed: false};
- }
- if (position.y > height)
- position.y = 200 - yInit;
- nodes.push( aNode(id, name, "inter-router", nodeInfo, nodes.length, position.x, position.y, undefined, position.fixed) );
- yInit *= -1;
- //QDR.log.debug("adding node " + nodes.length-1);
- }
-
- // initialize the list of links
- var source = 0;
- var client = 1;
- for (var id in nodeInfo) {
- var onode = nodeInfo[id];
- var conns = onode['.connection'].results;
- var attrs = onode['.connection'].attributeNames;
- var parent = getNodeIndex(QDRService.nameFromId(id));
- //QDR.log.debug("external client parent is " + parent);
- var normalsParent = {console: undefined, client: undefined}; // 1st normal node for this parent
-
- for (var j = 0; j < conns.length; j++) {
- var role = QDRService.valFor(attrs, conns[j], "role");
- var properties = QDRService.valFor(attrs, conns[j], "properties") || {};
- var dir = QDRService.valFor(attrs, conns[j], "dir");
- if (role == "inter-router") {
- var connId = QDRService.valFor(attrs, conns[j], "container");
- var target = getContainerIndex(connId);
- if (target >= 0)
- getLink(source, target, dir);
- } else if (role == "normal" || role == "on-demand") {
- // not a router, but an external client
- //QDR.log.debug("found an external client for " + id);
- var name = QDRService.nameFromId(id) + "." + client;
- //QDR.log.debug("external client name is " + name + " and the role is " + role);
-
- // if we have any new clients, animate the force graph to position them
- var position = angular.fromJson(localStorage[name]);
- if (!angular.isDefined(position)) {
- animate = true;
- position = {x: nodes[parent].x + 40 + Math.sin(Math.PI/2 * client),
- y: nodes[parent].y + 40 + Math.cos(Math.PI/2 * client),
- fixed: false};
- }
- if (position.y > height)
- position.y = nodes[parent].y + 40 + Math.cos(Math.PI/2 * client)
- var node = aNode(id, name, role, nodeInfo, nodes.length, position.x, position.y, j, position.fixed, properties)
- var nodeType = QDRService.isAConsole(properties, QDRService.valFor(attrs, conns[j], "identity"), role, node.key)
-
- if (role === 'normal') {
- node.user = QDRService.valFor(attrs, conns[j], "user")
- node.isEncrypted = QDRService.valFor(attrs, conns[j], "isEncrypted")
- node.host = QDRService.valFor(attrs, conns[j], "host")
- node.connectionId = QDRService.valFor(attrs, conns[j], "identity")
-
- if (!normalsParent[nodeType]) {
- normalsParent[nodeType] = node;
- nodes.push( node );
- node.normals = [node];
- // now add a link
- getLink(parent, nodes.length-1, dir);
- client++;
- } else {
- normalsParent[nodeType].normals.push(node)
- }
- } else {
- nodes.push( node)
- // now add a link
- getLink(parent, nodes.length-1, dir);
- client++;
- }
- }
- }
- source++;
- }
-
- $scope.schema = QDRService.schema;
- // init D3 force layout
- force = d3.layout.force()
- .nodes(nodes)
- .links(links)
- .size([width, height])
- .linkDistance(function(d) { return d.target.nodeType === 'inter-router' ? 150 : 65 })
- .charge(-1800)
- .friction(.10)
- .gravity(0.0001)
- .on('tick', tick)
- .start()
-
- svg.append("svg:defs").selectAll('marker')
- .data(["end-arrow", "end-arrow-selected"]) // Different link/path types can be defined here
- .enter().append("svg:marker") // This section adds in the arrows
- .attr("id", String)
- .attr("viewBox", "0 -5 10 10")
- //.attr("refX", 25)
- .attr("markerWidth", 4)
- .attr("markerHeight", 4)
- .attr("orient", "auto")
- .append("svg:path")
- .attr('d', 'M 0 -5 L 10 0 L 0 5 z')
-
- svg.append("svg:defs").selectAll('marker')
- .data(["start-arrow", "start-arrow-selected"]) // Different link/path types can be defined here
- .enter().append("svg:marker") // This section adds in the arrows
- .attr("id", String)
- .attr("viewBox", "0 -5 10 10")
- .attr("refX", 5)
- .attr("markerWidth", 4)
- .attr("markerHeight", 4)
- .attr("orient", "auto")
- .append("svg:path")
- .attr('d', 'M 10 -5 L 0 0 L 10 5 z');
-
- // handles to link and node element groups
- path = svg.append('svg:g').selectAll('path'),
- circle = svg.append('svg:g').selectAll('g');
-
- force.on('end', function() {
- //QDR.log.debug("force end called");
- circle
- .attr('cx', function(d) {
- localStorage[d.name] = angular.toJson({x: d.x, y: d.y, fixed: d.fixed});
- return d.x; });
- });
-
- // app starts here
- restart(false);
- force.start();
- setTimeout(function () {
- updateForm(Object.keys(QDRService.topology.nodeInfo())[0], 'router', 0);
- }, 10)
-
- }
-
- function updateForm (key, entity, resultIndex) {
- var nodeInfo = QDRService.topology.nodeInfo();
- var onode = nodeInfo[key]
- if (onode) {
- var nodeResults = onode['.' + entity].results[resultIndex]
- var nodeAttributes = onode['.' + entity].attributeNames
- var attributes = nodeResults.map( function (row, i) {
- return {
- attributeName: nodeAttributes[i],
- attributeValue: row
- }
- })
- // sort by attributeName
- attributes.sort( function (a, b) { return a.attributeName.localeCompare(b.attributeName) })
-
- // move the Name first
- var nameIndex = attributes.findIndex ( function (attr) {
- return attr.attributeName === 'name'
- })
- if (nameIndex >= 0)
- attributes.splice(0, 0, attributes.splice(nameIndex, 1)[0]);
- // get the list of ports this router is listening on
- if (entity === 'router') {
- var listeners = onode['.listener'].results;
- var listenerAttributes = onode['.listener'].attributeNames;
- var normals = listeners.filter ( function (listener) {
- return QDRService.valFor( listenerAttributes, listener, 'role') === 'normal';
- })
- var ports = []
- normals.forEach (function (normalListener) {
- ports.push(QDRService.valFor( listenerAttributes, normalListener, 'port'))
- })
- // add as 2nd row
- if (ports.length)
- attributes.splice(1, 0, {attributeName: 'Listening on', attributeValue: ports, description: 'The port on which this router is listening for connections'});
- }
-
- $scope.$broadcast('showEntityForm', {entity: entity, attributes: attributes})
- }
- if (!$scope.$$phase) $scope.$apply()
- }
-
- function getContainerIndex(_id) {
- var nodeIndex = 0;
- var nodeInfo = QDRService.topology.nodeInfo();
- for (var id in nodeInfo) {
- var node = nodeInfo[id]['.router'];
- // there should be only one router entity for each node, so using results[0] should be fine
- if (QDRService.valFor( node.attributeNames, node.results[0], "id") === _id)
- return nodeIndex;
- if (QDRService.valFor( node.attributeNames, node.results[0], "routerId") === _id)
- return nodeIndex;
- nodeIndex++
- }
- // there was no router.id that matched, check deprecated router.routerId
- nodeIndex = 0;
- for (var id in nodeInfo) {
- var node = nodeInfo[id]['.container'];
- if (node) {
- if (QDRService.valFor ( node.attributeNames, node.results[0], "containerName") === _id)
- return nodeIndex;
- }
- nodeIndex++
- }
- //QDR.log.warn("unable to find containerIndex for " + _id);
- return -1;
- }
-
- function getNodeIndex (_id) {
- var nodeIndex = 0;
- var nodeInfo = QDRService.topology.nodeInfo();
- for (var id in nodeInfo) {
- if (QDRService.nameFromId(id) == _id) return nodeIndex;
- nodeIndex++
- }
- QDR.log.warn("unable to find nodeIndex for " + _id);
- return -1;
- }
-
- function getLink (_source, _target, dir, cls) {
- for (var i=0; i < links.length; i++) {
- var s = links[i].source, t = links[i].target;
- if (typeof links[i].source == "object") {
- s = s.id;
- t = t.id;
- }
- if (s == _source && t == _target) {
- return i;
- }
- // same link, just reversed
- if (s == _target && t == _source) {
- return -i;
- }
- }
-
- //QDR.log.debug("creating new link (" + (links.length) + ") between " + nodes[_source].name + " and " + nodes[_target].name);
- var link = {
- source: _source,
- target: _target,
- left: dir != "out",
- right: dir == "out",
- cls: cls
- };
- return links.push(link) - 1;
- }
-
-
- function resetMouseVars() {
- mousedown_node = null;
- mouseup_node = null;
- mousedown_link = null;
- }
-
- // update force layout (called automatically each iteration)
- function tick() {
- circle.attr('transform', function (d) {
- var cradius;
- if (d.nodeType == "inter-router") {
- cradius = d.left ? radius + 8 : radius;
- } else {
- cradius = d.left ? radiusNormal + 18 : radiusNormal;
- }
- d.x = Math.max(d.x, radiusNormal * 2);
- d.y = Math.max(d.y, radiusNormal * 2);
- d.x = Math.max(0, Math.min(width-cradius, d.x))
- d.y = Math.max(0, Math.min(height-cradius, d.y))
- return 'translate(' + d.x + ',' + d.y + ')';
- });
-
- // draw directed edges with proper padding from node centers
- path.attr('d', function (d) {
- //QDR.log.debug("in tick for d");
- //console.dump(d);
- var sourcePadding, targetPadding, r;
-
- if (d.target.nodeType == "inter-router") {
- r = radius;
- // right arrow left line start
- sourcePadding = d.left ? radius + 8 : radius;
- // left arrow right line start
- targetPadding = d.right ? radius + 16 : radius;
- } else {
- r = radiusNormal - 18;
- sourcePadding = d.left ? radiusNormal + 18 : radiusNormal;
- targetPadding = d.right ? radiusNormal + 16 : radiusNormal;
- }
- var dtx = Math.max(targetPadding, Math.min(width-r, d.target.x)),
- dty = Math.max(targetPadding, Math.min(height-r, d.target.y)),
- dsx = Math.max(sourcePadding, Math.min(width-r, d.source.x)),
- dsy = Math.max(sourcePadding, Math.min(height-r, d.source.y));
-
- var deltaX = dtx - dsx,
- deltaY = dty - dsy,
- dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY),
- normX = deltaX / dist,
- normY = deltaY / dist;
- var sourceX = dsx + (sourcePadding * normX),
- sourceY = dsy + (sourcePadding * normY),
- targetX = dtx - (targetPadding * normX),
- targetY = dty - (targetPadding * normY);
- sourceX = Math.max(0, Math.min(width, sourceX))
- sourceY = Math.max(0, Math.min(width, sourceY))
- targetX = Math.max(0, Math.min(width, targetX))
- targetY = Math.max(0, Math.min(width, targetY))
-
- return 'M' + sourceX + ',' + sourceY + 'L' + targetX + ',' + targetY;
- });
-
- if (!animate) {
- animate = true;
- force.stop();
- }
- }
-
- // highlight the paths between the selected node and the hovered node
- function findNextHopNode(from, d) {
- // d is the node that the mouse is over
- // from is the selected_node ....
- if (!from)
- return null;
-
- if (from == d)
- return selected_node;
-
- //QDR.log.debug("finding nextHop from: " + from.name + " to " + d.name);
- var sInfo = QDRService.topology.nodeInfo()[from.key];
-
- if (!sInfo) {
- QDR.log.warn("unable to find topology node info for " + from.key);
- return null;
- }
-
- // find the hovered name in the selected name's .router.node results
- if (!sInfo['.router.node'])
- return null;
- var aAr = sInfo['.router.node'].attributeNames;
- var vAr = sInfo['.router.node'].results;
- for (var hIdx=0; hIdx<vAr.length; ++hIdx) {
- var addrT = QDRService.valFor(aAr, vAr[hIdx], "id" );
- if (addrT == d.name) {
- //QDR.log.debug("found " + d.name + " at " + hIdx);
- var nextHop = QDRService.valFor(aAr, vAr[hIdx], "nextHop");
- //QDR.log.debug("nextHop was " + nextHop);
- return (nextHop == null) ? nodeFor(addrT) : nodeFor(nextHop);
- }
- }
- return null;
- }
-
- function nodeFor(name) {
- for (var i=0; i<nodes.length; ++i) {
- if (nodes[i].name == name)
- return nodes[i];
- }
- return null;
- }
-
- function linkFor(source, target) {
- for (var i=0; i<links.length; ++i) {
- if ((links[i].source == source) && (links[i].target == target))
- return links[i];
- if ((links[i].source == target) && (links[i].target == source))
- return links[i];
- }
- // the selected node was a client/broker
- //QDR.log.debug("failed to find a link between ");
- //console.dump(source);
- //QDR.log.debug(" and ");
- //console.dump(target);
- return null;
- }
-
- function clearPopups() {
- d3.select("#crosssection").style("display", "none");
- $('.hastip').empty();
- d3.select("#multiple_details").style("display", "none")
- d3.select("#link_details").style("display", "none")
- d3.select('#node_context_menu').style('display', 'none');
-
- }
- function removeCrosssection() {
- setTimeout(function () {
- d3.select("[id^=tooltipsy]").remove()
- $('.hastip').empty();
- }, 1010);
- d3.select("#crosssection svg g").transition()
- .duration(1000)
- .attr("transform", "translate("+(dblckickPos[0]-140) + "," + (dblckickPos[1]-100) + ") scale(0)")
- .style("opacity", 0)
- .each("end", function (d) {
- d3.select("#crosssection svg").remove();
- d3.select("#crosssection").style("display","none");
- });
- d3.select("#multiple_details").transition()
- .duration(500)
- .style("opacity", 0)
- .each("end", function (d) {
- d3.select("#multiple_details").style("display", "none")
- stopUpdateConnectionsGrid();
- })
- hideLinkDetails();
- }
- function hideLinkDetails() {
- d3.select("#link_details").transition()
- .duration(500)
- .style("opacity", 0)
- .each("end", function (d) {
- d3.select("#link_details").style("display", "none")
- })
- }
-
- // takes the nodes and links array of objects and adds svg elements for everything that hasn't already
- // been added
- function restart(start) {
- circle.call(force.drag);
-
- // path (link) group
- path = path.data(links);
-
- // update existing links
- path.classed('selected', function(d) { return d === selected_link; })
- .classed('highlighted', function(d) { return d.highlighted; } )
- .classed('temp', function(d) { return d.cls == 'temp'; } )
- .attr('marker-start', function(d) {
- var sel = d===selected_link ? '-selected' : '';
- return d.left ? 'url('+urlPrefix+'#start-arrow' + sel + ')' : ''; })
- .attr('marker-end', function(d) {
- var sel = d===selected_link ? '-selected' : '';
- return d.right ? 'url('+urlPrefix+'#end-arrow' + sel +')' : ''; })
-
-
- // add new links. if links[] is longer than the existing paths, add a new path for each new element
- path.enter().append('svg:path')
- .attr('class', 'link')
- .attr('marker-start', function(d) {
- var sel = d===selected_link ? '-selected' : '';
- return d.left ? 'url('+urlPrefix+'#start-arrow' + sel + ')' : ''; })
- .attr('marker-end', function(d) {
- var sel = d===selected_link ? '-selected' : '';
- return d.right ? 'url('+urlPrefix+'#end-arrow' + sel + ')' : ''; })
- .classed('temp', function(d) { return d.cls == 'temp'; } )
- .on('mouseover', function (d) {
- if($scope.addingNode.step > 0) {
- if (d.cls == 'temp') {
- d3.select(this).classed('over', true);
- }
- return;
- }
- //QDR.log.debug("showing connections form");
- var resultIndex = 0; // the connection to use
- var left = d.left ? d.target : d.source;
- // right is the node that the arrow points to, left is the other node
- var right = d.left ? d.source : d.target;
- var onode = QDRService.topology.nodeInfo()[left.key];
- // loop through all the connections for left, and find the one for right
- if (!onode || !onode['.connection'])
- return;
- // update the info dialog for the link the mouse is over
- if (!selected_node && !selected_link) {
- for (resultIndex=0; resultIndex < onode['.connection'].results.length; ++resultIndex) {
- var conn = onode['.connection'].results[resultIndex];
- /// find the connection whose container is the right's name
- var name = QDRService.valFor(onode['.connection'].attributeNames, conn, "container");
- if (name == right.routerId) {
- break;
- }
- }
- // did not find connection. this is a connection to a non-interrouter node
- if (resultIndex === onode['.connection'].results.length) {
- // use the non-interrouter node's connection info
- left = d.target;
- resultIndex = left.resultIndex;
- }
- if (resultIndex)
- updateForm(left.key, 'connection', resultIndex);
- }
-
- mousedown_link = d;
- selected_link = mousedown_link;
- restart();
- })
- .on('mouseout', function (d) {
- if($scope.addingNode.step > 0) {
- if (d.cls == 'temp') {
- d3.select(this).classed('over', false);
- }
- return;
- }
- //QDR.log.debug("showing connections form");
- selected_link = null;
- restart();
- })
- .on("contextmenu", function(d) {
- $(document).click();
- d3.event.preventDefault();
- if (d.cls !== "temp")
- return;
-
- mousedown_link = d;
- d3.select('#link_context_menu')
- .style('left', (mouseX + $(document).scrollLeft()) + "px")
- .style('top', (mouseY + $(document).scrollTop()) + "px")
- .style('display', 'block');
- })
- .on("click", function (d) {
- dblckickPos = d3.mouse(this);
- QDR.log.debug("dblckickPos is [" + dblckickPos[0] + ", " + dblckickPos[1] + "]")
- d3.event.stopPropagation();
- clearPopups();
- var diameter = 400;
- var format = d3.format(",d");
- var pack = d3.layout.pack()
- .size([diameter - 4, diameter - 4])
- .padding(-10)
- .value(function(d) { return d.size; });
-
- d3.select("#crosssection svg").remove();
- var svg = d3.select("#crosssection").append("svg")
- .attr("width", diameter)
- .attr("height", diameter)
- var svgg = svg.append("g")
- .attr("transform", "translate(2,2)");
-
- var root = {
- name: "links between " + d.source.name + " and " + d.target.name,
- children: []
- }
- var nodeInfo = QDRService.topology.nodeInfo();
- var connections = nodeInfo[d.source.key]['.connection'];
- var containerIndex = connections.attributeNames.indexOf('container');
- connections.results.some ( function (connection) {
- if (connection[containerIndex] == d.target.routerId) {
- root.attributeNames = connections.attributeNames;
- root.obj = connection;
- root.desc = "Connection";
- return true; // stop looping after 1 match
- }
- return false;
- })
-
- // find router.links where link.remoteContainer is d.source.name
- var links = nodeInfo[d.source.key]['.router.link'];
- var identityIndex = connections.attributeNames.indexOf('identity')
- var roleIndex = connections.attributeNames.indexOf('role')
- var connectionIdIndex = links.attributeNames.indexOf('connectionId');
- var linkTypeIndex = links.attributeNames.indexOf('linkType');
- var nameIndex = links.attributeNames.indexOf('name');
- var linkDirIndex = links.attributeNames.indexOf('linkDir');
-
- if (roleIndex < 0 || identityIndex < 0 || connectionIdIndex < 0
- || linkTypeIndex < 0 || nameIndex < 0 || linkDirIndex < 0)
- return;
- links.results.forEach ( function (link) {
- if (root.obj && link[connectionIdIndex] == root.obj[identityIndex] && link[linkTypeIndex] == root.obj[roleIndex])
- root.children.push (
- { name: "(" + link[linkDirIndex] + ") " + link[nameIndex],
- size: 100,
- obj: link,
- desc: "Link",
- attributeNames: links.attributeNames
- })
- })
- if (root.children.length == 0)
- return;
- var node = svgg.datum(root).selectAll(".node")
- .data(pack.nodes)
- .enter().append("g")
- .attr("class", function(d) { return d.children ? "parent node hastip" : "leaf node hastip"; })
- .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")" + (!d.children ? "scale(0.9)" : ""); })
- .attr("title", function (d) {
- var title = "<h4>" + d.desc + "</h4><table class='tiptable'><tbody>";
- if (d.attributeNames)
- d.attributeNames.forEach( function (n, i) {
- title += "<tr><td>" + n + "</td><td>";
- title += d.obj[i] != null ? d.obj[i] : '';
- title += '</td></tr>';
- })
- title += "</tbody></table>"
- return title
- })
-
- node.append("circle")
- .attr("r", function(d) { return d.r; });
-
-// node.filter(function(d) { return !d.children; }).append("text")
- node.append("text")
- .attr("dy", function (d) { return d.children ? "-10em" : ".3em"})
- .style("text-anchor", "middle")
- .text(function(d) {
- return d.name.substring(0, d.r / 3);
- });
-
- $('.hastip').tooltipsy({ alignTo: 'cursor'});
- svgg.attr("transform", "translate("+(dblckickPos[0]-140) + "," + (dblckickPos[1]-100) + ") scale(0.01)")
- d3.select("#crosssection").style("display","block");
-
- svgg.transition().attr("transform", "translate(2,2) scale(1)")
- })
-
- // remove old links
- path.exit().remove();
-
-
- // circle (node) group
- // nodes are known by id
- circle = circle.data(nodes, function (d) {
- return d.id;
- });
-
- // update existing nodes visual states
- circle.selectAll('circle')
- .classed('selected', function (d) { return (d === selected_node) })
- .classed('fixed', function (d) { return (d.fixed & 0b1) })
-
- // add new circle nodes. if nodes[] is longer than the existing paths, add a new path for each new element
- var g = circle.enter().append('svg:g')
- .classed('multiple', function(d) { return (d.normals && d.normals.length > 1) } )
-
- var appendCircle = function (g) {
- // add new circles and set their attr/class/behavior
- return g.append('svg:circle')
- .attr('class', 'node')
- .attr('r', function (d) { return radii[d.nodeType] } )
- .classed('fixed', function (d) {return d.fixed})
- .classed('temp', function(d) { return QDRService.nameFromId(d.key) == '__internal__'; } )
- .classed('normal', function(d) { return d.nodeType == 'normal' } )
- .classed('inter-router', function(d) { return d.nodeType == 'inter-router' } )
- .classed('on-demand', function(d) { return d.nodeType == 'on-demand' } )
- .classed('console', function(d) { return QDRService.isConsole(d) } )
- .classed('artemis', function(d) { return QDRService.isArtemis(d) } )
- .classed('qpid-cpp', function(d) { return QDRService.isQpid(d) } )
- .classed('client', function(d) { return d.nodeType === 'normal' && !d.properties.console_identifier } )
- }
- appendCircle(g).on('mouseover', function (d) {
- if ($scope.addingNode.step > 0) {
- d3.select(this).attr('transform', 'scale(1.1)');
- return;
- }
- if (!selected_node) {
- if (d.nodeType === 'inter-router') {
- //QDR.log.debug("showing general form");
- updateForm(d.key, 'router', 0);
- } else if (d.nodeType === 'normal' || d.nodeType === 'on-demand') {
- //QDR.log.debug("showing connections form");
- updateForm(d.key, 'connection', d.resultIndex);
- }
- }
-
- if (d === mousedown_node)
- return;
- //if (d === selected_node)
- // return;
- // enlarge target node
- d3.select(this).attr('transform', 'scale(1.1)');
- // highlight the next-hop route from the selected node to this node
- mousedown_node = null;
-
- if (!selected_node) {
- return;
- }
- setTimeout(nextHop, 1, selected_node, d);
- })
- .on('mouseout', function (d) {
- // unenlarge target node
- d3.select(this).attr('transform', '');
- for (var i=0; i<links.length; ++i) {
- links[i]['highlighted'] = false;
- }
- restart();
- })
- .on('mousedown', function (d) {
- if (d3.event.button !== 0) { // ignore all but left button
- return;
- }
- mousedown_node = d;
- // mouse position relative to svg
- initial_mouse_down_position = d3.mouse(this.parentElement.parentElement.parentElement).slice();
- })
- .on('mouseup', function (d) {
- if (!mousedown_node)
- return;
-
- selected_link = null;
- // unenlarge target node
- d3.select(this).attr('transform', '');
-
- // check for drag
- mouseup_node = d;
- var mySvg = this.parentElement.parentElement.parentElement;
- // if we dragged the node, make it fixed
- var cur_mouse = d3.mouse(mySvg);
- if (cur_mouse[0] != initial_mouse_down_position[0] ||
- cur_mouse[1] != initial_mouse_down_position[1]) {
- console.log("mouse pos changed. making this node fixed")
- d3.select(this).classed("fixed", d.fixed = true);
- resetMouseVars();
- return;
- }
-
- // we didn't drag, we just clicked on the node
- if ($scope.addingNode.step > 0) {
- if (d.nodeType !== 'inter-router')
- return;
- if (QDRService.nameFromId(d.key) == '__internal__')
- return;
-
- // add a link from the clicked node to the new node
- getLink(d.id, nodes.length-1, "in", "temp");
- $scope.addingNode.hasLink = true;
- if (!$scope.$$phase) $scope.$apply()
- // add new elements to the svg
- force.links(links).start();
- restart();
- return;
-
- }
-
- // if this node was selected, unselect it
- if (mousedown_node === selected_node) {
- selected_node = null;
- }
- else {
- if (d.nodeType !== 'normal' && d.nodeType !== 'on-demand')
- selected_node = mousedown_node;
- }
- for (var i=0; i<links.length; ++i) {
- links[i]['highlighted'] = false;
- }
- mousedown_node = null;
- if (!$scope.$$phase) $scope.$apply()
- restart(false);
-
- })
- .on("dblclick", function (d) {
- if (d.fixed) {
- d3.select(this).classed("fixed", d.fixed = false);
- force.start(); // let the nodes move to a new position
- }
- if (QDRService.nameFromId(d.key) == '__internal__') {
- editNode();
- if (!$scope.$$phase) $scope.$apply()
- }
- })
- .on("contextmenu", function(d) {
- $(document).click();
- d3.event.preventDefault();
- $scope.contextNode = d;
- if (!$scope.$$phase) $scope.$apply() // we just changed a scope valiable during an async event
- d3.select('#node_context_menu')
- .style('left', (mouseX + $(document).scrollLeft()) + "px")
- .style('top', (mouseY + $(document).scrollTop()) + "px")
- .style('display', 'block');
-
- })
- .on("click", function (d) {
- // clicked on a circle
- clearPopups();
- if (!d.normals) {
- // circle was a router or a broker
- if ( QDRService.isArtemis(d) && Core.ConnectionName === 'Artemis' ) {
- $location.path('/jmx/attributes?tab=artemis&con=Artemis')
- }
- return;
- }
- clickPos = d3.mouse(this);
- d3.event.stopPropagation();
- startUpdateConnectionsGrid(d);
- })
-
- var appendContent = function (g) {
- // show node IDs
- g.append('svg:text')
- .attr('x', 0)
- .attr('y', function (d) {
- var y = 6;
- if (QDRService.isArtemis(d))
- y = 8;
- else if (QDRService.isQpid(d))
- y = 9;
- else if (d.nodeType === 'inter-router')
- y = 4;
- return y;})
- .attr('class', 'id')
- .classed('console', function(d) { return QDRService.isConsole(d) } )
- .classed('normal', function(d) { return d.nodeType === 'normal' } )
- .classed('on-demand', function(d) { return d.nodeType === 'on-demand' } )
- .classed('artemis', function(d) { return QDRService.isArtemis(d) } )
- .classed('qpid-cpp', function(d) { return QDRService.isQpid(d) } )
- .text(function (d) {
- if (QDRService.isConsole(d)) {
- return '\uf108'; // icon-desktop for this console
- }
- if (QDRService.isArtemis(d)) {
- return '\ue900'
- }
- if (QDRService.isQpid(d)) {
- return '\ue901';
- }
- if (d.nodeType === 'normal')
- return '\uf109'; // icon-laptop for clients
- return d.name.length>7 ? d.name.substr(0,6)+'...' : d.name;
- });
- }
-
- appendContent(g)
-
- var appendTitle = function (g) {
- g.append("svg:title").text(function (d) {
- var x = '';
- if (d.normals && d.normals.length > 1)
- x = " x " + d.normals.length;
- if (QDRService.isConsole(d)) {
- return 'Dispatch console' + x
- }
- if (d.properties.product == 'qpid-cpp') {
- return 'Broker - qpid-cpp' + x
- }
- if ( QDRService.isArtemis(d) ) {
- return 'Broker - Artemis' + x
- }
- return d.nodeType == 'normal' ? 'client' + x : (d.nodeType == 'on-demand' ? 'broker' : 'Router ' + d.name)
- })
- }
- appendTitle(g);
-
- // remove old nodes
- circle.exit().remove();
-
- // add subcircles
- svg.selectAll('.subcircle').remove();
- var multiples = svg.selectAll('.multiple')
- multiples.each( function (d) {
- d.normals.forEach( function (n, i) {
- if (i<d.normals.length-1 && i<3) // only show a few shadow circles
- this.insert('svg:circle', ":first-child")
- .attr('class', 'subcircle node')
- .attr('r', 15 - i)
- .attr('transform', "translate("+ 4 * (i+1) +", 0)")
- }, d3.select(this))
- })
-
- // dynamically create the legend based on which node types are present
- var legendNodes = [];
- legendNodes.push(aNode("Router", "", "inter-router", undefined, 0, 0, 0, 0, false, {}))
-
- if (!svg.selectAll('circle.console').empty()) {
- legendNodes.push(aNode("Dispatch console", "", "normal", undefined, 1, 0, 0, 0, false, {console_identifier: 'Dispatch console'}))
- }
- if (!svg.selectAll('circle.client').empty()) {
- legendNodes.push(aNode("Client", "", "normal", undefined, 2, 0, 0, 0, false, {}))
- }
- if (!svg.selectAll('circle.qpid-cpp').empty()) {
- legendNodes.push(aNode("Qpid cpp broker", "", "on-demand", undefined, 3, 0, 0, 0, false, {product: 'qpid-cpp'}))
- }
- if (!svg.selectAll('circle.artemis').empty()) {
- legendNodes.push(aNode("Artemis broker", "", "on-demand", undefined, 4, 0, 0, 0, false, {}))
- }
- lsvg = lsvg.data(legendNodes, function (d) {
- return d.id;
- });
- var lg = lsvg.enter().append('svg:g')
- .attr('transform', function (d, i) {
- // 45px between lines and add 10px space after 1st line
- return "translate(0, "+(45*i+(i>0?10:0))+")"
- })
-
- appendCircle(lg)
- appendContent(lg)
- appendTitle(lg)
- lg.append('svg:text')
- .attr('x', 35)
- .attr('y', 6)
- .attr('class', "label")
- .text(function (d) {return d.key })
- lsvg.exit().remove();
- var svgEl = document.getElementById('svglegend')
- if (svgEl) {
- var bb;
- // firefox can throw an exception on getBBox on an svg element
- try {
- bb = svgEl.getBBox();
- } catch (e) {
- bb = {y: 0, height: 200, x: 0, width: 200}
- }
- svgEl.style.height = (bb.y + bb.height) + 'px';
- svgEl.style.width = (bb.x + bb.width) + 'px';
- }
-
- if (!mousedown_node || !selected_node)
- return;
-
- if (!start)
- return;
- // set the graph in motion
- //QDR.log.debug("mousedown_node is " + mousedown_node);
- force.start();
-
- }
-
- var startUpdateConnectionsGrid = function (d) {
- var extendConnections = function () {
- $scope.multiData = []
- var normals = d.normals;
- // find updated normals for d
- d3.selectAll('.normal')
- .each(function(newd) {
- if (newd.id == d.id && newd.name == d.name) {
- normals = newd.normals;
- }
- });
- if (normals) {
- normals.forEach( function (n) {
- var nodeInfo = QDRService.topology.nodeInfo();
- var links = nodeInfo[n.key]['.router.link'];
- var linkTypeIndex = links.attributeNames.indexOf('linkType');
- var connectionIdIndex = links.attributeNames.indexOf('connectionId');
- n.linkData = [];
- links.results.forEach( function (link) {
- if (link[linkTypeIndex] === 'endpoint' && link[connectionIdIndex] === n.connectionId) {
- var l = {};
- l.owningAddr = QDRService.valFor(links.attributeNames, link, 'owningAddr');
- l.dir = QDRService.valFor(links.attributeNames, link, 'linkDir');
- if (l.owningAddr && l.owningAddr.length > 2)
- if (l.owningAddr[0] === 'M')
- l.owningAddr = l.owningAddr.substr(2)
- else
- l.owningAddr = l.owningAddr.substr(1)
-
- l.deliveryCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'deliveryCount'));
- l.undeliveredCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'undeliveredCount'));
- l.unsettledCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'unsettledCount'));
- l.adminStatus = QDRService.valFor(links.attributeNames, link, 'adminStatus');
- l.identity = QDRService.valFor(links.attributeNames, link, 'identity')
- l.connectionId = QDRService.valFor(links.attributeNames, link, 'connectionId')
-
- // TODO: remove this fake quiescing/reviving logic when the routers do the work
- initConnState(n.connectionId)
- if ($scope.quiesceState[n.connectionId].linkStates[l.identity])
- l.adminStatus = $scope.quiesceState[n.connectionId].linkStates[l.identity];
- if ($scope.quiesceState[n.connectionId].state == 'quiescing') {
- if (l.adminStatus === 'enabled') {
- // 25% chance of switching
- var chance = Math.floor(Math.random() * 2);
- if (chance == 1) {
- l.adminStatus = 'disabled';
- $scope.quiesceState[n.connectionId].linkStates[l.identity] = 'disabled';
- }
- }
- }
- if ($scope.quiesceState[n.connectionId].state == 'reviving') {
- if (l.adminStatus === 'disabled') {
- // 25% chance of switching
- var chance = Math.floor(Math.random() * 2);
- if (chance == 1) {
- l.adminStatus = 'enabled';
- $scope.quiesceState[n.connectionId].linkStates[l.identity] = 'enabled';
- }
- }
- }
- QDR.log.debug("pushing link state for " + l.owningAddr + " status: "+ l.adminStatus)
-
-
- n.linkData.push(l)
- }
- })
- $scope.multiData.push(n)
- if (n.connectionId == $scope.connectionId)
- $scope.linkData = n.linkData;
- initConnState(n.connectionId)
- $scope.multiDetails.updateState(n)
- })
- }
- $scope.$apply();
-
- d3.select('#multiple_details')
- .style({
- height: (normals.length + 1) * 30 + "px",
- 'overflow-y': normals.length > 10 ? 'scroll' : 'hidden'
- })
- }
-
- QDRService.addUpdatedAction("normalsStats", extendConnections)
- extendConnections();
- clearPopups();
- var display = 'block'
- var left = mouseX + $(document).scrollLeft()
- if (d.normals.length === 1) {
- display = 'none'
- left = left - 30;
- mouseY = mouseY - 20
- }
- d3.select('#multiple_details')
- .style({
- display: display,
- opacity: 1,
- left: (mouseX + $(document).scrollLeft()) + "px",
- top: (mouseY + $(document).scrollTop()) + "px"})
- if (d.normals.length === 1) {
- // simulate a click on the connection to popup the link details
- $scope.multiDetails.showLinksList( {entity: d} )
- }
- }
- var stopUpdateConnectionsGrid = function () {
- QDRService.delUpdatedAction("normalsStats");
- }
-
- var initConnState = function (id) {
- if (!angular.isDefined($scope.quiesceState[id])) {
- $scope.quiesceState[id] = {
- state: 'enabled',
- buttonText: 'Quiesce',
- buttonDisabled: false,
- linkStates: {}
- }
- }
- }
-
- function nextHop(thisNode, d) {
- if ((thisNode) && (thisNode != d)) {
- var target = findNextHopNode(thisNode, d);
- //QDR.log.debug("highlight link from node ");
- //console.dump(nodeFor(selected_node.name));
- //console.dump(target);
- if (target) {
- var hlLink = linkFor(nodeFor(thisNode.name), target);
- //QDR.log.debug("need to highlight");
- //console.dump(hlLink);
- if (hlLink)
- hlLink['highlighted'] = true;
- else
- target = null;
- }
- setTimeout(nextHop, 1, target, d);
- }
- restart();
- }
-
-
- function mousedown() {
- // prevent I-bar on drag
- //d3.event.preventDefault();
-
- // because :active only works in WebKit?
- svg.classed('active', true);
- }
-
- QDRService.addUpdatedAction("topology", function() {
- //QDR.log.debug("Topology controller was notified that the model was updated");
- if (hasChanged()) {
- QDR.log.info("svg graph changed")
- saveChanged();
- // TODO: update graph nodes instead of rebuilding entire graph
- d3.select("#SVG_ID").remove();
- d3.select("#svg_legend svg").remove();
- animate = true;
- initForceGraph();
- //if ($location.path().startsWith("/topology"))
- // Core.notification('info', "Qpid dispatch router topology changed");
-
- } else {
- //QDR.log.debug("no changes")
- }
- });
-
- function hasChanged () {
- // Don't update the underlying topology diagram if we are adding a new node.
- // Once adding is completed, the topology will update automatically if it has changed
- if ($scope.addingNode.step > 0)
- return false;
- var nodeInfo = QDRService.topology.nodeInfo();
- if (Object.keys(nodeInfo).length != Object.keys(savedKeys).length)
- return true;
- for (var key in nodeInfo) {
- // if this node isn't in the saved node list
- if (!savedKeys.hasOwnProperty(key))
- return true;
- // if the number of connections for this node chaanged
- if (nodeInfo[key]['.connection'].results.length != savedKeys[key]) {
- /*
- QDR.log.debug("number of connections changed for " + key);
- QDR.log.debug("QDRService.topology._nodeInfo[key]['.connection'].results.length");
- console.dump(QDRService.topology._nodeInfo[key]['.connection'].results.length);
- QDR.log.debug("savedKeys[key]");
- console.dump(savedKeys[key]);
- */
- return true;
- }
- }
- return false;
- };
- function saveChanged () {
- savedKeys = {};
- var nodeInfo = QDRService.topology.nodeInfo();
- // save the number of connections per node
- for (var key in nodeInfo) {
- savedKeys[key] = nodeInfo[key]['.connection'].results.length;
- }
- //QDR.log.debug("saving current keys");
- console.dump(savedKeys);
- };
- // we are about to leave the page, save the node positions
- $rootScope.$on('$locationChangeStart', function(event, newUrl, oldUrl) {
- //QDR.log.debug("locationChangeStart");
- nodes.forEach( function (d) {
- localStorage[d.name] = angular.toJson({x: d.x, y: d.y, fixed: d.fixed});
- });
- $scope.addingNode.step = 0;
-
- });
- // When the DOM element is removed from the page,
- // AngularJS will trigger the $destroy event on
- // the scope
- $scope.$on("$destroy", function( event ) {
- //QDR.log.debug("scope on destroy");
- QDRService.stopUpdating();
- QDRService.delUpdatedAction("topology");
- d3.select("#SVG_ID").remove();
- });
-
- initForceGraph();
- saveChanged();
- QDRService.startUpdating();
-
- function doAddDialog(NewRouterName) {
- var d = $dialog.dialog({
- dialogClass: "modal dlg-large",
- backdrop: true,
- keyboard: true,
- backdropClick: true,
- controller: 'QDR.NodeDialogController',
- templateUrl: 'node-config-template.html',
- resolve: {
- newname: function () {
- return NewRouterName;
- }
- }
- });
- d.open().then(function (result) {
- if (result)
- doDownloadDialog(result);
- });
- };
-
- function doDownloadDialog(result) {
- d = $dialog.dialog({
- backdrop: true,
- keyboard: true,
- backdropClick: true,
- controller: 'QDR.DownloadDialogController',
- templateUrl: 'download-dialog-template.html',
- resolve: {
- results: function () {
- return result;
- }
- }
- });
- d.open().then(function (result) {
- //QDR.log.debug("download dialog done")
- })
- if (!$scope.$$phase) $scope.$apply()
- };
- }]);
-
- QDR.module.controller("QDR.NodeDialogController", function($scope, QDRService, dialog, newname) {
- var schema = QDRService.schema;
- var myEntities = ['router', 'log', 'listener' ];
- var typeMap = {integer: 'number', string: 'text', path: 'text', boolean: 'boolean'};
- var newLinks = $('path.temp').toArray(); // jquery array of new links for the added router
- var nodeInfo = QDRService.topology.nodeInfo();
- var separatedEntities = []; // additional entities required if a link is reversed
- var myPort = 0, myAddr = '0.0.0.0'; // port and address for new router
- $scope.entities = [];
-
- // find max port number that is used in all the listeners
- var getMaxPort = function (nodeInfo) {
- var maxPort = 5674;
- for (var key in nodeInfo) {
- var node = nodeInfo[key];
- var listeners = node['.listener'];
- var attrs = listeners.attributeNames;
- for (var i=0; i<listeners.results.length; ++i) {
- var res = listeners.results[i];
- var port = QDRService.valFor(attrs, res, 'port');
- if (parseInt(port, 10) > maxPort)
- maxPort = parseInt(port, 10);
- }
- }
- return maxPort;
- }
- var maxPort = getMaxPort(nodeInfo);
-
- // construct an object that contains all the info needed for a single tab's fields
- var entity = function (actualName, tabName, humanName, ent, icon, link) {
- var nameIndex = -1; // the index into attributes that the name field was placed
- var index = 0;
- var info = {
- actualName: actualName,
- tabName: tabName,
- humanName: humanName,
- description:ent.description,
- icon: angular.isDefined(icon) ? icon : '',
- references: ent.references,
- link: link,
-
- attributes: $.map(ent.attributes, function (value, key) {
- // skip identity and depricated fields
- if (key == 'identity' || value.description.startsWith('Deprecated'))
- return null;
- var val = value['default'];
- if (key == 'name')
- nameIndex = index;
- index++;
- return { name: key,
- humanName: QDRService.humanify(key),
- description:value.description,
- type: typeMap[value.type],
- rawtype: value.type,
- input: typeof value.type == 'string' ? value.type == 'boolean' ? 'boolean' : 'input'
- : 'select',
- selected: val ? val : undefined,
- 'default': value['default'],
- value: val,
- required: value.required,
- unique: value.unique
- };
- })
- }
- // move the 'name' attribute to the 1st position
- if (nameIndex > -1) {
- var tmp = info.attributes[0];
- info.attributes[0] = info.attributes[nameIndex];
- info.attributes[nameIndex] = tmp;
- }
- return info;
- }
-
- // remove the annotation fields
- var stripAnnotations = function (entityName, ent, annotations) {
- if (ent.references) {
- var newEnt = {attributes: {}};
- ent.references.forEach( function (annoKey) {
- if (!annotations[annoKey])
- annotations[annoKey] = {};
- annotations[annoKey][entityName] = true; // create the key/consolidate duplicates
- var keys = Object.keys(schema.annotations[annoKey].attributes);
- for (var attrib in ent.attributes) {
- if (keys.indexOf(attrib) == -1) {
- newEnt.attributes[attrib] = ent.attributes[attrib];
- }
- }
- // add a field for the reference name
- newEnt.attributes[annoKey] = {type: 'string',
- description: 'Name of the ' + annoKey + ' section.',
- 'default': annoKey, required: true};
- })
- newEnt.references = ent.references;
- newEnt.description = ent.description;
- return newEnt;
- }
- return ent;
- }
-
- var annotations = {};
- myEntities.forEach(function (entityName) {
- var ent = schema.entityTypes[entityName];
- var hName = QDRService.humanify(entityName);
- if (entityName == 'listener')
- hName = "Listener for clients";
- var noAnnotations = stripAnnotations(entityName, ent, annotations);
- var ediv = entity(entityName, entityName, hName, noAnnotations, undefined);
- if (ediv.actualName == 'router') {
- ediv.attributes.filter(function (attr) { return attr.name == 'name'})[0].value = newname;
- // if we have any new links (connectors), then the router's mode should be interior
- if (newLinks.length) {
- var roleAttr = ediv.attributes.filter(function (attr) { return attr.name == 'mode'})[0];
- roleAttr.value = roleAttr.selected = "interior";
- }
- }
- if (ediv.actualName == 'container') {
- ediv.attributes.filter(function (attr) { return attr.name == 'containerName'})[0].value = newname + "-container";
- }
- if (ediv.actualName == 'listener') {
- // find max port number that is used in all the listeners
- ediv.attributes.filter(function (attr) { return attr.name == 'port'})[0].value = ++maxPort;
- }
- // special case for required log.module since it doesn't have a default
- if (ediv.actualName == 'log') {
- var moduleAttr = ediv.attributes.filter(function (attr) { return attr.name == 'module'})[0];
- moduleAttr.value = moduleAttr.selected = "DEFAULT";
- }
- $scope.entities.push( ediv );
- })
-
- // add a tab for each annotation that was found
- var annotationEnts = [];
- for (var key in annotations) {
- ent = angular.copy(schema.annotations[key]);
- ent.attributes.name = {type: "string", unique: true, description: "Unique name that is used to refer to this set of attributes."}
- var ediv = entity(key, key+'tab', QDRService.humanify(key), ent, undefined);
- ediv.attributes.filter(function (attr) { return attr.name == 'name'})[0].value = key;
- $scope.entities.push( ediv );
- annotationEnts.push( ediv );
- }
-
- // add an additional listener tab if any links are reversed
- ent = schema.entityTypes['listener'];
- newLinks.some(function (link) {
- if (link.__data__.right) {
- var noAnnotations = stripAnnotations('listener', ent, annotations);
- var ediv = entity("listener", "listener0", "Listener (internal)", noAnnotations, undefined);
- ediv.attributes.filter(function (attr) { return attr.name == 'port'})[0].value = ++maxPort;
- // connectors from other routers need to connect to this addr:port
- myPort = maxPort;
- myAddr = ediv.attributes.filter(function (attr) { return attr.name == 'host'})[0].value
-
- // override the role. 'normal' is the default, but we want inter-router
- ediv.attributes.filter(function( attr ) { return attr.name == 'role'})[0].selected = 'inter-router';
- separatedEntities.push( ediv );
- return true; // stop looping
- }
- return false; // continue looping
- })
-
- // Add connector tabs for each new link on the topology graph
- ent = schema.entityTypes['connector'];
- newLinks.forEach(function (link, i) {
- var noAnnotations = stripAnnotations('connector', ent, annotations);
- var ediv = entity('connector', 'connector' + i, " " + link.__data__.source.name, noAnnotations, link.__data__.right, link)
-
- // override the connector role. 'normal' is the default, but we want inter-router
- ediv.attributes.filter(function( attr ) { return attr.name == 'role'})[0].selected = 'inter-router';
-
- // find the addr:port of the inter-router listener to use
- var listener = nodeInfo[link.__data__.source.key]['.listener'];
- var attrs = listener.attributeNames;
- for (var i=0; i<listener.results.length; ++i) {
- var res = listener.results[i];
- var role = QDRService.valFor(attrs, res, 'role');
- if (role == 'inter-router') {
- ediv.attributes.filter(function( attr ) { return attr.name == 'host'})[0].value =
- QDRService.valFor(attrs, res, 'host')
- ediv.attributes.filter(function( attr ) { return attr.name == 'port'})[0].value =
- QDRService.valFor(attrs, res, 'port')
- break;
- }
- }
- if (link.__data__.right) {
- // connectors from other nodes need to connect to the new router's listener addr:port
- ediv.attributes.filter(function (attr) { return attr.name == 'port'})[0].value = myPort;
- ediv.attributes.filter(function (attr) { return attr.name == 'host'})[0].value = myAddr;
-
- separatedEntities.push(ediv)
- }
- else
- $scope.entities.push( ediv );
- })
- Array.prototype.push.apply($scope.entities, separatedEntities);
-
- // update the description on all the annotation tabs
- annotationEnts.forEach ( function (ent) {
- var shared = Object.keys(annotations[ent.actualName]);
- ent.description += " These fields are shared by " + shared.join(" and ") + ".";
-
- })
-
- $scope.testPattern = function (attr) {
- if (attr.rawtype == 'path')
- return /^(\/)?([^/\0]+(\/)?)+$/;
- //return /^(.*\/)([^/]*)$/;
- return /(.*?)/;
- }
-
- $scope.attributeDescription = '';
- $scope.attributeType = '';
- $scope.attributeRequired = '';
- $scope.attributeUnique = '';
- $scope.active = 'router'
- $scope.fieldsetDivs = "/fieldsetDivs.html"
- $scope.setActive = function (tabName) {
- $scope.active = tabName
- }
- $scope.isActive = function (tabName) {
- return $scope.active === tabName
- }
- $scope.showDescription = function (attr, e) {
- $scope.attributeDescription = attr.description;
- var offset = jQuery(e.currentTarget).offset()
- jQuery('.attr-description').offset({top: offset.top})
-
- $scope.attributeType = "Type: " + JSON.stringify(attr.rawtype);
- $scope.attributeRequired = attr.required ? 'required' : '';
- $scope.attributeUnique = attr.unique ? 'Must be unique' : '';
- }
- // handle the download button click
- // copy the dialog's values to the original node
- $scope.download = function () {
- dialog.close({entities: $scope.entities, annotations: annotations});
- }
- $scope.cancel = function () {
- dialog.close()
- };
-
- $scope.selectAnnotationTab = function (tabName) {
- var tabs = $( "#tabs" ).tabs();
- tabs.tabs("select", tabName);
- }
-
- var initTabs = function () {
- var div = angular.element("#tabs");
- if (!div.width()) {
- setTimeout(initTabs, 100);
- return;
- }
- $( "#tabs" )
- .tabs()
- .addClass('ui-tabs-vertical ui-helper-clearfix');
- }
- // start the update loop
- initTabs();
-
- });
-
-QDR.module.controller("QDR.DownloadDialogController", function($scope, QDRService, $templateCache, $window, dialog, results) {
- var result = results.entities;
- var annotations = results.annotations;
- var annotationKeys = Object.keys(annotations);
- var annotationSections = {};
-
- // use the router's name as the file name if present
- $scope.newRouterName = 'router';
- result.forEach( function (e) {
- if (e.actualName == 'router') {
- e.attributes.forEach( function (a) {
- if (a.name == 'name') {
- $scope.newRouterName = a.value;
- }
- })
- }
- })
- $scope.newRouterName = $scope.newRouterName + ".conf";
-
- var template = $templateCache.get('config-file-header.html');
- $scope.verbose = true;
- $scope.$watch('verbose', function (newVal) {
- if (newVal !== undefined) {
- // recreate output using current verbose setting
- getOutput();
- }
- })
-
- var getOutput = function () {
- $scope.output = template + '\n';
- $scope.parts = [];
- var commentChar = '#'
- result.forEach(function (entity) {
- // don't output a section for annotations, they get flattened into the entities
- var section = "";
- if (entity.icon) {
- section += "##\n## Add to " + entity.link.__data__.source.name + "'s configuration file\n##\n";
- }
- section += "##\n## " + QDRService.humanify(entity.actualName) + " - " + entity.description + "\n##\n";
- section += entity.actualName + " {\n";
- entity.attributes.forEach(function (attribute) {
- if (attribute.input == 'select')
- attribute.value = attribute.selected;
-
- // treat values with all spaces and empty strings as undefined
- attribute.value = String(attribute.value).trim();
- if (attribute.value === 'undefined' || attribute.value === '')
- attribute.value = undefined;
-
- if ($scope.verbose) {
- commentChar = attribute.required || attribute.value != attribute['default'] ? ' ' : '#';
- if (!attribute.value) {
- commentChar = '#';
- attribute.value = '';
- }
- section += commentChar + " "
- + attribute.name + ":" + Array(Math.max(20 - attribute.name.length, 1)).join(" ")
- + attribute.value
- + Array(Math.max(20 - ((attribute.value)+"").length, 1)).join(" ")
- + '# ' + attribute.description
- + "\n";
- } else {
- if (attribute.value) {
- if (attribute.value != attribute['default'] || attribute.required)
- section += " "
- + attribute.name + ":" + Array(20 - attribute.name.length).join(" ")
- + attribute.value + "\n";
-
- }
- }
- })
- section += "}\n\n";
- // if entity.icon is true, this is a connector intended for another router
- if (entity.icon)
- $scope.parts.push({output: section,
- link: entity.link,
- name: entity.link.__data__.source.name,
- references: entity.references});
- else
- $scope.output += section;
-
- // if this section is actually an annotation
- if (annotationKeys.indexOf(entity.actualName) > -1) {
- annotationSections[entity.actualName] = section;
- }
- })
- // go back and add annotation sections to the parts
- $scope.parts.forEach (function (part) {
- for (var section in annotationSections) {
- if (part.references.indexOf(section) > -1) {
- part.output += annotationSections[section];
- }
- }
- })
- QDR.log.debug($scope.output);
- }
-
- // handle the download button click
- $scope.download = function () {
- var output = $scope.output + "\n\n"
- var blob = new Blob([output], { type: 'text/plain;charset=utf-16' });
- saveAs(blob, $scope.newRouterName);
- }
-
- $scope.downloadPart = function (part) {
- var linkName = part.link.__data__.source.name + 'additional.conf';
- var blob = new Blob([part.output], { type: 'text/plain;charset=utf-16' });
- saveAs(blob, linkName);
- }
-
- $scope.done = function () {
- dialog.close();
- }
-});
-
- return QDR;
-}(QDR || {}));
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js b/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js
new file mode 120000
index 0000000..36d5187
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrTopology.js
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/js/qdrTopology.js
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[11/11] qpid-dispatch git commit: DISPATCH-316 Hawtio and stand-alone
consoles now use common code
Posted by ea...@apache.org.
DISPATCH-316 Hawtio and stand-alone consoles now use common code
Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/d98ae37e
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/d98ae37e
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/d98ae37e
Branch: refs/heads/master
Commit: d98ae37ef5bed5080ea50b53eef737e914dd9be6
Parents: c9d1413
Author: Ernest Allen <ea...@redhat.com>
Authored: Fri Aug 19 12:57:59 2016 -0400
Committer: Ernest Allen <ea...@redhat.com>
Committed: Fri Aug 19 12:57:59 2016 -0400
----------------------------------------------------------------------
.../src/main/webapp/plugin/css/dispatch.css | 626 +----
.../src/main/webapp/plugin/css/plugin.css | 870 +------
.../src/main/webapp/plugin/html/qdrCharts.html | 4 +-
.../src/main/webapp/plugin/html/qdrConnect.html | 81 +-
.../src/main/webapp/plugin/html/qdrLayout.html | 27 +-
.../src/main/webapp/plugin/html/qdrList.html | 112 +-
.../main/webapp/plugin/html/qdrOverview.html | 154 +-
.../src/main/webapp/plugin/html/qdrSchema.html | 22 +-
.../main/webapp/plugin/html/qdrTopology.html | 220 +-
.../main/webapp/plugin/html/tmplListChart.html | 12 +
.../main/webapp/plugin/html/tmplListTree.html | 8 +
.../webapp/plugin/html/tmplOverviewTree.html | 6 +
.../src/main/webapp/plugin/js/dispatchPlugin.js | 58 +-
.../hawtio/src/main/webapp/plugin/js/navbar.js | 124 +-
.../main/webapp/plugin/js/qdrChartService.js | 1112 +--------
.../src/main/webapp/plugin/js/qdrCharts.js | 38 +-
.../hawtio/src/main/webapp/plugin/js/qdrList.js | 812 +------
.../src/main/webapp/plugin/js/qdrListChart.js | 1 +
.../src/main/webapp/plugin/js/qdrOverview.js | 1427 +-----------
.../src/main/webapp/plugin/js/qdrSchema.js | 73 +-
.../src/main/webapp/plugin/js/qdrService.js | 889 +-------
.../src/main/webapp/plugin/js/qdrSettings.js | 152 +-
.../src/main/webapp/plugin/js/qdrTopology.js | 2133 +-----------------
.../src/main/webapp/plugin/lib/rhea-min.js | 8 +-
console/stand-alone/index.html | 54 +-
console/stand-alone/plugin/css/dispatch.css | 640 ++++++
console/stand-alone/plugin/css/plugin.css | 439 +++-
console/stand-alone/plugin/css/qdrTopology.css | 562 -----
console/stand-alone/plugin/css/site-base.css | 229 +-
console/stand-alone/plugin/html/qdrCharts.html | 114 +-
console/stand-alone/plugin/html/qdrConnect.html | 90 +-
console/stand-alone/plugin/html/qdrLayout.html | 8 +-
console/stand-alone/plugin/html/qdrList.html | 96 +-
.../stand-alone/plugin/html/qdrOverview.html | 96 +-
console/stand-alone/plugin/html/qdrSchema.html | 4 +-
.../stand-alone/plugin/html/qdrTopology.html | 121 +-
.../stand-alone/plugin/html/tmplListChart.html | 18 +
.../stand-alone/plugin/html/tmplListTree.html | 17 +
.../plugin/html/tmplOverviewTree.html | 15 +
console/stand-alone/plugin/js/dispatchPlugin.js | 254 +++
console/stand-alone/plugin/js/navbar.js | 65 +-
.../stand-alone/plugin/js/qdrChartService.js | 304 ++-
console/stand-alone/plugin/js/qdrCharts.js | 212 +-
console/stand-alone/plugin/js/qdrList.js | 879 +++++---
console/stand-alone/plugin/js/qdrListChart.js | 109 +
console/stand-alone/plugin/js/qdrOverview.js | 1559 +++++++++----
console/stand-alone/plugin/js/qdrPlugin.js | 197 --
console/stand-alone/plugin/js/qdrSchema.js | 45 +-
console/stand-alone/plugin/js/qdrService.js | 267 ++-
console/stand-alone/plugin/js/qdrSettings.js | 142 +-
console/stand-alone/plugin/js/qdrTopology.js | 827 ++++---
console/stand-alone/plugin/lib/rhea-min.js | 99 +-
52 files changed, 4852 insertions(+), 11579 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/css/dispatch.css
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/css/dispatch.css b/console/hawtio/src/main/webapp/plugin/css/dispatch.css
deleted file mode 100644
index cb050e6..0000000
--- a/console/hawtio/src/main/webapp/plugin/css/dispatch.css
+++ /dev/null
@@ -1,625 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
-*/
-
-svg {
- background-color: transparent;
- cursor: default;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- -o-user-select: none;
- user-select: none;
-}
-
-svg:not(.active):not(.ctrl) {
- cursor: crosshair;
-}
-#end-arrow-selected, #start-arrow-selected {
- stroke: #00F;
- fill: #00F;
-}
-
-path.link {
- fill: none;
- stroke: #000;
- stroke-width: 4px;
- cursor: default;
-}
-
-svg:not(.active):not(.ctrl) path.link {
- cursor: pointer;
-}
-
-path.link.selected {
- stroke-dasharray: 10,2;
- stroke: #00F !important;
-}
-
-
-path.link.highlighted {
- stroke: #0F0 !important;
-
-}
-
-path.link.temp {
- opacity: 0.3;
-}
-path.link.temp.over {
- opacity: 0.8;
- stroke-dasharray: 10,2;
-}
-
-path.link.dragline {
- pointer-events: none;
-}
-
-path.link.hidden {
- stroke-width: 0;
-}
-
-
-circle.node {
- stroke-width: 1.5px;
- cursor: pointer;
- stroke: darkgray;
- fill: lightgray;
-}
-
-circle.node.reflexive {
- stroke: #F00 !important;
- stroke-width: 2.5px;
-}
-circle.node.selected {
- stroke: #F00 !important;
- stroke-width: 2px;
- fill: #e0e0ff !important;
-}
-circle.node.inter-router {
- fill: #EAEAEA;
-}
-circle.node.normal {
- fill: #F0F000;
-}
-circle.node.on-demand {
- fill: #C0FFC0;
-}
-circle.node.on-demand.artemis {
- fill: #FCC;
- /*opacity: 0.2; */
-}
-
-circle.node.fixed {
- stroke-dasharray: 10,2;
-}
-circle.node.temp {
- stroke: #f80;
- fill: #f0f0ff;
-}
-
-text {
- font: 12px sans-serif;
- pointer-events: none;
- /*font-family: monospace;*/
-
-}
-
-.tooltipsy
-{
- padding: 10px;
-/* max-width: 320px;*/
- color: #303030;
- background-color: #fcfcfe;
- border: 1px solid #deca7e;
- border-radius: 5px;
-}
-
-.tiptable {
-
-}
-.tiptable tr {
- border-bottom: 1px solid #ccc;
-}
-
-.tiptable tr:last-child {
- border-bottom: 0px;
-}
-
-.tiptable tr:nth-child(even) {
- background: #fcfcfe;
-}
-.tiptable tr:nth-child(odd) {
- background: #FFF
-}
-
-text.id {
- text-anchor: middle;
- font-weight: bold;
-}
-
-text.label {
- text-anchor: start;
- font-weight: bold;
-}
-
-.row-fluid.tertiary {
- position: relative;
- left: 20px;
-}
-
-.row-fluid.tertiary.left {
- float: left;
-}
-
-.row-fluid.tertiary.panel {
- width: 410px;
- /*height: 100%; */
-}
-
-div#topologyForm .ngViewport, div#topologyForm .gridStyle {
- height: inherit !important;
- min-height: initial !important;
- overflow: initial;
-}
-
-div#multiple_details, div#link_details {
- height: 300px;
- width: 600px;
- display: none;
- padding: 0.5em;
- border: 1px solid;
- position: absolute;
- background-color: white;
- max-height: 330px !important;
- overflow: hidden;
-}
-div#multiple_details div.ngRow.selected {
- background-color: #c9dde1 !important;
-}
-
-div.grid-values {
- text-align: right;
-}
-
-div.grid-values.ngCellText span {
- padding-right: 4px;
-}
-
-.panel-adjacent {
- margin-left: 430px;
-}
-
-#topologyForm.selected {
- border: 1px solid red;
-}
-#topologyForm {
- border: 1px solid white;
- padding: 2px;
- /* position: relative; */
- /* top: -8px; */
-}
-div.qdr-topology.pane.left .ngViewport {
- /* border: 1px solid lightgray; */
-}
-
-#topologyForm > div {
- width:396px;
- /*height: 100vh;*/
-}
-
-/* globe */
-.land {
- fill: #999;
- stroke-opacity: 1;
-}
-
-.graticule {
- fill: none;
- stroke: black;
- stroke-width:.5;
- opacity:.1;
-}
-
-.labels {
- font: 18px sans-serif;
- fill: black;
- opacity: .85;
- text-anchor: middle;
-}
-
-.noclicks { pointer-events:none; }
-
-.point { opacity:.6; }
-
-.arcs {
- opacity:.7;
- stroke: darkgreen;
- stroke-width: 3;
-}
-.flyers {
- stroke-width:1;
- opacity: 0;
- stroke: darkred;
-}
-.arc, .flyer {
- stroke-linejoin: round;
- fill:none;
-}
-.arc { }
-.arc:hover {
- stroke: darkred;
-}
-.flyer { }
-.flyer:hover {
- stroke: darkgreen;
-}
-.arc.inter-router {
- stroke: darkblue;
-}
-
-#addNodeForm {
- padding: 1em;
-}
-
-
-li.currentStep {
- font-weight: bold;
-}
-
-.qdrTopology div.panel {
- position: absolute;
-}
-/*
-.ui-dialog-titlebar {
- border: 0;
- background: transparent;
-}
-*/
-
-/*
-.ui-tabs.ui-tabs-vertical {
- padding: 0;
- width: 48em;
-}
-.ui-tabs.ui-tabs-vertical .ui-widget-header {
- border: none;
-}
-.ui-tabs.ui-tabs-vertical .ui-tabs-nav {
- float: left;
- width: 10em;
- background: #CCC;
- border-radius: 4px 0 0 4px;
- border-right: 1px solid gray;
-}
-.ui-tabs.ui-tabs-vertical .ui-tabs-nav li {
- clear: left;
- width: 100%;
- margin: 0.1em 0;
- border: 1px solid gray;
- border-width: 1px 0 1px 1px;
- border-radius: 4px 0 0 4px;
- overflow: hidden;
- position: relative;
- right: -2px;
- z-index: 2;
-}
-.ui-tabs.ui-tabs-vertical .ui-tabs-nav li a {
- display: block;
- width: 100%;
- padding: 0.1em 1em;
-}
-.ui-tabs.ui-tabs-vertical .ui-tabs-nav li a:hover {
- cursor: pointer;
-}
-.ui-tabs.ui-tabs-vertical .ui-tabs-nav li.ui-tabs-active {
- margin-bottom: 0.2em;
- padding-bottom: 0;
- border-right: 1px solid white;
-}
-.ui-tabs.ui-tabs-vertical .ui-tabs-nav li:last-child {
- margin-bottom: 10px;
-}
-.ui-tabs.ui-tabs-vertical .ui-tabs-panel {
- float: left;
- width: 34em;
- border-left: 1px solid gray;
- border-radius: 0;
- position: relative;
- left: -1px;
-}
-
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected {
- right: -3px !important;
-}
-
-.ui-tabs li i.ui-icon {
- display: inline-block;
-}
-*/
-.ui-tabs .ui-tabs-panel {
- /* padding-top: 0 !important; */
-}
-
-.ui-widget-content fieldset {
- float: left;
- padding: 0 1em 0 0;
-}
-
-.entity-description {
- color: #960;
- font-size: 90%;
-}
-
-.attr-description {
- padding-top: 1.5em;
- float: right;
- width: 17em;
-}
-.attr-annotations {
- padding-top: 2.5em;
- clear: both;
-}
-.attr-annotations > span {
- padding-top: 0.5em;
- border-top: 1px dashed darkgray;
- display: block;
-}
-
-.attr-type {
- color: #990;
- font-size: 85%;
-}
-.attr-required {
- color: red;
- font-size: 85%;
-}
-.attr-unique {
- color: green;
- font-size: 85%;
-}
-
-#tabs.nodeEntities {
- border: 0;
-}
-
-#tabs ul.nodeTabs {
- background: #fff;
-}
-
-#tabs #Container {
- border-left: 1px solid #aaa;
-}
-
-#tabs.ui-tabs .ui-tabs-nav li {
- border-bottom: 1px solid #aaa !important;
-}
-
-.entity-fields {
- /* height: 400px; */
- overflow-y: scroll;
- overflow-x: hidden;
-}
-
-div.boolean label:first-child {
- float: left;
- margin-right: 1em;
-}
-div.boolean {
- padding-bottom: 1em;
-}
-
-.entity-fields label {
- font-weight: 600;
- margin-top: 0.5em;
- display: inline;
-}
-
-.aggregate {
- text-align: right;
-}
-
-.aggregate i {
- float: right;
- margin: 3px 3px 3px 8px;
-}
-
-.aggregate .hastip {
- padding: 5px;
-}
-
-.subTip .tipsy-inner {
- background-color: white;
- color: black;
- font-size: 1.3em;
- border: 1px solid black;
-}
-
-.subTip .tipsy-arrow-n { border-bottom-color: black; }
-.subTip .tipsy-arrow-s { border-top-color: black; }
-.subTip .tipsy-arrow-e { border-left-color: black; }
-.subTip .tipsy-arrow-w { border-right-color: black; }
-
-
-.contextMenu {
- display:none;
- position:absolute;
- left:30px;
- top:-30px;
- z-index:999;
- /* width:300px; */
-}
-.contextMenu ul {
- width:300px;
- margin:0;
- /* padding:10px; */
- list-style:none;
- background:#fff;
- color:#333;
- font-weight: 600;
- /* -moz-border-radius:5px; -webkit-border-radius:5px; border-radius:5px; */
- -moz-box-shadow:5px 5px 5px #ddd; -webkit-box-shadow:5px 5px 5px #999; box-shadow:5px 5px 5px #ddd;
- border: 1px solid #aaa;
-}
-.contextMenu ul li {
- padding:5px 10px;
- /* border-bottom: solid 1px #ccc; */
-}
-.contextMenu ul li:hover {
- background:#4a90d9; color:#fff;
-}
-.contextMenu ul li:last-child {
- border:none;
-}
-
-.na {
- display: none;
-}
-.contextMenu ul li.new {
- display: block;
-}
-.contextMenu ul li.adding, .contextMenu ul li.adding + li {
- display: block;
-}
-.contextMenu ul li.force-display {
- display: block;
-}
-.contextMenu ul li.context-separator {
- background-color: lightgray;
- height: 1px;
- padding: 0;
-}
-
-#crosssection {
- display: none;
- position: absolute;
- top: 200px;
- left: 600px;
-}
-
-.node circle {
-/* fill: rgb(31, 119, 180);
- fill-opacity: .25; */
- fill: #cfe2f3;
- fill-opacity: .98;
- stroke: black;
- stroke-width: 3px;
-}
-
-circle.subcircle {
- stroke-width: 1px;
- /* stroke-dasharray: 2; */
- fill-opacity: 0;
- stroke: darkgray;
-}
-
-.leaf circle {
- fill: #6fa8dc;
- fill-opacity: 0.95;
- stroke-width: 3px;
-}
-
-.leaf circle[title] {
- font-family: monospace;
-
-}
-
-#svg_legend {
- position: absolute;
- top: 110px;
- right: 0;
- border: 1px solid #ccc;
- border-radius: 5px;
- background-color: #fcfcfc;
- margin-right: 1.3em;
- padding: 1em;
-}
-
-#svg_legend svg {
- height: 235px;
- width: 180px;
-}
-
-#multiple_details div.gridStyle {
-/* height: 50em; */
- min-height: 70px !important;
- height: auto !important;
-}
-
-#multiple_details .ngViewport {
- height: auto !important;
-}
-
-#multiple_details .gridCellButton button, #link_details .gridCellButton button {
- margin: .25em .4em;
- font-size: 12px;
- height: 2em;
- padding-top: .1em;
-}
-
-#linkFilter {
- display: none;
- padding: 0.5em;
- border: 1px solid grey;
- background-color: #F0F0F0;
- position: absolute;
-}
-
-span.filter-icon {
- padding-left: 1em;
-}
-
-button.filter-close {
- width: 15px;
- height: 20px;
- padding: 0;
- position: absolute;
- right: 4px;
- top: 4px;
-}
-
-div.filter-title h6 {
- margin: 0;
-}
-
-.links button.btn-filter {
- padding: 0 1em 0 0;
- margin-left: 1em;
- font-size: 1em;
-}
-
-button.btn-filter {
- visibility: hidden;
-}
-span.dynatree-expanded button.btn-filter,
-a.dynatree-title:hover button.btn-filter {
- visibility: visible;
-}
-
-div.hdash-button a {
- color: white;
-}
-
-.linkDirIn {
- color: red;
- background-color: #f3f3f3;
-}
-
-.linkDirOut {
- color: blue;
- background-color: white;
-}
\ No newline at end of file
diff --git a/console/hawtio/src/main/webapp/plugin/css/dispatch.css b/console/hawtio/src/main/webapp/plugin/css/dispatch.css
new file mode 120000
index 0000000..f3dbfa0
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/css/dispatch.css
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/css/dispatch.css
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/css/plugin.css
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/css/plugin.css b/console/hawtio/src/main/webapp/plugin/css/plugin.css
deleted file mode 100644
index eeeb558..0000000
--- a/console/hawtio/src/main/webapp/plugin/css/plugin.css
+++ /dev/null
@@ -1,869 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
-*/
-main-display > .span8 {
- height: 100%;
- position: relative;
-}
-
-ul.qdrListNodes > li > span {
- padding: 6px 20px; 6px; 6px;
- display: block;
-}
-
-.qdrList .gridStyle {
- width: 20em;
- margin-right: 0;
- float: left;
-}
-
-
-.qdrList div.gridDetails {
-
- width: auto;
-}
-
-.selectedItems {
-/* margin-left: 21em; */
-}
-
-.qdrListPane {
- top: 110px;
-}
-
-.qdrListActions {
- width: auto;
-}
-
-div.listAttrName {
- padding-top: 5px;
-}
-
-div.listAttrName i.icon-bar-chart {
- float: right;
- margin: 3px 5px;
-}
-
-div.listAttrName i.icon-bar-chart.active, div.hastip i.icon-bar-chart.active, li.haschart i {
- background-color: #AAFFAA;
-}
-
-div#main div ul.nav li a:not(.btn) {
- background: initial !important;
-}
-
-div#main div ul.nav li.active a {
- background-color: #f0f0ff !important;
-}
-
-div#main.qdr {
- margin-top: 44px !important;
-}
-
-div.charts-header {
- font-size: 1.2em;
- color: #666666;
- margin: 1em 0;
-}
-
-.selectedNode, .selectedAction, .selectedEntity {
- font-weight: 600;
- color: #606066;
-}
-
-.okButton {
- text-align: center;
- margin: 1em;
-}
-
-span.showChartsLink {
- border: 1px solid blue;
- padding: 1px 2px;
-}
-
-div.listGraphs p {
- margin: 1em 0 2em 2em;
- text-align: center;
-}
-
-div.centered {
- text-align: center;
- margin: 4em;
-}
-
-.modal-body.centered {
- margin: 0;
-}
-
-/* dialog */
-div.aChart {
- height: 200px;
- width: 400px;
- margin: 1em;
-}
-
-/* dashboard */
-div.aChart.hDash {
- /* width: 21em; */
- /* height: 17em; */
- width: 100%;
- height: 87%;
- margin: 0;
- padding: 0;
-
-}
-div.chartContainer {
- float: left;
- width: 100%;
- height: 100%;
- overflow: hidden;
-}
-
-/* the x and y axis lines */
-.d3Chart g.axis path.domain {
- stroke-width: 1;
- stroke: black;
-}
-
-/* the line surrounding the area chart */
-div.d3Chart path {
-/* stroke: black; */
- stroke-width: 0;
-/* opacity: 0.5; */
-}
-
-/* the line above the area chart */
-/* the color gets overridden */
-div.d3Chart path.line {
- stroke: steelblue;
- stroke-width: 1.5;
- fill: none;
- opacity: 1;
-}
-
-.mo-rect {
- fill: #ffffdd;
- stroke: #f0f0f0;
- stroke-width: 1;
-}
-
-.mo-guide {
- fill: none;
- stroke: #d0d0d0;
- stroke-width: 2;
- stroke-dasharray: 3,3;
-}
-
-div.d3Chart .title {
- text-decoration: underline;
-}
-
-
-.axis line, .axis path {
- fill: none;
- shape-rendering: crispEdges;
- stroke-width: 1;
- stroke: #000000;
-}
-
-.axis line {
- stroke: #C0C0C0;
- stroke-dasharray: 1,1;
- opacity: 0.5;
-}
-
-.y.axis text, .x.axis text, .focus text, div.d3Chart .title {
- font-size: 12px;
-}
-
-.y.axis path {
- stroke: #000;
- }
-
-.overlay {
- fill: none;
- pointer-events: all;
- }
-
-.focus circle {
- fill: none;
- stroke: steelblue;
- }
-.focus .fo-table {
- /* box-shadow: 2px 2px 3px #EEE; */
-}
-
-div.d3Chart {
- padding: 1em 0;
- border: 1px solid #C0C0C0;
-}
-div.d3Chart.hDash {
- border: 0px;
-}
-
-div.d3Chart .axis path {
- display: inherit;
-}
-.c3-circle {
- display: none;
-}
-
-.fo-table {
- border: 1px solid darkgray;
- background-color: white;
- font-size: .85em;
-}
-
-.fo-table td {
- padding: 4px;
- border-left: 1px solid darkgray;
-}
-.fo-table tr.detail td {
- padding: 1px 4px;
-}
-.fo-title {
- color: white;
- background-color: darkgray;
-}
-
-.fo-table-legend {
- width: 8px;
- height: 8px;
- border: 1px solid black;
- margin: 0 4px;
- display: inline-block;
-}
-
-svg .legend {
- dominant-baseline: central;
-}
-
-div.chartContainer div.aChart {
- margin-top: 0.5em;
-}
-
-div.qdr-attributes .tree-header select {
- width: 100%;
-}
-
-div#main.qdr div ul.nav li.active a {
- background-color: #e0e0ff !important;
- color: #000000;
-}
-
-div#main.qdr .selected, .box.selected {
- color: #000000;
- text-shadow: none;
-}
-
-/* the selected node on the list page */
-div.qdrList li.active, ul.qdrListNodes li.active {
- background-color: #e0e0ff;
-}
-
-div.qdr-attributes span.dynatree-selected a {
- background-color: #e0e0ff;
-}
-div.qdr-attributes.pane, div.qdr-topology.pane {
- position: absolute;
- margin-left: 10px;
-}
-div.qdr-topology.pane.left {
- width: auto;
-}
-
-/* the selected row in the name table */
-div#main.qdr div.qdrList div.selected {
- background-color: #e0e0ff !important;
-}
-
-#dialogChart {
- height: 200px;
-}
-
-div.qdrCharts p.chartLabels button {
- float: right;
-}
-
-div.qdrCharts p.chartLabels {
- padding-right: 1em;;
- }
-
-p.dialogHeader {
- text-align: center;
-}
-
-p.dialogHeader input {
- margin-top: 10px;
- width: 480px;
-}
-
-.ui-slider-tick {
- position: absolute;
- background-color: #666;
- width: 2px;
- height: 8px;
- top: 12px;
- z-index: -1;
-}
-
-label.rateGroup {
- float: left;
-}
-
-div.chartOptions div.dlg-slider {
- float: left;
- margin-left: 2em;
- width: 28em;
- font-size: 14px;
-}
-
-div.chartOptions div.duration {
- width: 35em !important;
-}
-
-div.chartOptions .slider {
- margin-top: 1em;
- margin-bottom: 1em;
-}
-
-input[type="radio"] {
- margin-top: 0 !important;
-}
-
-div.chartOptions legend {
- font-size: 1.2em;
- margin-bottom: 10px;
-}
-
-div.chartOptions span.minicolors-swatch {
- width: 14px;
- height: 14px;
-}
-
-.minicolors-input {
- width: 4em;
- padding: 0 0 0 24px !important;
-}
-
-div.colorPicker div.colorText {
- display: inline-block;
- width: 10em;
-}
-
-div.chartOptions p.sep {
- height: 1em;
-}
-
-ul.nav-tabs {
- border-bottom: 1px solid #ddd !important;
-}
-
-.chartOptions ul.nav-tabs {
- margin-bottom: 0px !important;
-}
-
-div.tabbable div.tab-content {
- overflow: visible;
-}
-
-div.tabbable ul.nav-tabs > .active > a {
- background-color: #f8f8f8;
- border: 1px solid #ddd;
- border-bottom-color: transparent;
-}
-
-div.tabbable .tab-pane {
- background-color: #f8f8f8;
- padding: 12px;
- border-right: 1px solid #ddd;
- border-left: 1px solid #ddd;
- border-bottom: 1px solid #ddd;
-}
-div.dlg-large div.tabbable .tab-pane {
- margin-left: 11em;
-}
-
-div.tabbable ul.nav-tabs {
- margin-bottom: 0;
-}
-
-ul.qdrTopoModes {
- position: relative;
- top: -10px;
-}
-.overview.section {
- /* width: 35em; */
-}
-.overview.section .ngGrid {
- height: 12em !important;
- min-height: 12em !important;
-}
-
-.overview.routers.section .ngGrid {
- height: 16em !important;
- min-height: 16em !important;
-}
-.overview.routers.section {
- /*width: 15em; */
- }
-
-.grid-align-value {
- text-align: right;
-}
-
-.grid-align-value .ngCellText {
- padding-right: 10px;
-}
-
-.overview .ngRow:hover {
- background:#e0e0ff;
-}
-
-.qdr-overview.pane.left, .qdr-attributes.pane.left {
- top: 100px;
-}
-.qdr-topology.pane.left {
- top: 104px;
-}
-.qdr-overview.pane.left {
- left: 10px;
-}
-
-.treeContainer {
- /*width: 250px;
- float: left;
- overflow-y: auto;
- border-right: 1px solid lightgrey;
- height: 100vh;
-*/
-}
-
-#entityNames {
- width: 20em;
- float: left;
-}
-
-.treeDetails {
- /* margin-left: 300px; */
-}
-
-.gridStyle:not(.noHighlight) .ui-grid-row:hover .ui-grid-cell-contents {
- background-color: #e0e0ff;
-}
-
-.ngCellText {
- padding: 4px 0 0 4px;
-}
-
-.overview {
- border-bottom: 1px solid #d4d4d4;
-}
-
-.ui-grid-row.ui-grid-row-selected > [ui-grid-row] > .ui-grid-cell {
- background-color: #e0e0ff;
-}
-
-.tab-content .tab-pane {
- background-color: #f8f8f8;
- padding: 12px;
- border-right: 1px solid #ddd;
- border-left: 1px solid #ddd;
- border-bottom: 1px solid #ddd;
-}
-
-div.chartOptions ul.nav-tabs > .active > a {
- background-color: #f8f8f8;
- border: 1px solid #ddd;
- border-bottom-color: transparent;
-}
-
-div.chartOptions label:nth-of-type(2) {
- margin-left: 1em;
-}
-div.chartOptions label {
- font-weight: normal;
- display: inline-block;
-}
-
-/*
-.form-horizontal .control-label {
- float: left;
- width: 160px;
- padding-top: 5px;
- text-align: right;
-}
-
-.form-horizontal .controls {
- margin-left: 180px;
-}
-
-.form-horizontal input, {
- display: inline-block;
- margin-bottom: 0;
- vertical-align: middle;
-}
-
-input[type="text"], input[type="number"], input[type="password"] {
- background-color: #ffffff;
- border: 1px solid #cccccc;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
- -moz-transition: border linear 0.2s, box-shadow linear 0.2s;
- -o-transition: border linear 0.2s, box-shadow linear 0.2s;
- transition: border linear 0.2s, box-shadow linear 0.2s;
-}
-
-input[type="text"], input[type="number"], input[type="password"] {
- display: inline-block;
- width: 200px;
- padding: 4px 6px;
- margin-bottom: 10px;
- font-size: 14px;
- line-height: 20px;
- color: #555555;
- vertical-align: middle;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
-}
-
-.login input[type="checkbox"] {
- margin-top: 0.75em;
-}
-*/
-
-#dispatch-login-container {
- /* width: 18.5em; */
- margin-top: 2em;
-}
-/*
-div.login.container {
- width: 550px;
-}
-*/
-
-
-#overtree .fancytree-container {
-/* border: 0px; */
-}
-
-#overtree span.fancytree-alert-icon.ui-icon-refresh {
- /*background-position: -64px -80px; */
-}
-#overtree span.fancytree-alert-icon.ui-icon-transfer-e-w {
- /*background-position: -112px -80px;*/
-}
-
-#alerts {
- position: fixed;
- right: 0;
- top: 0;
- z-index: 100;
-}
-
-.alert-enter,
-.alert-leave,
-.alert-move {
- -webkit-transition: 1s linear all;
- -moz-transition: 1s linear all;
- -o-transition: 1s linear all;
- transition: 1s linear all;
- position:relative;
-}
-
-.alert-enter {
- left:-10px;
- opacity:0;
-}
-.alert-enter.alert-enter-active {
- left:0;
- opacity:1;
-}
-
-.alert-leave {
- left:0;
- opacity:1;
-}
-.alert-leave.alert-leave-active {
- left:-10px;
- opacity:0;
-}
-
-.alert-move {
- opacity:0.5;
-}
-.alert-move.alert-move-active {
- opacity:1;
-}
-
-.overview .table-striped tr:hover td {
- background-color: #e0e0ff !important;
-}
-
-#entityNames div.ngViewport {
- overflow-x: hidden;
-}
-
-.connect-column.connect-form {
- width: 20em;
-}
-
-.chartLabels button a {
- text-decoration: none;
-}
-
-.fancytree-ico-c.router .fancytree-icon {
-
-}
-
-.tabs-left .nav-tabs {
- float: left;
-}
-.tabs-left .nav-tabs > li {
-/* float: initial; */
-}
-
-div.modal.dlg-large {
- width: 53em;
-}
-
-button.hdash-button a {
- text-decoration: none;
- color: #fff;
-}
-
-div.widget-body > div {
- height: 100%;
-}
-
-div.qdrCharts {
- height: 100%;
-}
-
-ul.dispatch-view {
- margin-bottom: 0 !important;
-}
-
-.qdr-overview.pane.left span:not(.dynatree-has-children) .dynatree-icon:before,
-.qdr-attributes.pane.left span:not(.dynatree-has-children) .dynatree-icon:before {
- color: green;
-}
-
-span:not(.dynatree-has-children).address .dynatree-icon:before,
-span:not(.dynatree-has-children).router\.address .dynatree-icon:before {
- content: "\f0ac";
-}
-
-span:not(.dynatree-has-children).connection.external .dynatree-icon:before,
-span:not(.dynatree-has-children).connection.normal .dynatree-icon:before {
- content: "\f08e";
-}
-span:not(.dynatree-has-children).connection.external.quiesced .dynatree-icon:before {
- content: "\f14c";
- color: red;
-}
-
-span:not(.dynatree-has-children).connection.inter-router .dynatree-icon:before {
- content: "\f152";
-}
-span:not(.dynatree-has-children).no-data .dynatree-icon:before {
- content: "\f05e";
- color: red !important;
-}
-span:not(.dynatree-has-children).loading .dynatree-icon:before {
- content: "\f254";
-}
-span:not(.dynatree-has-children).router\.node .dynatree-icon:before {
- content: "\f013";
-}
-span:not(.dynatree-has-children).connector .dynatree-icon:before {
- content: "\f126";
-}
-span:not(.dynatree-has-children).container .dynatree-icon:before {
- content: "\f16c";
-}
-span:not(.dynatree-has-children).log .dynatree-icon:before {
- content: "\f0f6";
-}
-span:not(.dynatree-has-children).router\.link.inter-router .dynatree-icon:before {
- content: "\f04e";
-}
-span:not(.dynatree-has-children).router\.link.endpoint .dynatree-icon:before {
- content: "\f051";
-}
-span:not(.dynatree-has-children).listener .dynatree-icon:before {
- content: "\f025";
-}
-span:not(.dynatree-has-children).connection .dynatree-icon:before {
- content: "\f07e";
-}
-span:not(.dynatree-has-children).waypoint .dynatree-icon:before {
- content: "\f0ec";
-}
-span:not(.dynatree-has-children).router .dynatree-icon:before {
- content: "\f047";
-}
-span:not(.dynatree-has-children).fixedAddress .dynatree-icon:before {
- content: "\f015";
-}
-span:not(.dynatree-has-children).linkRoutePattern .dynatree-icon:before {
- content: "\f039";
-}
-span:not(.dynatree-has-children).allocator .dynatree-icon:before {
- content: "\f170";
-}
-
-.ngCellText {
-/* color: #333333; */
-}
-
-.changed {
- color: #339933;
-}
-
-div.dispatch-router div.help {
- width: auto;
- padding: 1em;
- background-color: lavender;
- border-radius: 6px;
- margin-top: 1em;
- text-align: center;
-}
-
-div.operations tr:nth-child(even) {
- background: #f3f3f3;
-}
-div.operations tr:nth-child(odd), div.operations tr:last-child {
- background: #fff;
-}
-
-div.operations tr input {
- margin: 0;
- padding: 3px 6px;
-}
-div.operations table {
- width: 100%;
-}
-div.operations th {
- width: 50%;
- border-bottom: 1px solid #cccccc;
- text-align: left;
-}
-div.operations td:nth-child(odd), div.operations th:nth-child(odd) {
- border-right: 1px solid #cccccc;
-}
-div.operations td:nth-child(odd) {
- padding-left: 0;
-}
-div.operations td:nth-child(even), div.operations th:nth-child(even) {
- padding-left: 5px;
-}
-div.operations th {
- padding: 5px;
-}
-div.operations .tab-pane.active {
- padding: 12px 12px 12px 0;
-}
-div.operations label {
- padding-top: 4px;
- margin-bottom: 4px;
-}
-.qdrListActions .ngGrid {
- /*min-height: 40em;
- height: 100%; */
-}
-div.qdrListActions .ngViewport {
- height: initial !important;
-}
-
-div.operations .boolean {
- padding-bottom: 0;
-}
-
-table.log-entry {
- margin-bottom: 1em;
- border-top: 1px solid black;
-}
-
-table.log-entry pre {
- background-color: #f5f5f5;
- color: inherit;
- margin: 0;
-}
-
-circle.node.normal.console {
- fill: lightcyan;
-}
-
-text.console, text.on-demand, text.normal {
- font-family: FontAwesome;
- font-weight: normal;
- font-size: 16px;
-}
-
-@font-face {
- font-family:"Brokers";
- src: url("brokers.ttf") /* TTF file for CSS3 browsers */
-}
-
-text.artemis.on-demand {
- font-family: Brokers;
- font-size: 20px;
- font-weight: bold;
-}
-
-text.qpid-cpp.on-demand {
- font-family: Brokers;
- font-size: 18px;
- font-weight: bold;
-}
-
-i.red {
- color: red;
-}
-
-.qdrListActions div.delete {
- width: 20em;
- margin: auto;
- border: 1px solid #eaeaea;
- height: 5em;
- padding: 4em;
- background-color: #fcfcfc;
-}
-
-.btn:focus {
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
-}
-
-select:focus, input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus {
- outline:3px solid rgba(82, 168, 236, 0.6);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
- outline: 5px auto -webkit-focus-ring-color;
- outline-offset: -2px;
-}
-
-btn.disabled, .btn[disabled] {
- opacity: 0.35;
-}
-
-#dispatch-login-container .ng-invalid-range {
- border-color: #e9322d !important;
-}
\ No newline at end of file
diff --git a/console/hawtio/src/main/webapp/plugin/css/plugin.css b/console/hawtio/src/main/webapp/plugin/css/plugin.css
new file mode 120000
index 0000000..b94a926
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/css/plugin.css
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/css/plugin.css
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/html/qdrCharts.html
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrCharts.html b/console/hawtio/src/main/webapp/plugin/html/qdrCharts.html
index 3267a9d..cb4f338 100644
--- a/console/hawtio/src/main/webapp/plugin/html/qdrCharts.html
+++ b/console/hawtio/src/main/webapp/plugin/html/qdrCharts.html
@@ -55,10 +55,10 @@ under the License.
<tab ng-hide="$parent.chart.aggregate()" heading="Colors">
<legend>Chart colors</legend>
<div class="colorPicker">
- <div class="colorText">Area ({{dialogChart.areaColor}}):</div><div hawtio-color-picker="dialogChart.areaColor"></div>
+ <label>Line: <input id="lineColor" name="lineColor" type="color" /></label>
</div>
<div class="colorPicker">
- <div class="colorText">Line ({{dialogChart.lineColor}}):</div><div hawtio-color-picker="dialogChart.lineColor"></div>
+ <label>Area: <input id="areaColor" name="areaColor" type="color" /></label>
</div>
<div style="clear:both;"> </div>
</tab>
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/html/qdrConnect.html
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrConnect.html b/console/hawtio/src/main/webapp/plugin/html/qdrConnect.html
deleted file mode 100644
index 54687fb..0000000
--- a/console/hawtio/src/main/webapp/plugin/html/qdrConnect.html
+++ /dev/null
@@ -1,80 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
--->
-<div class="row-fluid" ng-controller="QDR.SettingsController">
- <div class="login container" ng-hide="connecting">
- <div class="row" id="dispatch-login-container">
- <div class="connect-column">
- <div class="alert alert-success">
- <p>
- Enter the address and port of a <strong><a href="http://qpid.apache.org/components/dispatch-router/" target="_blank">Qpid Dispatch Router</a></strong> to connect..
- </p>
-
- <p>
- The port should be a websockets <==> tcp proxy.
- </p>
-
- <p>
- When Autostart is checked, you will be automatically logged in to the router the next time you start the console.
- </p>
-
- </div>
- </div>
- <div class="connect-column connect-form">
- <form class="hawtio-form form-horizontal no-bottom-margin" novalidate ng-submit="connect()" name="settings">
- <fieldset>
- <div class="spacer"></div>
- <div class="control-group" ng-show="true">
- <label class="strong control-label">Address: </label>
- <div class="controls">
- <input tabindex="1" type="text" ng-model="formEntity.address" placeholder="localhost" name="address" autofocus="autofocus" class="ng-pristine ng-valid ng-valid-required"></div>
- </div>
- <div class="control-group" ng-show="true">
- <label tabindex="-1" class="control-label" title="Ports to connect to, by default 5673">Port: </label>
- <div class="controls">
- <input tabindex="2" posint type="number" placeholder="5673" tooltip="Ports to connect to, by default 5673" ng-model="formEntity.port" name="port" title="Ports to connect to, by default 5673">
- <span ng-show="settings.port.$error.range">Must be 1 through 65535</span>
- </div>
- </div>
- <div class="control-group" ng-show="true">
- <label tabindex="-1" class="control-label" title="Whether or not the connection should be started as soon as you log into hawtio">Autostart: </label>
- <div class="controls">
- <input tabindex="3" type="checkbox" tooltip="Whether or not the connection should be started as soon as you log into hawtio" ng-model="formEntity.autostart" name="autostart" title="Whether or not the connection should be started as soon as you log into hawtio"
- class="ng-scope ng-pristine ng-valid"></div>
- </div>
- <input tabindex="-1" type="submit" style="position: absolute; left: -9999px; width: 1px; height: 1px;">
- <p></p>
- <div>
- <button type="submit" tabindex="4" class="btn btn-primary pull-right" ng-disabled="settings.$invalid">{{buttonText()}}</button>
- <!-- <button tabindex="-1" class="btn btn-secondary pull-right" ng-click="connect1()">Debug</button> -->
- </div>
- </fieldset>
- </form>
- </div>
- </div>
- </div>
-
- <div class="centered" ng-show="connecting">
- <i class="icon-spin icon-spinner icon-4x"></i>
- <p>Please wait, connecting now...</p>
- </div>
- <div class="centered" ng-show="connectionError">
- <p>There was a connection error: {{connectionErrorText}}</p>
- </div>
-
-</div>
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrConnect.html b/console/hawtio/src/main/webapp/plugin/html/qdrConnect.html
new file mode 120000
index 0000000..2eb3530
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/html/qdrConnect.html
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/html/qdrConnect.html
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/html/qdrLayout.html
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrLayout.html b/console/hawtio/src/main/webapp/plugin/html/qdrLayout.html
deleted file mode 100644
index 80cd5ea..0000000
--- a/console/hawtio/src/main/webapp/plugin/html/qdrLayout.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
--->
-<ul class="nav nav-tabs connected dispatch-view" ng-controller="QDR.NavBarController">
- <li ng-repeat="link in breadcrumbs" title="{{link.title}}" ng-show="isValid(link)" ng-class='{active : isActive(link.href), "pull-right" : isRight(link)}'>
- <a ng-href="{{link.href}}" ng-bind-html-unsafe="link.content"></a>
- </li>
-</ul>
-<div class="row-fluid dispatch-router">
- <div ng-view></div>
-</div>
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrLayout.html b/console/hawtio/src/main/webapp/plugin/html/qdrLayout.html
new file mode 120000
index 0000000..f4caaf6
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/html/qdrLayout.html
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/html/qdrLayout.html
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/html/qdrList.html
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrList.html b/console/hawtio/src/main/webapp/plugin/html/qdrList.html
deleted file mode 100644
index e259e64..0000000
--- a/console/hawtio/src/main/webapp/plugin/html/qdrList.html
+++ /dev/null
@@ -1,111 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
--->
-
-<div ng-controller="QDR.ListController">
- <hawtio-pane class="qdr-attributes" position="left" width="200">
- <div class="treeContainer">
- <div class="tree-header"><select ng-options="node as node.name for node in nodes" ng-model="currentNode" ng-change="selectNode(currentNode)"></select></div>
- <div id="entityTree" onSelect="onTreeSelected" onRoot="onRootReady" hideRoot="true"></div>
- <div ng-init="treeReady()"></div>
- </div>
- </hawtio-pane>
- <div class="row-fluid qdrListActions">
- <ul class="nav nav-tabs">
- <li ng-repeat="mode in modes" ng-show="isValid(mode)" ng-click="selectMode(mode)" ng-class="{active : isModeSelected(mode)}" title="{{mode.title}}" ng-bind-html-unsafe="mode.content"> </li>
- </ul>
- <h4>{{selectedRecordName}}</h4>
- <div ng-show="currentMode.id === 'attributes'" class="selectedItems">
- <div ng-show="selectedRecordName === selectedEntity" class="no-content">There are no {{selectedEntity | safePlural}}</div>
- <div ng-hide="selectedRecordName === selectedEntity" ng-grid="details"></div>
- </div>
- <div ng-show="currentMode.id === 'delete'">
- <div class="delete" ng-show="selectedRecordName !== selectedEntity">
- <button class="btn btn-primary" ng-click="remove()">Delete</button> {{selectedRecordName}}
- </div>
- <div ng-hide="selectedRecordName !== selectedEntity">
- There are no {{selectedEntity}}s
- </div>
- </div>
- <div class="operations" ng-show="currentMode.id === 'operations'">
- <fieldset ng-show="operation != ''">
- <table>
- <tr>
- <th>Attribute</th>
- <th>Value</th>
- </tr>
- <tr title="{{attribute.title}}" ng-repeat="attribute in detailFields">
- <td><label for="{{attribute.name}}">{{attribute.name | humanify}}</label></td>
- <!-- we can't do <input type="{angular expression}"> because... jquery throws an exception because... -->
- <td>
- <div ng-if="attribute.input == 'input'">
- <!-- ng-pattern="testPattern(attribute)" -->
- <input ng-if="attribute.type == 'number'" type="number" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.rawValue" ng-required="attribute.required" class="ui-widget-content ui-corner-all"/>
- <input ng-if="attribute.type == 'text'" type="text" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.attributeValue" ng-required="attribute.required" class="ui-widget-content ui-corner-all"/>
- <textarea ng-if="attribute.type == 'textarea'" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.attributeValue" ng-required="attribute.required" class="ui-widget-content ui-corner-all"></textarea>
- <span ng-if="attribute.type == 'disabled'" >{{getAttributeValue(attribute)}}</span>
- </div>
- <div ng-if="attribute.input == 'select'">
- <select id="{{attribute.name}}" ng-model="attribute.selected" ng-options="item for item in attribute.rawtype track by item"></select>
- </div>
- <div ng-if="attribute.input == 'boolean'" class="boolean">
- <label><input type="radio" ng-model="attribute.rawValue" ng-value="true"> True</label>
- <label><input type="radio" ng-model="attribute.rawValue" ng-value="false"> False</label>
- </div>
- </td>
- </tr>
- <tr><td></td><td><button class="btn btn-primary" type="button" ng-click="ok()">{{operation | Pascalcase}}</button></td></tr>
- </table>
- </fieldset>
- </div>
- <div ng-show="currentMode.id === 'log'">
- <table class="log-entry" ng-repeat="entry in logResults track by $index">
- <tr>
- <td align="left" colspan="2">{{entry.time}}</td>
- </tr>
- <tr>
- <td>Type</td><td>{{entry.type}}</td>
- </tr>
- <tr>
- <td>Source</td><td>{{entry.source}}:{{entry.line}}</td>
- </tr>
- <tr>
- <td valign="middle">Message</td><td valign="middle"><pre>{{entry.message}}</pre></td>
- </tr>
- </table>
- </div>
- </div>
-</div>
-
-<!--
- This is the template for the graph dialog that is displayed.
--->
-<script type="text/ng-template" id="template-from-script.html">
- <div class="modal-header">
- <h3 class="modal-title">Chart {{chart.attr() | humanify}}</h3>
- </div>
- <div class="modal-body">
- <div id="{{svgDivId}}" class="d3Chart"></div>
- </div>
- <div class="modal-footer">
- <span>
- <div class="btn btn-success hdash-button" ng-click="addHChart()" title="Add this chart to a dashboard"><a ng-href="{{addToDashboardLink()}}"><i class="icon-share"></i> Add this chart to a dashboard</a></div>
- </span>
- <button class="btn btn-primary" type="button" ng-click="ok()">Close</button>
- </div>
-</script>
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrList.html b/console/hawtio/src/main/webapp/plugin/html/qdrList.html
new file mode 120000
index 0000000..843a1ef
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/html/qdrList.html
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/html/qdrList.html
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html b/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html
deleted file mode 100644
index 14653b1..0000000
--- a/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html
+++ /dev/null
@@ -1,153 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
--->
-<!--
-<div ng-controller="QDR.OverviewController">
-
- <div class="treeContainer">
- <div id="overtree"></div>
- </div>
-
- <div class="treeDetails" ng-include="template.url"></div>
-</div>
--->
-<div ng-controller="QDR.OverviewController">
- <hawtio-pane class="qdr-overview" position="left" width="300">
- <div class="treeContainer">
- <div id="overtree"></div>
- </div>
- </hawtio-pane>
- <div class="treeDetails" ng-include="template.url"></div>
- <div id="linkFilter">
- <div class="filter-title">
- <h6>Filter by link type</h6>
- <button ng-click="filterClose()" type="button" class="btn btn-primary filter-close">x</button>
- </div>
- <select ng-init="currentLinkFilter = 'endpoint'" ng-model="currentLinkFilter" ng-change="setLinkFilter(currentLinkFilter)">
- <option value="">All link types</option>
- <option value="endpoint" selected>Endpoints only</option>
- </select>
- </div>
-</div>
-
-<!-- the following scripts are content that gets loaded into the above div that has the temple.url -->
-<script type="text/ng-template" id="routers.html">
- <div class="row-fluid">
- <h3>Routers</h3>
- <div class="overview">
- <div class="gridStyle" ng-grid="allRouters"></div>
- </div>
- </div>
-</script>
-
-<script type="text/ng-template" id="router.html">
- <div class="row-fluid">
- <h3>Router {{router.data.title}} attributes</h3>
- <div class="gridStyle noHighlight" ng-grid="routerGrid"></div>
- </div>
-</script>
-
-<script type="text/ng-template" id="addresses.html">
- <div class="row-fluid">
- <h3>Addresses</h3>
- <div class="overview">
- <div class="gridStyle" ng-grid="addressesGrid"></div>
- </div>
- </div>
-</script>
-<script type="text/ng-template" id="address.html">
- <div class="row-fluid">
- <h3>Address {{address.data.title}}</h3>
- <div class="gridStyle noHighlight" ng-grid="addressGrid"></div>
- </div>
-</script>
-<script type="text/ng-template" id="links.html">
- <div class="row-fluid">
- <h3>Links</h3>
- <div class="gridStyle" ng-grid="linksGrid"></div>
- </div>
-</script>
-<script type="text/ng-template" id="link.html">
- <div class="row-fluid">
- <h3>Link {{link.data.title}}</h3>
- <div class="gridStyle noHighlight" ng-grid="linkGrid"></div>
- </div>
-</script>
-<script type="text/ng-template" id="connections.html">
- <div class="row-fluid">
- <h3>Connections</h3>
- <div class="overview">
- <div class="gridStyle" ng-grid="allConnectionGrid"></div>
- </div>
- </div>
-</script>
-<script type="text/ng-template" id="connection.html">
- <div class="row-fluid">
- <ul class="nav nav-tabs">
- <li ng-repeat="mode in connectionModes" ng-show="isValid(mode)" ng-click="selectMode(mode)" ng-class="{active : isModeSelected(mode)}" title="{{mode.title}}" ng-bind-html-unsafe="mode.content"> </li>
- </ul>
- <div ng-show="currentMode.id === 'attributes'" class="selectedItems">
- <h3>Connection {{connection.data.title}}</h3>
- <div class="gridStyle noHighlight" ng-grid="connectionGrid"></div>
- </div>
- <div ng-show="currentMode.id === 'links'" class="selectedItems">
- <h3>External links for connection {{connection.data.title}}</h3>
- <!-- <button title="{{quiesceState.buttonText}} links" type="button" ng-hide="quiesceHide()" ng-class="quiesceClass()" class="btn" ng-click="quiesceAllClicked()" ng-disabled="quiesceState.buttonDisabled">{{quiesceState.buttonText}}</button> -->
- <div class="gridStyle noHighlight" ng-grid="connectionLinksGrid"></div>
- </div>
- </div>
-</script>
-<script type="text/ng-template" id="titleHeaderCellTemplate.html">
- <div title="{{col.displayName}}" class="ngHeaderSortColumn {{col.headerClass}}" ng-style="{'cursor': col.cursor}" ng-class="{ 'ngSorted': !noSortVisible }">
- <div ng-click="col.sort($event)" ng-class="'colt' + col.index" class="ngHeaderText">{{col.displayName}}</div>
- <div class="ngSortButtonDown" ng-show="col.showSortButtonDown()"></div>
- <div class="ngSortButtonUp" ng-show="col.showSortButtonUp()"></div>
- <div class="ngSortPriority">{{col.sortPriority}}</div>
- </div>
-</script>
-<script type="text/ng-template" id="titleCellTemplate.html">
- <div title="{{row.entity[col.field]}}" class="ngCellText">{{row.entity[col.field]}}</div>
-</script>
-<script type="text/ng-template" id="logs.html">
- <div class="row-fluid">
- <h3>Logs</h3>
- </div>
-</script>
-<script type="text/ng-template" id="log.html">
- <div class="row-fluid">
- <h3>Log {{log.data.title}}</h3>
- </div>
-</script>
-
-<script type="text/ng-template" id="linkRowTemplate.html">
- <div ng-class="{linkDirIn: row.getProperty('linkDir') == 'in', linkDirOut: row.getProperty('linkDir') == 'out'}">
- <div ng-style="{ 'cursor': row.cursor }" ng-repeat="col in renderedColumns" ng-class="col.colIndex()" class="ngCell {{col.cellClass}}">
- <div class="ngVerticalBar" ng-style="{height: rowHeight}" ng-class="{ ngVerticalBarVisible: !$last }"> </div>
- <div ng-cell></div>
- </div>
- </div>
-</script>
-
-<script type="text/ng-template" id="linkAggTemplate.html">
- <div ng-click='row.toggleExpand(); saveGroupState()' ng-style='rowStyle(row)' class='ngAggregate ng-scope' style='top: 0px; height: 48px; left: 0px;'>
- <span class='ngAggregateText ng-binding'>
- {{row.label CUSTOM_FILTERS}} ({{row.totalChildren()}} {{AggItemsLabel}})
- </span>
- <div ng-class="{true: 'ngAggArrowCollapsed', false: 'ngAggArrowExpanded'}[row.collapsed]"></div>
- </div>
-</script>
\ No newline at end of file
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html b/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html
new file mode 120000
index 0000000..3c33d8a
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/html/qdrOverview.html
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/html/qdrOverview.html
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/html/qdrSchema.html
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrSchema.html b/console/hawtio/src/main/webapp/plugin/html/qdrSchema.html
deleted file mode 100644
index 6661baf..0000000
--- a/console/hawtio/src/main/webapp/plugin/html/qdrSchema.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
--->
-<div class="main-display row-fluid" ng-controller="QDR.SchemaController">
- <div id="schema"></div>
-</div>
\ No newline at end of file
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrSchema.html b/console/hawtio/src/main/webapp/plugin/html/qdrSchema.html
new file mode 120000
index 0000000..7f9422e
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/html/qdrSchema.html
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/html/qdrSchema.html
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html b/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html
deleted file mode 100644
index 864441f..0000000
--- a/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html
+++ /dev/null
@@ -1,219 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
--->
-<div class="qdrTopology row-fluid" ng-controller="QDR.TopologyController">
- <div class="qdr-topology pane left" ng-controller="QDR.TopologyFormController">
- <div id="topologyForm" ng-class="{selected : isSelected()}">
- <!-- <div ng-repeat="form in forms" ng-show="isVisible(form)" ng-class='{selected : isSelected(form)}'> -->
- <div ng-show="form == 'router'">
- <h4>Router Info</h4>
- <div class="gridStyle" ng-grid="topoGridOptions"></div>
- </div>
- <div ng-show="form == 'connection'">
- <h4>Connection Info</h4>
- <div class="gridStyle" ng-grid="topoGridOptions"></div>
- </div>
- <div id="addNodeForm" ng-show="form == 'add'">
- <h4>Add a new router</h4>
- <ul>
- <li>Click on an existing router to create a connection to the new router</li>
- <li>Double-click on the new router to <button ng-click="editNewRouter()">edit</button> its properties</li>
- <li ng-show="addingNode.hasLink" >Right-click on a new connection to edit its properties</li>
- </ul>
- <button ng-click="cancel()">Cancel</button>
- </div>
- </div>
- </div>
- <div class="panel-adjacent">
-
-<!--
- <ul class="nav nav-tabs ng-scope qdrTopoModes">
- <li ng-repeat="mode in modes" ng-class="{active : isModeActive(mode.name), 'pull-right' : isRight(mode)}" ng-click="selectMode('{{mode.name}}')" >
- <a data-placement="bottom" class="ng-binding"> {{mode.name}} </a></li>
- </ul>
--->
- <div id="topology" ng-show="mode == 'Diagram'"><!-- d3 toplogy here --></div>
- <div id="crosssection"><!-- d3 pack here --></div>
- <div id="node_context_menu" class="contextMenu">
- <ul>
- <li class="na" ng-class="{new: contextNode.cls == 'temp'}" ng-click="addingNode.trigger = 'editNode'">Edit...</li>
- <li class="na" ng-class="{adding: addingNode.step > 0}" ng-click="addingNode.step = 0">Cancel add</li>
- <li class="context-separator"></li>
- <li class="na" ng-class="{'force-display': !isFixed()}" ng-click="setFixed(true)">Freeze in place</li>
- <li class="na" ng-class="{'force-display': isFixed()}" ng-click="setFixed(false)">Unfreeze</li>
- </ul>
- </div>
- <div id="svg_context_menu" class="contextMenu">
- <ul>
- <li ng-click="addingNode.step = 2">Add a new router</li>
- </ul>
- </div>
- <div id="link_context_menu" class="contextMenu">
- <ul>
- <li ng-click="reverseLink()">Reverse connection direction</li>
- <li ng-click="removeLink()">Remove connection</li>
- </ul>
- </div>
- <div id="svg_legend"></div>
- <div id="multiple_details">
- <div class="gridStyle" ng-grid="multiDetails"></div>
- </div>
- <div id="link_details">
- <div class="gridStyle" ng-grid="linkDetails"></div>
- </div>
- </div>
-</div>
-
-
-<script type="text/ng-template" id="titleHeaderCellTemplate.html">
- <div title="{{col.displayName}}" class="ngHeaderSortColumn {{col.headerClass}}" ng-style="{'cursor': col.cursor}" ng-class="{ 'ngSorted': !noSortVisible }">
- <div ng-click="col.sort($event)" ng-class="'colt' + col.index" class="ngHeaderText">{{col.displayName}}</div>
- <div class="ngSortButtonDown" ng-show="col.showSortButtonDown()"></div>
- <div class="ngSortButtonUp" ng-show="col.showSortButtonUp()"></div>
- <div class="ngSortPriority">{{col.sortPriority}}</div>
- </div>
-</script>
-<script type="text/ng-template" id="titleCellTemplate.html">
- <div title="{{row.entity[col.field]}}" class="ngCellText">{{row.entity[col.field]}}</div>
-</script>
-
-<!--
- This is the template for the node edit dialog that is displayed.
--->
-<script type="text/ng-template" id="node-config-template.html">
- <div class="modal-header">
- <h3 class="modal-title">Configure new router</h3>
- </div>
- <div class="modal-body">
- <form novalidate name="editForm">
-
- <tabset vertical="true" class="tabs-left">
- <tab ng-repeat="entity in entities"> <!-- ng-class="{separated: entity.tabName == 'listener0'}" -->
- <tab-heading>
- <i ng-if="entity.icon !== ''" ng-class="entity.icon ? 'ui-icon-arrowthick-1-w' : 'ui-icon-arrowthick-1-e'" class="ui-icon"></i>{{entity.humanName}}
- </tab-heading>
- <div class="entity-description">{{entity.description}}</div>
- <fieldset>
- <div ng-mouseenter="showDescription(attribute, $event)" ng-repeat="attribute in entity.attributes">
- <label for="{{attribute.name}}">{{attribute.humanName}}</label>
-<!-- we can't do <input type="{angular expression}"> because... jquery throws an exception because... -->
- <div ng-if="attribute.input == 'input'">
- <!-- ng-pattern="testPattern(attribute)" -->
- <input ng-if="attribute.type == 'number'" type="number" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.value" ng-required="attribute.required" class="ui-widget-content ui-corner-all"/>
- <input ng-if="attribute.type == 'text'" type="text" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.value" ng-required="attribute.required" class="ui-widget-content ui-corner-all"/>
- </div>
- <div ng-if="attribute.input == 'select'">
- <select id="{{attribute.name}}" ng-model="attribute.selected" ng-options="item for item in attribute.rawtype"></select>
- </div>
- <div ng-if="attribute.input == 'boolean'" class="boolean">
- <label><input type="radio" ng-model="attribute.value" value="true"> True</label>
- <label><input type="radio" ng-model="attribute.value" value="false"> False</label>
- </div>
- </div>
- </fieldset>
- <div class="attr-description">{{attributeDescription}}
- <div class="attr-type">{{attributeType}}</div>
- <div class="attr-required">{{attributeRequired}}</div>
- <div class="attr-unique">{{attributeUnique}}</div>
- </div>
- <div class="attr-annotations" ng-repeat="annotation in entity.annotatedBy">
- <span>You can also enter the <button ng-click="selectAnnotationTab(annotation)">{{annotation}}</button> values.</span>
- </div>
- </tab>
- </tabset>
-
-
- </form>
- </div>
- <div class="modal-footer">
- <button class="btn btn-primary" type="button" ng-click="download()">Download</button>
- <button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button>
- </div>
-</script>
-
-<script type="text/ng-template" id="config-file-header.html">##
-## Licensed to the Apache Software Foundation (ASF) under one
-## or more contributor license agreements. See the NOTICE file
-## distributed with this work for additional information
-## regarding copyright ownership. The ASF licenses this file
-## to you 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
-##
-</script>
-
-<script type="text/ng-template" id="download-dialog-template.html">
- <div class="modal-header">
- <h3 class="modal-title">Configure new router</h3>
- </div>
- <div class="modal-body">
-
- <label title="Show descriptions and default values in confile files"><input type="checkbox" ng-model="verbose"> Verbose output</label>
- <div>
- <button ng-click="download()">Download</button>
- <button class="btn" zero-clipboard data-clipboard-text="{{output}}" title="Copy to clipboard">
- <i class="icon-copy"></i>
- </button> configuration file for {{newRouterName}}
- </div>
- <div ng-repeat="part in parts">
- <button ng-click="downloadPart(part)">Download</button>
- <button class="btn" zero-clipboard data-clipboard-text="{{part.output}}" title="Copy to clipboard">
- <i class="icon-copy"></i>
- </button> connector section for {{part.name}}
- </div>
-
- </div>
- <div class="modal-footer">
- <button class="btn btn-primary" type="button" ng-click="done()">Done</button>
- </div>
-
-<!--
-
- <div title="Configure new router">
-
- <label title="Show descriptions and default values in confile files"><input type="checkbox" ng-model="verbose"> Verbose output</label>
- <div>
- <button ng-click="download()">Download</button>
- <button class="btn" zero-clipboard data-clipboard-text="{{output}}" title="Copy to clipboard">
- <i class="icon-copy"></i>
- </button> configuration file for {{newRouterName}}
- </div>
- <div ng-repeat="part in parts">
- <button ng-click="downloadPart(part)">Download</button>
- <button class="btn" zero-clipboard data-clipboard-text="{{part.output}}" title="Copy to clipboard">
- <i class="icon-copy"></i>
- </button> connector section for {{part.name}}
- </div>
-
- <div class="okButton">
- <button ng-click="done()">Done</button>
- </div>
-
- </div>
--->
-</script>
-
diff --git a/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html b/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html
new file mode 120000
index 0000000..9dc2f21
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/html/qdrTopology.html
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/html/qdrTopology.html
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/html/tmplListChart.html
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/html/tmplListChart.html b/console/hawtio/src/main/webapp/plugin/html/tmplListChart.html
new file mode 100644
index 0000000..4a4811e
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/html/tmplListChart.html
@@ -0,0 +1,12 @@
+<div class="modal-header">
+ <h3 class="modal-title">Chart {{chart.attr() | humanify}}</h3>
+</div>
+<div class="modal-body">
+ <div id="{{svgDivId}}" class="d3Chart"></div>
+</div>
+<div class="modal-footer">
+ <span>
+ <div class="btn btn-success hdash-button" ng-click="addHChart()" title="Add this chart to a dashboard"><a ng-href="{{addToDashboardLink()}}"><i class="icon-share"></i> Add this chart to a dashboard</a></div>
+ </span>
+ <button class="btn btn-primary" type="button" ng-click="ok()">Close</button>
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/html/tmplListTree.html
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/html/tmplListTree.html b/console/hawtio/src/main/webapp/plugin/html/tmplListTree.html
new file mode 100644
index 0000000..b523efe
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/html/tmplListTree.html
@@ -0,0 +1,8 @@
+<hawtio-pane class="qdr-attributes" position="left" width="200">
+ <div class="treeContainer">
+ <div class="tree-header"><select ng-options="node as node.name for node in nodes" ng-model="currentNode" ng-change="selectNode(currentNode)"></select></div>
+ <div id="entityTree" onSelect="onTreeSelected" onRoot="onRootReady" hideRoot="true"></div>
+ <div ng-init="treeReady()"></div>
+ </div>
+</hawtio-pane>
+<ng-include src="'listGrid.html'"></ng-include>
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/html/tmplOverviewTree.html
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/html/tmplOverviewTree.html b/console/hawtio/src/main/webapp/plugin/html/tmplOverviewTree.html
new file mode 100644
index 0000000..48f9cbc
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/html/tmplOverviewTree.html
@@ -0,0 +1,6 @@
+<hawtio-pane class="qdr-overview" position="left" width="300">
+ <div class="treeContainer">
+ <div id="overtree"></div>
+ </div>
+</hawtio-pane>
+<ng-include src="'overviewGrid.html'"></ng-include>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/js/dispatchPlugin.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/dispatchPlugin.js b/console/hawtio/src/main/webapp/plugin/js/dispatchPlugin.js
index 80c2c9d..9383f06 100644
--- a/console/hawtio/src/main/webapp/plugin/js/dispatchPlugin.js
+++ b/console/hawtio/src/main/webapp/plugin/js/dispatchPlugin.js
@@ -82,6 +82,12 @@ var QDR = (function(QDR) {
.when(QDR.pluginRoot, {
templateUrl: QDR.templatePath + 'qdrConnect.html'
})
+ .when(QDR.pluginRoot + '/', {
+ templateUrl: QDR.templatePath + 'qdrConnect.html'
+ })
+ .when(QDR.pluginRoot + '/connect', {
+ templateUrl: QDR.templatePath + 'qdrConnect.html'
+ })
.when(QDR.pluginRoot + '/overview', {
templateUrl: QDR.templatePath + 'qdrOverview.html'
})
@@ -97,9 +103,6 @@ var QDR = (function(QDR) {
.when(QDR.pluginRoot + '/charts', {
templateUrl: QDR.templatePath + 'qdrCharts.html'
})
- .when(QDR.pluginRoot + '/connect', {
- templateUrl: QDR.templatePath + 'qdrConnect.html'
- })
})
.config(function ($compileProvider) {
var cur = $compileProvider.urlSanitizationWhitelist();
@@ -111,6 +114,7 @@ var QDR = (function(QDR) {
})
.filter('to_trusted', function($sce){
return function(text) {
+ debugger;
return $sce.trustAsHtml(text);
};
})
@@ -165,18 +169,22 @@ var QDR = (function(QDR) {
* plugin. This is just a matter of adding to the workspace's
* topLevelTabs array.
*/
- QDR.module.run(function(workspace, viewRegistry, layoutFull, $rootScope, $location, localStorage, QDRService, QDRChartService) {
+ QDR.module.run(function(workspace, viewRegistry, layoutFull, $route, $rootScope, $location, localStorage, QDRService, QDRChartService) {
QDR.log.info("*************creating Dispatch Console************");
var curPath = $location.path()
- var lastLocation = localStorage[QDR.LAST_LOCATION];
- if (!angular.isDefined(lastLocation)) {
- lastLocation = "connect";
- }
+ QDR.log.info("curPath is " + curPath)
+ var lastLocation = localStorage[QDR.LAST_LOCATION] || "connect"
if (lastLocation.startsWith(QDR.pluginRoot)) {
lastLocation = lastLocation.substr(QDR.pluginRoot.length+1)
+ if (lastLocation === '')
+ lastLocation = "overview"
}
+ $location.path(QDR.pluginRoot + "/connect");
if (curPath.startsWith(QDR.pluginRoot)) {
var org = curPath.substr(QDR.pluginRoot.length + 1)
+ if (org === '') {
+ org = lastLocation
+ }
if (curPath === QDR.pluginRoot && (!org || org.length===0 || org !== 'connect')) {
org = lastLocation
}
@@ -228,8 +236,9 @@ var QDR = (function(QDR) {
$rootScope.$on('$routeChangeSuccess', function() {
var path = $location.path();
if (path.startsWith(QDR.pluginRoot)) {
- if (path != QDR.pluginRoot && path != QDR.pluginRoot + "/connect") {
- localStorage[QDR.LAST_LOCATION] = $location.path();
+ if (path !== QDR.pluginRoot && path !== (QDR.pluginRoot + "/") && path !== (QDR.pluginRoot + "/connect")) {
+ localStorage[QDR.LAST_LOCATION] = path;
+QDR.log.info("saving page changed to " + path)
}
}
});
@@ -237,40 +246,17 @@ var QDR = (function(QDR) {
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
if (next && next.templateUrl == QDR.templatePath + "qdrConnect.html" && QDRService.connected) {
// clicked connect from another dispatch page
- if (current && current.loadedTemplateUrl.startsWith(QDR.contextPath)) {
+ if (current && current.loadedTemplateUrl && current.loadedTemplateUrl.startsWith(QDR.contextPath)) {
return;
}
// clicked the Dispatch Router top level tab from a different plugin
- var lastLocation = localStorage[QDR.LAST_LOCATION];
- if (!angular.isDefined(lastLocation)) {
- lastLocation = QDR.pluginRoot + "/overview";
- }
+ var lastLocation = localStorage[QDR.LAST_LOCATION] || (QDR.pluginRoot + "/overview");
// show the last page visited
+QDR.log.info("showing dispatch tab: going to page " + lastLocation)
$location.path(lastLocation)
}
});
- /* Set up top-level link to our plugin. Requires an object
- with the following attributes:
- id - the ID of this plugin, used by the perspective plugin
- and by the preferences page
- content - The text or HTML that should be shown in the tab
- title - This will be the tab's tooltip
- isValid - A function that returns whether or not this
- plugin has functionality that can be used for
- the current JVM. The workspace object is passed
- in by hawtio's navbar controller which lets
- you inspect the JMX tree, however you can do
- any checking necessary and return a boolean
- href - a function that returns a link, normally you'd
- return a hash link like #/foo/bar but you can
- also return a full URL to some other site
- isActive - Called by hawtio's navbar to see if the current
- $location.url() matches up with this plugin.
- Here we use a helper from workspace that
- checks if $location.url() starts with our
- route.
- */
workspace.topLevelTabs.push({
id: "dispatch",
content: "Dispatch Router",
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/js/navbar.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/navbar.js b/console/hawtio/src/main/webapp/plugin/js/navbar.js
deleted file mode 100644
index 74cc5a6..0000000
--- a/console/hawtio/src/main/webapp/plugin/js/navbar.js
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
-*/
-/**
- * @module QDR
- */
-var QDR = (function (QDR) {
-
- /**
- * @property breadcrumbs
- * @type {{content: string, title: string, isValid: isValid, href: string}[]}
- *
- * Data structure that defines the sub-level tabs for
- * our plugin, used by the navbar controller to show
- * or hide tabs based on some criteria
- */
- QDR.breadcrumbs = [
- {
- content: '<i class="icon-cogs"></i> Connect',
- title: "Connect to a router",
- isValid: function () { return true; },
- href: "#/" + QDR.pluginName + "/connect"
- },
- {
- content: '<i class="fa fa-home"></i> Overview',
- title: "View router overview",
- isValid: function (QDRService) { return QDRService.isConnected(); },
- href: "#/" + QDR.pluginName + "/overview"
- },
- {
- content: '<i class="icon-list "></i> Entities',
- title: "View the attributes of the router entities",
- isValid: function (QDRService) { return QDRService.isConnected(); },
- href: "#/" + QDR.pluginName + "/list"
- },
- {
- content: '<i class="icon-star-empty"></i> Topology',
- title: "View router network topology",
- isValid: function (QDRService) { return QDRService.isConnected(); },
- href: "#/" + QDR.pluginName + "/topology"
- },
- {
- content: '<i class="icon-align-left"></i> Schema',
- title: "View dispatch schema",
- isValid: function (QDRService) { return QDRService.isConnected(); },
- href: "#/" + QDR.pluginName + "/schema",
- right: true
-
- }
- ];
- /**
- * @function NavBarController
- *
- * @param $scope
- * @param workspace
- *
- * The controller for this plugin's navigation bar
- *
- */
-QDR.NavBarController = function($scope, QDRService, QDRChartService, $location, $routeParams) {
- $scope.breadcrumbs = QDR.breadcrumbs;
- $scope.isValid = function(link) {
- return link.isValid(QDRService, $location);
- };
-
- $scope.isActive = function(href) {
- // highlight the connect tab if we are on the root page
- if (($location.path() === QDR.pluginRoot) && (href.split("#")[1] === QDR.pluginRoot + "/connect"))
- return true
- return href.split("#")[1] == $location.path();
- };
-
- $scope.isRight = function (link) {
- return angular.isDefined(link.right);
- };
-
- $scope.hasChart = function (link) {
- if (link.href == "#/" + QDR.pluginName + "/charts") {
- return QDRChartService.charts.some(function (c) { return c.dashboard });
- }
- }
-
- $scope.isDashboardable = function () {
- return ($location.path().indexOf("schema") < 0 && $location.path().indexOf("connect") < 0);
- }
-
- $scope.addToDashboardLink = function () {
- var href = "#" + $location.path();
- var size = angular.toJson({
- size_x: 2,
- size_y: 2
- });
-
- var routeParams = angular.toJson($routeParams);
- var title = "Dispatch Router";
- return "/hawtio/#/dashboard/add?tab=dashboard" +
- "&href=" + encodeURIComponent(href) +
- "&routeParams=" + encodeURIComponent(routeParams) +
- "&title=" + encodeURIComponent(title) +
- "&size=" + encodeURIComponent(size);
- };
-
- };
-
-
- return QDR;
-
-} (QDR || {}));
diff --git a/console/hawtio/src/main/webapp/plugin/js/navbar.js b/console/hawtio/src/main/webapp/plugin/js/navbar.js
new file mode 120000
index 0000000..e88b618
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/navbar.js
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/js/navbar.js
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[03/11] qpid-dispatch git commit: DISPATCH-316 Hawtio and stand-alone
consoles now use common code
Posted by ea...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/js/qdrOverview.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrOverview.js b/console/stand-alone/plugin/js/qdrOverview.js
index d787a5e..d16b8e2 100644
--- a/console/stand-alone/plugin/js/qdrOverview.js
+++ b/console/stand-alone/plugin/js/qdrOverview.js
@@ -34,99 +34,118 @@ var QDR = (function (QDR) {
*
* Controller that handles the QDR overview page
*/
- QDR.module.controller("QDR.OverviewController", ['$scope', 'uiGridConstants', 'QDRService', function($scope, uiGridConstants, QDRService) {
+ QDR.module.controller("QDR.OverviewController", ['$scope', 'QDRService', '$location', '$timeout', function($scope, QDRService, $location, $timeout) {
+ console.log("QDR.OverviewControll started with location of " + $location.path() + " and connection of " + QDRService.connected);
+ var columnStateKey = 'QDRColumnKey.';
+ var OverviewExpandedKey = "QDROverviewExpanded"
+ var OverviewActivatedKey = "QDROverviewActivated"
+ var treeRoot; // the dynatree root node. initialized once log data is received
- if (!angular.isDefined(QDRService.schema))
- return;
-
- var nodeIds = QDRService.nodeIdList();
- var currentTimer;
+ // we want attributes to be listed first, so add it at index 0
+ $scope.subLevelTabs = [{
+ content: '<i class="icon-list"></i> Attributes',
+ title: "View the attribute values on your selection",
+ isValid: function (workspace) { return true; },
+ href: function () { return "#/" + QDR.pluginName + "/attributes"; },
+ index: 0
+ },
+ {
+ content: '<i class="icon-leaf"></i> Operations',
+ title: "Execute operations on your selection",
+ isValid: function (workspace) { return true; },
+ href: function () { return "#/" + QDR.pluginName + "/operations"; },
+ index: 1
+ }]
+ $scope.activeTab = $scope.subLevelTabs[0];
+ $scope.setActive = function (nav) {
+ $scope.activeTab = nav;
+ }
+ $scope.isValid = function (nav) {
+ return nav.isValid()
+ }
+ $scope.isActive = function (nav) {
+ return nav == $scope.activeTab;
+ }
+ $scope.linkFields = []
+ $scope.link = null;
var refreshInterval = 5000
- var Folder = (function () {
- function Folder(title) {
- this.title = title;
- this.children = [];
- this.folder = true;
- }
- return Folder;
- })();
- var Leaf = (function () {
- function Leaf(title) {
- this.title = title;
- }
- return Leaf;
- })();
$scope.modes = [
{title: 'Overview', name: 'Overview', right: false}
];
+ $scope.tmplOverviewTree = QDR.templatePath + 'tmplOverviewTree.html';
$scope.templates =
- [ { name: 'Routers', url: 'routers.html'},
+ [ { name: 'Routers', url: 'routers.html'},
{ name: 'Router', url: 'router.html'},
{ name: 'Addresses', url: 'addresses.html'},
{ name: 'Address', url: 'address.html'},
+ { name: 'Links', url: 'links.html'},
+ { name: 'Link', url: 'link.html'},
{ name: 'Connections', url: 'connections.html'},
{ name: 'Connection', url: 'connection.html'},
{ name: 'Logs', url: 'logs.html'},
- { name: 'Log', url: 'log.html'} ];
+ { name: 'Log', url: 'log.html'}
+ ];
+ var topLevelChildren = [];
- $scope.getGridHeight = function (data) {
- // add 1 for the header row
- return {height: (($scope[data.data].length + 1) * 30) + "px"};
+ $scope.allRouterSelected = function (row ) {
+ console.log("row selected" + row)
}
- $scope.overview = new Folder("Overview");
+ function afterSelectionChange(rowItem, checkAll) {
+ var nodeId = rowItem.entity.nodeId;
+ $("#overtree").dynatree("getTree").activateKey(nodeId);
+ }
$scope.allRouterFields = [];
- var allRouterCols = [
- {
- field: 'routerId',
- displayName: 'Router'
- },
- {
- field: 'area',
- displayName: 'Area'
- },
- {
- field: 'mode',
- displayName: 'Mode'
- },
- {
- field: 'connections',
- displayName: 'External connections'
- },
- {
- field: 'addrCount',
- displayName: 'Address count'
- },
- {
- field: 'linkCount',
- displayName: 'Link count'
- }
- ];
+ $scope.allRouterSelections = [];
$scope.allRouters = {
+ saveKey: 'allRouters',
data: 'allRouterFields',
- columnDefs: allRouterCols,
- enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
- enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
+ columnDefs: [
+ {
+ field: 'routerId',
+ saveKey: 'allRouters',
+ displayName: 'Router'
+ },
+ {
+ field: 'area',
+ displayName: 'Area'
+ },
+ {
+ field: 'mode',
+ displayName: 'Mode'
+ },
+ {
+ field: 'connections',
+ displayName: 'External connections'
+ },
+ {
+ field: 'addrCount',
+ displayName: 'Address count'
+ },
+ {
+ field: 'linkCount',
+ displayName: 'Link count'
+ }
+ ],
enableColumnResize: true,
multiSelect: false,
- enableRowHeaderSelection: false,
- noUnselect: true,
- enableSelectAll: false,
- enableRowSelection: true,
- onRegisterApi: function (gridApi) {
- gridApi.selection.on.rowSelectionChanged($scope, function(row) {
- if (row.isSelected) {
- var nodeId = row.entity.nodeId;
- $("#overtree").fancytree("getTree").activateKey(nodeId);
- }
- });
- }
+ selectedItems: $scope.allRouterSelections,
+ afterSelectionChange: function(data) {
+ if (data.selected) {
+ var selItem = $scope.allRouterSelections[0]
+ var nodeId = selItem.nodeId
+ // activate Routers->nodeId in the tree
+ $("#overtree").dynatree("getTree").activateKey(nodeId);
+
+ }
+ }
};
+
// get info for all routers
var allRouterInfo = function () {
- nodeIds = QDRService.nodeIdList()
+ var nodeIds = QDRService.nodeIdList()
var expected = Object.keys(nodeIds).length
var received = 0;
var allRouterFields = [];
@@ -145,63 +164,59 @@ var QDR = (function (QDR) {
if (expected == received) {
allRouterFields.sort ( function (a,b) { return a.routerId < b.routerId ? -1 : a.routerId > b.routerId ? 1 : 0})
// now get each router's node info
- QDRService.getMultipleNodeInfo(nodeIds, "router", [], function (nodeIds, entity, response) {
- var results = response.aggregates
- results.forEach ( function (result) {
-
- var routerId = QDRService.valFor(response.attributeNames, result, "routerId").sum
+ QDRService.getMultipleNodeInfo(nodeIds, "router", [], function (nodeIds, entity, responses) {
+ for(var r in responses) {
+ var result = responses[r]
+ var routerId = QDRService.valFor(result.attributeNames, result.results[0], "routerId")
allRouterFields.some( function (connField) {
if (routerId === connField.routerId) {
- response.attributeNames.forEach ( function (attrName) {
- connField[attrName] = QDRService.valFor(response.attributeNames, result, attrName).sum
+ result.attributeNames.forEach ( function (attrName) {
+ connField[attrName] = QDRService.valFor(result.attributeNames, result.results[0], attrName)
})
return true
}
return false
})
- })
- $scope.allRouterFields = allRouterFields
- $scope.$apply()
- if (currentTimer) {
- clearTimeout(currentTimer)
}
- currentTimer = setTimeout(allRouterInfo, refreshInterval);
- }, nodeIds[0])
+ $scope.allRouterFields = allRouterFields
+ }, nodeIds[0], false)
}
}
- nodeIds.forEach ( function (nodeId) {
+ nodeIds.forEach ( function (nodeId, i) {
QDRService.getNodeInfo(nodeId, ".connection", ["role"], gotNodeInfo)
})
-
+ loadColState($scope.allRouters)
+ updateRouterTree(nodeIds)
}
+ $scope.routerFields = []
+ $scope.routerGrid = {
+ saveKey: 'routerGrid',
+ data: 'routerFields',
+ columnDefs: [
+ {
+ field: 'attribute',
+ displayName: 'Attribute',
+ saveKey: 'routerGrid',
+ width: '40%'
+ },
+ {
+ field: 'value',
+ displayName: 'Value',
+ width: '40%'
+ }
+ ],
+ enableColumnResize: true,
+ multiSelect: false
+ }
+
// get info for a single router
var routerInfo = function (node) {
$scope.router = node
- $scope.routerFields = []
- var cols = [
- {
- field: 'attribute',
- displayName: 'Attribute',
- width: '40%'
- },
- {
- field: 'value',
- displayName: 'Value',
- width: '40%'
- }
- ]
- $scope.routerGrid = {
- data: 'routerFields',
- columnDefs: cols,
- enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
- enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
- enableColumnResize: true,
- multiSelect: false
- }
+ $scope.routerFields = [];
$scope.allRouterFields.some( function (field) {
- if (field.routerId === node.title) {
+ if (field.routerId === node.data.title) {
Object.keys(field).forEach ( function (key) {
if (key !== '$$hashKey')
$scope.routerFields.push({attribute: key, value: field[key]})
@@ -209,90 +224,90 @@ var QDR = (function (QDR) {
return true
}
})
-
- $scope.$apply()
- if (currentTimer) {
- clearTimeout(currentTimer)
- currentTimer = null
- }
+ loadColState($scope.routerGrid);
}
- // get info for a all addresses
- var allAddressInfo = function () {
- $scope.addressFields = []
- var addressCols = [
- {
- field: 'address',
- displayName: 'address'
- },
- {
- field: 'class',
- displayName: 'class'
- },
- {
- field: 'phase',
- displayName: 'phase',
- cellClass: 'grid-align-value'
- },
- {
- field: 'inproc',
- displayName: 'in-proc'
- },
- {
- field: 'local',
- displayName: 'local',
- cellClass: 'grid-align-value'
- },
- {
- field: 'remote',
- displayName: 'remote',
- cellClass: 'grid-align-value'
- },
- {
- field: 'in',
- displayName: 'in',
- cellClass: 'grid-align-value'
- },
- {
- field: 'out',
- displayName: 'out',
- cellClass: 'grid-align-value'
- }
- ]
- $scope.selectedAddresses = []
- $scope.addressGrid = {
- data: 'addressFields',
- columnDefs: addressCols,
- enableColumnResize: true,
- enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
- enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
- multiSelect: false,
- enableRowHeaderSelection: false,
- noUnselect: true,
- enableSelectAll: false,
- enableRowSelection: true,
- onRegisterApi: function (gridApi) {
- gridApi.selection.on.rowSelectionChanged($scope, function(row) {
- if (row.isSelected) {
- var key = row.entity.uid;
- $("#overtree").fancytree("getTree").activateKey(key);
- }
- });
- }
- }
+ $scope.addressesData = []
+ $scope.selectedAddresses = []
+ $scope.addressesGrid = {
+ saveKey: 'addressesGrid',
+ data: 'addressesData',
+ columnDefs: [
+ {
+ field: 'address',
+ saveKey: 'addressesGrid',
+ displayName: 'address'
+ },
+ {
+ field: 'class',
+ displayName: 'class'
+ },
+ {
+ field: 'phase',
+ displayName: 'phase',
+ cellClass: 'grid-align-value'
+ },
+ {
+ field: 'inproc',
+ displayName: 'in-proc'
+ },
+ {
+ field: 'local',
+ displayName: 'local',
+ cellClass: 'grid-align-value'
+ },
+ {
+ field: 'remote',
+ displayName: 'remote',
+ cellClass: 'grid-align-value'
+ },
+ {
+ field: 'in',
+ displayName: 'in',
+ cellClass: 'grid-align-value'
+ },
+ {
+ field: 'out',
+ displayName: 'out',
+ cellClass: 'grid-align-value'
+ }
+ ],
+ enableColumnResize: true,
+ multiSelect: false,
+ selectedItems: $scope.selectedAddresses,
+ afterSelectionChange: function(data) {
+ if (data.selected) {
+ var selItem = data.entity;
+ var nodeId = selItem.uid
+ $("#overtree").dynatree("getTree").activateKey(nodeId);
+ }
+ }
+ };
+ // get info for all addresses
+ var allAddressInfo = function () {
var gotAllAddressFields = function ( addressFields ) {
- $scope.addressFields = addressFields
- $scope.$apply()
- if (currentTimer) {
- clearTimeout(currentTimer)
+ // update the grid's data
+ addressFields.sort ( function (a,b) { return a.address < b.address ? -1 : a.address > b.address ? 1 : 0})
+ addressFields[0].title = addressFields[0].address
+ for (var i=1; i<addressFields.length; ++i) {
+ if (addressFields[i].address === addressFields[i-1].address) {
+ addressFields[i-1].title = addressFields[i-1].address + " (" + addressFields[i-1]['class'] + ")"
+ addressFields[i].title = addressFields[i].address + " (" + addressFields[i]['class'] + ")"
+ } else
+ addressFields[i].title = addressFields[i].address
}
- currentTimer = setTimeout(allAddressInfo, refreshInterval);
+ $scope.addressesData = addressFields
+
+ // repopulate the tree's child nodes
+ updateAddressTree(addressFields)
}
getAllAddressFields(gotAllAddressFields)
+ loadColState($scope.addressesGrid);
}
var getAllAddressFields = function (callback) {
+ var nodeIds = QDRService.nodeIdList()
var addr_class = function (addr) {
if (!addr) return "-"
if (addr[0] == 'M') return "mobile"
@@ -331,7 +346,6 @@ var QDR = (function (QDR) {
}
var addressFields = []
- nodeIds = QDRService.nodeIdList()
QDRService.getMultipleNodeInfo(nodeIds, "router.address", [], function (nodeIds, entity, response) {
response.aggregates.forEach( function (result) {
var prettySum = function (field) {
@@ -365,139 +379,667 @@ var QDR = (function (QDR) {
}, nodeIds[0])
}
+ var updateLinkGrid = function ( linkFields ) {
+ $scope.linkFields = linkFields
+ // if we have a selected link
+ if ($scope.link) {
+ // find the selected link in the array of all links
+ var links = $scope.linkFields.filter(function (link) {
+ return link.name === $scope.link.data.fields.name;
+ })
+ if (links.length > 0) {
+ // linkInfo() is the function that is called by dynatree when a link is selected
+ // It is passed a dynatree node. We need to simulate that node type to update the link grid
+ linkInfo({data: {title: links[0].title, fields: links[0]}})
+ }
+ }
+ }
+
+ // get info for a all links
+ $scope.selectedLinks = []
+ $scope.linksGrid = {
+ saveKey: 'linksGrid',
+ data: 'linkFields',
+ columnDefs: [
+ {
+ field: 'link',
+ displayName: 'Link',
+ groupable: false,
+ saveKey: 'linksGrid',
+ width: '12%'
+ },
+ {
+ field: 'linkType',
+ displayName: 'Link type',
+ groupable: false,
+ width: '10%'
+ },
+ {
+ field: 'linkDir',
+ displayName: 'Link dir',
+ groupable: false,
+ width: '8%'
+ },
+ {
+ field: 'adminStatus',
+ displayName: 'Admin status',
+ groupable: false,
+ width: '10%'
+ },
+ {
+ field: 'operStatus',
+ displayName: 'Oper status',
+ groupable: false,
+ width: '10%'
+ },
+ {
+ field: 'deliveryCount',
+ displayName: 'Delivery Count',
+ groupable: false,
+ cellClass: 'grid-align-value',
+ width: '12%'
+ },
+ {
+ field: 'rate',
+ displayName: 'Rate',
+ groupable: false,
+ cellClass: 'grid-align-value',
+ width: '8%'
+ },
+ {
+ field: 'uncounts',
+ displayName: 'Outstanding',
+ groupable: false,
+ cellClass: 'grid-align-value',
+ width: '10%'
+ },
+ {
+ field: 'owningAddr',
+ displayName: 'Address',
+ groupable: false,
+ width: '20%'
+ }
+ ],
+ enableColumnResize: true,
+ enableColumnReordering: true,
+ showColumnMenu: true,
+ rowTemplate: 'linkRowTemplate.html',
+ // aggregateTemplate: "linkAggTemplate.html",
+ multiSelect: false,
+ selectedItems: $scope.selectedLinks,
+ afterSelectionChange: function(data) {
+ if (data.selected) {
+ var selItem = data.entity;
+ var nodeId = selItem.uid
+ $("#overtree").dynatree("getTree").activateKey(nodeId);
+ }
+ }
+ };
+
+ $scope.$on('ngGridEventColumns', function (e, columns) {
+ var saveInfo = columns.map( function (col) {
+ return [col.width, col.visible]
+ })
+ var saveKey = columns[0].colDef.saveKey
+ if (saveKey)
+ localStorage.setItem(columnStateKey+saveKey, JSON.stringify(saveInfo));
+ })
+
+ var loadColState = function (grid) {
+ if (!grid)
+ return;
+ var columns = localStorage.getItem(columnStateKey+grid.saveKey);
+ if (columns) {
+ var cols = JSON.parse(columns);
+ cols.forEach( function (col, index) {
+ grid.columnDefs[index].width = col[0];
+ grid.columnDefs[index].visible = col[1]
+ })
+ }
+ }
+ var allLinkInfo = function () {
+ getAllLinkFields([updateLinkGrid, updateLinkTree])
+ loadColState($scope.linksGrid);
+ }
+
+ var getAllLinkFields = function (callbacks) {
+ var nodeIds = QDRService.nodeIdList()
+ var linkFields = []
+ var now = Date.now()
+ var rate = function (response, result) {
+ var name = QDRService.valFor(response.attributeNames, result, "linkName").sum
+ var oldname = $scope.linkFields.filter(function (link) {
+ return link.linkName === name
+ })
+ if (oldname.length > 0) {
+ var elapsed = (now - oldname[0].timestamp) / 1000;
+ var delivered = QDRService.valFor(response.attributeNames, result, "deliveryCount").sum - oldname[0].rawDeliveryCount
+ //QDR.log.debug("elapsed " + elapsed + " delivered " + delivered)
+ return elapsed > 0 ? parseFloat(Math.round((delivered/elapsed) * 100) / 100).toFixed(2) : 0;
+ } else {
+ //QDR.log.debug("unable to find old linkName")
+ return 0
+ }
+ }
+ QDRService.getMultipleNodeInfo(nodeIds, "router.link", [], function (nodeIds, entity, response) {
+ response.aggregates.forEach( function (result) {
+ var prettySum = function (field) {
+ var fieldIndex = response.attributeNames.indexOf(field)
+ if (fieldIndex < 0) {
+ return "-"
+ }
+ var val = result[fieldIndex].sum
+ return QDRService.pretty(val)
+ }
+ var uncounts = function () {
+ var und = QDRService.valFor(response.attributeNames, result, "undeliveredCount").sum
+ var uns = QDRService.valFor(response.attributeNames, result, "unsettledCount").sum
+ return und + uns
+ }
+ var nameIndex = response.attributeNames.indexOf('name')
+ var linkName = function () {
+ var details = result[nameIndex].detail
+ var names = []
+ details.forEach( function (detail) {
+ if (detail.node.endsWith(':'))
+ names.push(detail.node.slice(0, -1))
+ else
+ names.push(detail.node)
+ })
+ //var namestr = names.join('-')
+ var namestr = names.length > 0 ? names[0] : ""
+ return namestr + ':' + QDRService.valFor(response.attributeNames, result, "identity").sum
+ }
+ var fixAddress = function () {
+ var owningAddr = QDRService.valFor(response.attributeNames, result, "owningAddr").sum || ""
+ /*
+ - "L*" => "* (local)"
+ - "M0*" => "* (direct)"
+ - "M1*" => "* (dequeue)"
+ - "MX*" => "* (phase X)"
+ */
+ var address = undefined;
+ var starts = {'L': '(local)', 'M0': '(direct)', 'M1': '(dequeue)'}
+ for (var start in starts) {
+ if (owningAddr.startsWith(start)) {
+ var ends = owningAddr.substr(start.length)
+ address = ends + " " + starts[start]
+ break;
+ }
+ }
+ if (!address) {
+ // check for MX*
+ if (owningAddr.length > 3) {
+ if (owningAddr[0] === 'M') {
+ var phase = parseInt(owningAddress.substr(1))
+ if (phase && !isNaN(phase)) {
+ var phaseStr = phase + "";
+ var star = owningAddress.substr(2 + phaseStr.length)
+ address = star + " " + "(phase " + phaseStr + ")"
+ }
+ }
+ }
+ }
+ return address || owningAddr;
+ }
+
+ var adminStatus = QDRService.valFor(response.attributeNames, result, "adminStatus").sum
+ var operStatus = QDRService.valFor(response.attributeNames, result, "operStatus").sum
+ var linkName = linkName()
+ var linkType = QDRService.valFor(response.attributeNames, result, "linkType").sum
+ if ($scope.currentLinkFilter === "" || $scope.currentLinkFilter === linkType) {
+ linkFields.push({
+ link: linkName,
+ title: linkName,
+ uncounts: uncounts(),
+ operStatus: operStatus,
+ adminStatus:adminStatus,
+ owningAddr: fixAddress(),
+ deliveryCount:prettySum("deliveryCount") + " ",
+ rawDeliveryCount: QDRService.valFor(response.attributeNames, result, "deliveryCount").sum,
+ name: QDRService.valFor(response.attributeNames, result, "name").sum,
+ linkName: QDRService.valFor(response.attributeNames, result, "linkName").sum,
+ capacity: QDRService.valFor(response.attributeNames, result, "capacity").sum,
+ connectionId: QDRService.valFor(response.attributeNames, result, "connectionId").sum,
+ linkDir: QDRService.valFor(response.attributeNames, result, "linkDir").sum,
+ linkType: linkType,
+ peer: QDRService.valFor(response.attributeNames, result, "peer").sum,
+ type: QDRService.valFor(response.attributeNames, result, "type").sum,
+ undeliveredCount: QDRService.valFor(response.attributeNames, result, "undeliveredCount").sum,
+ unsettledCount: QDRService.valFor(response.attributeNames, result, "unsettledCount").sum,
+ uid: linkName,
+ timestamp: now,
+ rate: rate(response, result)
+ })
+ }
+ })
+ callbacks.forEach( function (cb) {
+ cb(linkFields)
+ })
+ }, nodeIds[0])
+ }
+
+ $scope.allConnectionFields = []
+ $scope.allConnectionSelections = [];
+ $scope.allConnectionGrid = {
+ saveKey: 'allConnGrid',
+ data: 'allConnectionFields',
+ columnDefs: [
+ {
+ field: 'host',
+ saveKey: 'allConnGrid',
+ displayName: 'host'
+ },
+ {
+ field: 'container',
+ displayName: 'container'
+ },
+ {
+ field: 'role',
+ displayName: 'role'
+ },
+ {
+ field: 'dir',
+ displayName: 'dir'
+ },
+ {
+ field: 'security',
+ displayName: 'security'
+ },
+ {
+ field: 'authentication',
+ displayName: 'authentication'
+ }
+ ],
+ enableColumnResize: true,
+ multiSelect: false,
+ selectedItems: $scope.allConnectionSelections,
+ afterSelectionChange: function(data) {
+ if (data.selected) {
+ var selItem = $scope.allConnectionSelections[0]
+ var nodeId = selItem.host
+ // activate Routers->nodeId in the tree
+ $("#overtree").dynatree("getTree").activateKey(nodeId);
+ }
+ }
+ };
// get info for a all connections
var allConnectionInfo = function () {
- $scope.allConnectionFields = []
- var allConnectionCols = [
- {
- field: 'host',
- displayName: 'host'
- },
- {
- field: 'container',
- displayName: 'container'
- },
- {
- field: 'role',
- displayName: 'role'
- },
- {
- field: 'dir',
- displayName: 'dir'
- },
- {
- field: 'security',
- displayName: 'security'
- },
- {
- field: 'authentication',
- displayName: 'authentication'
- }
- ]
- $scope.allConnectionGrid = {
- data: 'allConnectionFields',
- columnDefs: allConnectionCols,
- enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
- enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
- enableColumnResize: true,
- multiSelect: false,
- enableRowHeaderSelection: false,
- noUnselect: true,
- enableSelectAll: false,
- enableRowSelection: true,
- onRegisterApi: function (gridApi) {
- gridApi.selection.on.rowSelectionChanged($scope, function(row) {
- if (row.isSelected) {
- var host = row.entity.host;
- $("#overtree").fancytree("getTree").activateKey(host);
- }
- });
- }
- }
- connections.children.forEach( function (connection) {
- $scope.allConnectionFields.push(connection.fields)
+ var nodeIds = QDRService.nodeIdList()
+ updateConnectionTree(nodeIds)
+ $scope.allConnectionFields = [];;
+ var connectionNodes = $("#overtree").dynatree("getTree").getNodeByKey('Connections').getChildren()
+ connectionNodes.forEach( function (connection) {
+ $scope.allConnectionFields.push(connection.data.fields)
})
- $scope.$apply()
- if (currentTimer) {
- clearTimeout(currentTimer)
- currentTimer = null
- }
+ loadColState($scope.allConnectionGrid);
+ }
+
+ $scope.addressFields = []
+ $scope.addressGrid = {
+ saveKey: 'addGrid',
+ data: 'addressFields',
+ columnDefs: [
+ {
+ field: 'attribute',
+ displayName: 'Attribute',
+ saveKey: 'addGrid',
+ width: '40%'
+ },
+ {
+ field: 'value',
+ displayName: 'Value',
+ width: '40%'
+ }
+ ],
+ enableColumnResize: true,
+ multiSelect: false
}
// get info for a single address
var addressInfo = function (address) {
+ if (!address)
+ return;
$scope.address = address
- $scope.addressFields = []
- var cols = [
- {
- field: 'attribute',
- displayName: 'Attribute',
- width: '40%'
- },
- {
- field: 'value',
- displayName: 'Value',
- width: '40%'
- }
- ]
- $scope.addressGrid = {
- data: 'addressFields',
- columnDefs: cols,
- enableColumnResize: true,
- enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
- enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
- multiSelect: false
- }
+ $scope.addressFields = [];
var fields = Object.keys(address.data.fields)
fields.forEach( function (field) {
if (field != "title" && field != "uid")
$scope.addressFields.push({attribute: field, value: address.data.fields[field]})
})
+ loadColState($scope.addressGrid);
+ }
- $scope.$apply()
- if (currentTimer) {
- clearTimeout(currentTimer)
- currentTimer = null
- }
+ $scope.singleLinkFields = []
+ $scope.linkGrid = {
+ saveKey: 'linkGrid',
+ data: 'singleLinkFields',
+ columnDefs: [
+ {
+ field: 'attribute',
+ displayName: 'Attribute',
+ width: '40%'
+ },
+ {
+ field: 'value',
+ displayName: 'Value',
+ width: '40%'
+ }
+ ],
+ enableColumnResize: true,
+ multiSelect: false
+ }
+
+ // display the grid detail info for a single link
+ var linkInfo = function (link) {
+ if (!link)
+ return;
+ $scope.link = link
+
+ $scope.singleLinkFields = [];
+ var fields = Object.keys(link.data.fields)
+ var excludeFields = ["title", "uid", "uncounts", "rawDeliveryCount", "timestamp"]
+ fields.forEach( function (field) {
+ if (excludeFields.indexOf(field) == -1)
+ $scope.singleLinkFields.push({attribute: field, value: link.data.fields[field]})
+ })
+ loadColState($scope.linkGrid);
}
// get info for a single connection
+ $scope.connectionModes = [{
+ content: '<a><i class="icon-list"></i> Attriutes</a>',
+ id: 'attributes',
+ title: "View connection attributes",
+ isValid: function () { return true; }
+ },
+ {
+ content: '<a><i class="icon-link"></i> Links</a>',
+ id: 'links',
+ title: "Show links",
+ isValid: function () { return true }
+ }
+ ];
+ $scope.currentMode = $scope.connectionModes[0];
+ $scope.isModeSelected = function (mode) {
+ return mode === $scope.currentMode;
+ }
+ $scope.connectionLinks = [];
+ var updateConnectionLinks = function () {
+ var n = $scope.connection.data.fields
+ var key = n.routerId
+ var nodeInfo = QDRService.topology.nodeInfo();
+ var links = nodeInfo[key]['.router.link'];
+ var linkTypeIndex = links.attributeNames.indexOf('linkType');
+ var connectionIdIndex = links.attributeNames.indexOf('connectionId');
+ $scope.connectionLinks = [];
+ links.results.forEach( function (link) {
+ if (link[linkTypeIndex] === 'endpoint' && link[connectionIdIndex] === n.identity) {
+ var l = {};
+ l.owningAddr = QDRService.valFor(links.attributeNames, link, 'owningAddr');
+ l.dir = QDRService.valFor(links.attributeNames, link, 'linkDir');
+ if (l.owningAddr && l.owningAddr.length > 2)
+ if (l.owningAddr[0] === 'M')
+ l.owningAddr = l.owningAddr.substr(2)
+ else
+ l.owningAddr = l.owningAddr.substr(1)
+
+ l.adminStatus = QDRService.valFor(links.attributeNames, link, 'adminStatus');
+ l.operStatus = QDRService.valFor(links.attributeNames, link, 'operStatus');
+ l.identity = QDRService.valFor(links.attributeNames, link, 'identity')
+ l.connectionId = QDRService.valFor(links.attributeNames, link, 'connectionId')
+/*
+ l.deliveryCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'deliveryCount'));
+ l.undeliveredCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'undeliveredCount'));
+ l.unsettledCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'unsettledCount'));
+*/
+ // ---------------------------------------------
+ // TODO: remove this fake quiescing/reviving logic when the routers do the work
+ if ($scope.quiesceState.linkStates[l.identity])
+ l.adminStatus = $scope.quiesceState.linkStates[l.identity];
+ if ($scope.quiesceState.operStates[l.identity])
+ l.operStatus = $scope.quiesceState.operStates[l.identity];
+ if ($scope.quiesceState.state == 'quiescing') {
+ if (l.adminStatus === 'enabled') {
+ var chance = Math.floor(Math.random() * 2);
+ if (chance == 1) {
+ l.adminStatus = 'disabled';
+ $scope.quiesceState.linkStates[l.identity] = 'disabled';
+ $scope.quiesceState.operStates[l.identity] = 'idle';
+ }
+ }
+ }
+ if ($scope.quiesceState.state == 'reviving') {
+ if (l.adminStatus === 'disabled') {
+ var chance = Math.floor(Math.random() * 2);
+ if (chance == 1) {
+ l.adminStatus = 'enabled';
+ $scope.quiesceState.linkStates[l.identity] = 'enabled';
+ $scope.quiesceState.operStates[l.identity] = 'up';
+ }
+ }
+ }
+ if ($scope.quiesceState.linkStates[l.identity] === 'disabled') {
+ l.unsettledCount = 0;
+ l.undeliveredCount = 0;
+ l.operState = 'idle'
+ $scope.quiesceState.operStates[l.identity] = l.operState
+ } else {
+ l.deliveryCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'deliveryCount'));
+ l.undeliveredCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'undeliveredCount'));
+ l.unsettledCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'unsettledCount'));
+ l.operState = 'up'
+ $scope.quiesceState.operStates[l.identity] = l.operState
+ }
+ // ---------------------------------------------
+
+ $scope.connectionLinks.push(l)
+ }
+ })
+ $scope.connectionLinksGrid.updateState()
+ }
+
+ $scope.selectMode = function (mode) {
+ $scope.currentMode = mode;
+ if (mode.id === 'links') {
+ QDRService.addUpdatedAction("connectionLinks", updateConnectionLinks)
+ updateConnectionLinks();
+ } else {
+ QDRService.delUpdatedAction("connectionLinks");
+ }
+ }
+ $scope.isValid = function (mode) {
+ return mode.isValid()
+ }
+ $scope.quiesceState = {
+ state: 'enabled',
+ buttonText: 'Quiesce',
+ buttonDisabled: false,
+ linkStates: {},
+ operStates: {}
+ }
+ $scope.quiesceAllClicked = function () {
+ var state = $scope.quiesceState.state;
+ if (state === 'enabled') {
+ // start quiescing all links
+ $scope.quiesceState.state = 'quiescing';
+ } else if (state === 'quiesced') {
+ // start reviving all links
+ $scope.quiesceState.state = 'reviving';
+ }
+ $scope.connectionLinksGrid.updateState();
+ }
+ $scope.quiesceClass = function (row) {
+ var stateClassMap = {
+ enabled: 'btn-primary',
+ quiescing: 'btn-warning',
+ reviving: 'btn-warning',
+ quiesced: 'btn-danger'
+ }
+ return stateClassMap[$scope.quiesceState.state];
+ }
+ $scope.quiesceLinkClass = function (row) {
+ var stateClassMap = {
+ enabled: 'btn-primary',
+ disabled: 'btn-danger'
+ }
+ return stateClassMap[row.entity.adminStatus]
+ }
+ $scope.quiesceLink = function (row) {
+ var state = row.entity.adminStatus === 'enabled' ? 'disabled' : 'enabled';
+ var operState = state === 'enabled' ? 'up' : 'idle';
+ $scope.quiesceState.linkStates[row.entity.identity] = state;
+ $scope.quiesceState.operStates[row.entity.identity] = operState;
+ }
+ $scope.quiesceLinkDisabled = function (row) {
+ return false;
+ }
+ $scope.quiesceLinkText = function (row) {
+ return row.entity.adminStatus === 'disabled' ? "Revive" : "Quiesce";
+ }
+ $scope.quiesceHide = function () {
+ return $scope.connectionLinks.length == 0;
+ }
+ $scope.connectionLinksGrid = {
+ saveKey: 'connLinksGrid',
+
+ data: 'connectionLinks',
+ updateState: function () {
+ var state = $scope.quiesceState.state;
+
+ // count enabled and disabled links for this connection
+ var enabled = 0, disabled = 0;
+ $scope.connectionLinks.forEach ( function (link) {
+ if (link.adminStatus === 'enabled')
+ ++enabled;
+ if (link.adminStatus === 'disabled')
+ ++disabled;
+ })
+
+ var linkCount = $scope.connectionLinks.length;
+ if (linkCount == 0) {
+ $scope.quiesceState.buttonText = 'Quiesce';
+ $scope.quiesceState.buttonDisabled = false;
+ $scope.quiesceState.state = 'enabled'
+ return;
+ }
+ // if state is quiescing and any links are enabled, button should say 'Quiescing' and be disabled
+ if (state === 'quiescing' && (enabled > 0)) {
+ $scope.quiesceState.buttonText = 'Quiescing';
+ $scope.quiesceState.buttonDisabled = true;
+ } else
+ // if state is enabled and all links are disabled, button should say Revive and be enabled. set state to quisced
+ // if state is quiescing and all links are disabled, button should say 'Revive' and be enabled. set state to quiesced
+ if ((state === 'quiescing' || state === 'enabled') && (disabled === linkCount)) {
+ $scope.quiesceState.buttonText = 'Revive';
+ $scope.quiesceState.buttonDisabled = false;
+ $scope.quiesceState.state = 'quiesced'
+ } else
+ // if state is reviving and any links are disabled, button should say 'Reviving' and be disabled
+ if (state === 'reviving' && (disabled > 0)) {
+ $scope.quiesceState.buttonText = 'Reviving';
+ $scope.quiesceState.buttonDisabled = true;
+ } else
+ // if state is reviving or quiesced and all links are enabled, button should say 'Quiesce' and be enabled. set state to enabled
+ if ((state === 'reviving' || state === 'quiesced') && (enabled === linkCount)) {
+ $scope.quiesceState.buttonText = 'Quiesce';
+ $scope.quiesceState.buttonDisabled = false;
+ $scope.quiesceState.state = 'enabled'
+ }
+
+ if ($scope.quiesceState.state === 'quiesced') {
+ d3.selectAll('.external.connection.dynatree-active')
+ .classed('quiesced', true)
+ } else {
+ d3.selectAll('.external.connection.dynatree-active.quiesced')
+ .classed('quiesced', false)
+ }
+ },
+ columnDefs: [
+ {
+ field: 'adminStatus',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ saveKey: 'connLinksGrid',
+ displayName: 'Admin state'
+ },
+ {
+ field: 'operStatus',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ displayName: 'Oper state'
+ },
+ {
+ field: 'dir',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ displayName: 'dir'
+ },
+ {
+ field: 'owningAddr',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ displayName: 'Address'
+ },
+ {
+ field: 'deliveryCount',
+ displayName: 'Delivered',
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ cellClass: 'grid-values'
+
+ },
+ {
+ field: 'undeliveredCount',
+ displayName: 'Undelivered',
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ cellClass: 'grid-values'
+ },
+ {
+ field: 'unsettledCount',
+ displayName: 'Unsettled',
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ cellClass: 'grid-values'
+ }/*,
+ {
+ cellClass: 'gridCellButton',
+ cellTemplate: '<button title="{{quiesceLinkText(row)}} this link" type="button" ng-class="quiesceLinkClass(row)" class="btn" ng-click="quiesceLink(row)" ng-disabled="quiesceLinkDisabled(row)">{{quiesceLinkText(row)}}</button>'
+ }*/
+ ]
+ }
+
+ $scope.connectionFields = []
+ $scope.connectionGrid = {
+ saveKey: 'connGrid',
+ data: 'connectionFields',
+ columnDefs: [
+ {
+ field: 'attribute',
+ displayName: 'Attribute',
+ saveKey: 'connGrid',
+ width: '40%'
+ },
+ {
+ field: 'value',
+ displayName: 'Value',
+ width: '40%'
+ }
+ ],
+ enableColumnResize: true,
+ multiSelect: false
+ }
+
var connectionInfo = function (connection) {
$scope.connection = connection
- $scope.connectionFields = []
- var cols = [
- {
- field: 'attribute',
- displayName: 'Attribute',
- width: '40%'
- },
- {
- field: 'value',
- displayName: 'Value',
- width: '40%'
- }
- ]
- $scope.connectionGrid = {
- data: 'connectionFields',
- columnDefs: cols,
- enableColumnResize: true,
- enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
- enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
- multiSelect: false
- }
+ $scope.connectionFields = [];
var fields = Object.keys(connection.data.fields)
fields.forEach( function (field) {
$scope.connectionFields.push({attribute: field, value: connection.data.fields[field]})
})
-
- $scope.$apply()
- if (currentTimer) {
- clearTimeout(currentTimer)
- currentTimer = null
- }
+ $scope.selectMode($scope.currentMode)
+ loadColState($scope.connectionGrid);
}
// get info for a all logs
@@ -509,142 +1051,309 @@ var QDR = (function (QDR) {
$scope.log = node
}
- var activated = function (event, node) {
+ var getExpandedList = function () {
+ if (!treeRoot)
+ return;
+ var list = [];
+ if (treeRoot.visit) {
+ treeRoot.visit(function(node){
+ if (node.isExpanded()) {
+ list.push(node.data.parent)
+ }
+ });
+ }
+ return list;
+ }
+
+ var updateExpanded = function () {
+ if (!treeRoot)
+ return;
+ if (treeRoot.visit) {
+ treeRoot.visit(function(node){
+ if (node.isExpanded() || node.isActive()) {
+ node.data.info(node)
+ }
+ });
+ }
+ }
+
+ // loads the tree node name that was last selected
+ var loadActivatedNode = function () {
+ return localStorage[OverviewActivatedKey] || 'Routers'
+ }
+ // saved the tree node name that is currently selected
+ var saveActivated = function (key) {
+ localStorage[OverviewActivatedKey] = key;
+ lastKey = key;
+ }
+ // loads list that was saved
+ var loadExpandedNodeList = function () {
+ return angular.fromJson(localStorage[OverviewExpandedKey]) || [];
+ }
+ // called when a node is expanded
+ // here we save the expanded node so it can be restored when the page reloads
+ var saveExpanded = function () {
+ var list = getExpandedList();
+ localStorage[OverviewExpandedKey] = JSON.stringify(list)
+ }
+
+ // activated is called each time a tree node is clicked
+ // based on which node is clicked, load the correct data grid template and start getting the data
+ var activated = function (node) {
//QDR.log.debug("node activated: " + node.data.title)
- node = node.node;
var type = node.data.type;
+ saveExpanded()
+ saveActivated(node.data.key)
+
var template = $scope.templates.filter( function (tpl) {
return tpl.name == type;
})
$scope.template = template[0];
- // Call the function associated with this type passing in the node that was selected
- // In dynatree I could save the function to call in the node, but not in FancyTree
- if (treeTypeMap[type])
- treeTypeMap[type](node);
-
- /*if (node.data.info)
- node.data.info(node)
- */
+ // the nodes info function will fetch the grids data
+ if (node.data.info) {
+ $timeout(function () {node.data.info(node)})
+ }
+
+ }
+ $scope.template = {url: ''};
+
+ if (!QDRService.connected) {
+ QDRService.redirectWhenConnected("overview")
+ return;
+ }
+
+ // we are currently connected. setup a handler to get notified if we are ever disconnected
+ QDRService.addDisconnectAction( function () {
+ QDRService.redirectWhenConnected("overview")
$scope.$apply();
+ })
+
+ /* --------------------------------------------------
+ *
+ * setup the tree on the left
+ *
+ * -------------------------------------------------
+ */
+ // utility function called by each top level tree node when it needs to populate its child nodes
+ var updateLeaves = function (leaves, parentKey, parentFolder, worker) {
+ var scrollTree = $('.qdr-overview.pane.left .pane-viewport')
+ var scrollTop = scrollTree.scrollTop();
+ var tree;
+ try {
+ tree = $("#overtree").dynatree("getTree")
+ } catch (e) {
+ // tree is not initialized yet
+ tree = {}
+ }
+ var parentNode = tree.count ? tree.getNodeByKey(parentKey) : null;
+ // if we were called after the tree is created, replace the existing nodes
+ var activeNode;
+ if (parentNode) {
+ activeNode = tree.getActiveNode();
+ parentNode.removeChildren();
+ }
+ leaves.forEach( function (leaf) {
+ var childFolder = worker(leaf)
+ if (parentNode)
+ parentNode.addChild(childFolder)
+ else
+ parentFolder.children.push(childFolder)
+ })
+ scrollTree.scrollTop(scrollTop)
+ if (activeNode) {
+ var newNode = tree.getNodeByKey(activeNode.data.key)
+ newNode.activateSilently()
+ }
}
- $scope.template = $scope.templates[0];
+ // get saved tree state
+ var lastKey = loadActivatedNode();
+ var expandedNodeList = loadExpandedNodeList();
+
+ // create a routers tree branch
var routers = new Folder("Routers")
routers.type = "Routers"
- //routers.info = allRouterInfo
- routers.focus = true
- routers.expanded = true
+ routers.info = allRouterInfo
+ routers.activate = lastKey === 'Routers'
+ routers.expand = (expandedNodeList.indexOf("Routers") > -1)
+ routers.clickFolderMode = 1
routers.key = "Routers"
- $scope.overview.children.push(routers)
- nodeIds.forEach( function (node) {
- var name = QDRService.nameFromId(node)
- var router = new Leaf(name)
- router.type = "Router"
- //router.info = routerInfo
- router.nodeId = node
- router.key = node
- routers.children.push(router)
- })
+ routers.parent = "Routers"
+ routers.addClass = "routers"
+ topLevelChildren.push(routers)
+ // called when the list of routers changes
+ var updateRouterTree = function (nodes) {
+ var worker = function (node) {
+ var name = QDRService.nameFromId(node)
+ var router = new Folder(name)
+ router.type = "Router"
+ router.info = routerInfo
+ router.nodeId = node
+ router.key = node
+ router.addClass = "router"
+ router.parent = "Routers"
+ router.activate = lastKey === node
+ return router;
+ }
+ updateLeaves(nodes, "Routers", routers, worker)
+ }
+ updateRouterTree(QDRService.nodeIdList());
- var expected = nodeIds.length;
+ // create an addresses tree branch
var addresses = new Folder("Addresses")
addresses.type = "Addresses"
- //addresses.info = allAddressInfo
+ addresses.info = allAddressInfo
+ addresses.activate = lastKey === 'Addresses'
+ addresses.expand = (expandedNodeList.indexOf("Addresses") > -1)
+ addresses.clickFolderMode = 1
addresses.key = "Addresses"
- $scope.overview.children.push(addresses)
-
- var gotAddressFields = function (addressFields) {
- addressFields.sort ( function (a,b) { return a.address < b.address ? -1 : a.address > b.address ? 1 : 0})
- addressFields[0].title = addressFields[0].address
- for (var i=1; i<addressFields.length; ++i) {
- if (addressFields[i].address === addressFields[i-1].address) {
- addressFields[i-1].title = addressFields[i-1].address + " (" + addressFields[i-1]['class'] + ")"
- addressFields[i].title = addressFields[i].address + " (" + addressFields[i]['class'] + ")"
- } else
- addressFields[i].title = addressFields[i].address
- }
- addressFields.forEach( function (address) {
- var a = new Leaf(address.title)
- //a.info = addressInfo
+ addresses.parent = "Addresses"
+ addresses.addClass = "addresses"
+ topLevelChildren.push(addresses)
+ var updateAddressTree = function (addressFields) {
+ var worker = function (address) {
+ var a = new Folder(address.title)
+ a.info = addressInfo
a.key = address.uid
a.fields = address
a.type = "Address"
- addresses.children.push(a)
- } )
+ a.addClass = "address"
+ a.activate = lastKey === address.uid
+ a.parent = "Addresses"
+ return a;
+ }
+ updateLeaves(addressFields, "Addresses", addresses, worker)
}
- getAllAddressFields(gotAddressFields)
+ allAddressInfo();
+ $scope.setLinkFilter = function (cur) {
+ // filter out non-matching links from the tree and the grid
+ getAllLinkFields([updateLinkGrid, updateLinkTree])
+ }
+ $scope.filterClose = function () {
+ var filter = $('#linkFilter')
+ filter.hide();
+ }
+ $scope.currentLinkFilter = "endpoint"
+ var filterHtml = "<button type='button' class='btn btn-secondary btn-filter'><span class='filter-icon'><i class='icon-filter'> Filter</span></button>";
+ var links = new Folder("Links " + filterHtml)
+ links.type = "Links"
+ links.info = allLinkInfo
+ links.activate = lastKey === 'Links'
+ links.expand = (expandedNodeList.indexOf("Links") > -1)
+ links.clickFolderMode = 1
+ links.key = "Links"
+ links.parent = "Links"
+ links.addClass = "links"
+ topLevelChildren.push(links)
+
+ // called both before the tree is created and whenever a background update is done
+ var updateLinkTree = function (linkFields) {
+ var worker = function (link) {
+ var l = new Folder(link.title)
+ l.info = linkInfo
+ l.key = link.uid
+ l.fields = link
+ l.type = "Link"
+ l.parent = "Links"
+ l.activate = lastKey === link.uid
+ l.addClass = "link"
+ return l;
+ }
+ linkFields.sort ( function (a,b) { return a.link < b.link ? -1 : a.link > b.link ? 1 : 0})
+ updateLeaves(linkFields, "Links", links, worker)
+ }
+ allLinkInfo();
- var connreceived = 0;
- var connectionsObj = {}
var connections = new Folder("Connections")
connections.type = "Connections"
- //connections.info = allConnectionInfo
+ connections.info = allConnectionInfo
+ connections.activate = lastKey === 'Connections'
+ connections.expand = (expandedNodeList.indexOf("Connections") > -1)
+ connections.clickFolderMode = 1
connections.key = "Connections"
- $scope.overview.children.push(connections)
- nodeIds.forEach( function (nodeId) {
+ connections.parent = "Connections"
+ connections.addClass = "connections"
+ topLevelChildren.push(connections)
- QDRService.getNodeInfo(nodeId, ".connection", [], function (nodeName, entity, response) {
- response.results.forEach( function (result) {
+ updateConnectionTree = function (nodes) {
+ var connectionsObj = {}
+ var expected = nodes.length;
+ var connreceived = 0;
+ nodes.forEach( function (nodeId) {
+ QDRService.getNodeInfo(nodeId, ".connection", [], function (nodeName, entity, response) {
+ response.results.forEach( function (result) {
- var auth = "no_auth"
- var sasl = QDRService.valFor(response.attributeNames, result, "sasl")
- if (QDRService.valFor(response.attributeNames, result, "isAuthenticated")) {
- auth = sasl
- if (sasl === "ANONYMOUS")
- auth = "anonymous-user"
- else {
+ var auth = "no_auth"
+ var sasl = QDRService.valFor(response.attributeNames, result, "sasl")
+ if (QDRService.valFor(response.attributeNames, result, "isAuthenticated")) {
+ auth = sasl
+ if (sasl === "ANONYMOUS")
+ auth = "anonymous-user"
+ else {
+ if (sasl === "GSSAPI")
+ sasl = "Kerberos"
+ if (sasl === "EXTERNAL")
+ sasl = "x.509"
+ auth = QDRService.valFor(response.attributeNames, result, "user") + "(" +
+ QDRService.valFor(response.attributeNames, result, "sslCipher") + ")"
+ }
+ }
+
+ var sec = "no-security"
+ if (QDRService.valFor(response.attributeNames, result, "isEncrypted")) {
if (sasl === "GSSAPI")
- sasl = "Kerberos"
- if (sasl === "EXTERNAL")
- sasl = "x.509"
- auth = QDRService.valFor(response.attributeNames, result, "user") + "(" +
- QDRService.valFor(response.attributeNames, result, "sslCipher") + ")"
- }
- }
+ sec = "Kerberos"
+ else
+ sec = QDRService.valFor(response.attributeNames, result, "sslProto") + "(" +
+ QDRService.valFor(response.attributeNames, result, "sslCipher") + ")"
+ }
- var sec = "no-security"
- if (QDRService.valFor(response.attributeNames, result, "isEncrypted")) {
- if (sasl === "GSSAPI")
- sec = "Kerberos"
- else
- sec = QDRService.valFor(response.attributeNames, result, "sslProto") + "(" +
- QDRService.valFor(response.attributeNames, result, "sslCipher") + ")"
- }
+ var host = QDRService.valFor(response.attributeNames, result, "host")
+ connectionsObj[host] = {}
+ response.attributeNames.forEach( function (attribute, i) {
+ connectionsObj[host][attribute] = result[i]
+ })
+ connectionsObj[host].security = sec
+ connectionsObj[host].authentication = auth
+ connectionsObj[host].routerId = nodeName
- var host = QDRService.valFor(response.attributeNames, result, "host")
- connectionsObj[host] = {}
- response.attributeNames.forEach( function (attribute, i) {
- connectionsObj[host][attribute] = result[i]
})
- connectionsObj[host].security = sec
- connectionsObj[host].authentication = auth
+ ++connreceived;
+ if (connreceived == expected) {
+ var worker = function (connection) {
+ var c = new Folder(connection)
+ c.type = "Connection"
+ c.info = connectionInfo
+ c.key = connection
+ c.fields = connectionsObj[connection]
+ c.tooltip = connectionsObj[connection].role === "inter-router" ? "inter-router connection" : "external connection"
+ c.addClass = c.tooltip
+ c.parent = "Connections"
+ c.activate = lastKey === connection
+ return c
+ }
+ var allConnections = Object.keys(connectionsObj).sort()
+ updateLeaves(allConnections, "Connections", connections, worker)
+ }
})
- ++connreceived;
- if (connreceived == expected) {
- var allConnections = Object.keys(connectionsObj).sort()
- allConnections.forEach(function (connection) {
- var c = new Leaf(connection)
- c.type = "Connection"
- c.icon = "ui-icon "
- c.icon += connectionsObj[connection].role === "inter-router" ? "ui-icon-refresh" : "ui-icon-transfer-e-w"
- //c.info = connectionInfo
- c.key = connection
- c.fields = connectionsObj[connection]
- c.tooltip = connectionsObj[connection].role === "inter-router" ? "inter-router connection" : "external connection"
- connections.children.push(c)
- })
- }
})
- })
+ }
+ updateConnectionTree(QDRService.nodeIdList())
var logsreceived = 0;
var logObj = {}
var logs = new Folder("Logs")
logs.type = "Logs"
- //logs.info = allLogInfo
+ logs.info = allLogInfo
+ logs.activate = lastKey === 'Logs'
+ logs.expand = (expandedNodeList.indexOf("Logs") > -1)
+ logs.clickFolderMode = 1
logs.key = "Logs"
- //$scope.overview.children.push(logs)
+ logs.parent = "Logs"
+ //topLevelChildren.push(logs)
+ var nodeIds = QDRService.nodeIdList()
+ var expected = nodeIds.length;
nodeIds.forEach( function (nodeId) {
QDRService.getNodeInfo(nodeId, ".log", ["name"], function (nodeName, entity, response) {
response.results.forEach( function (result) {
@@ -654,39 +1363,73 @@ var QDR = (function (QDR) {
if (logsreceived == expected) {
var allLogs = Object.keys(logObj).sort()
allLogs.forEach(function (log) {
- var l = new Leaf(log)
+ var l = new Folder(log)
l.type = "Log"
- //l.info = logInfo
+ l.info = logInfo
l.key = log
+ l.parent = "Logs"
+ l.activate = lastKey === log
logs.children.push(l)
})
- //console.log("---------------")
- //console.dump($scope.overview.children)
- //console.log("---------------")
- $("#overtree").fancytree({
- activate: activated,
- clickFolderMode: 1,
- source: $scope.overview.children
- })
- allRouterInfo();
+ $('#overtree').dynatree({
+ onActivate: activated,
+ onExpand: saveExpanded,
+ onClick: function (n, e) {
+ if (e.target.className.indexOf('-filter') > -1) {
+ //QDR.log.debug("overtree on click called")
+ e.preventDefault();
+ e.stopPropagation()
+ var filter = $('#linkFilter')
+ var treeLink = $('span.links')
+ filter.css({
+ top: treeLink.offset().top + treeLink.height(),
+ left: treeLink.offset().left,
+ zIndex:5000
+ });
+ filter.toggle()
+ $("#overtree").dynatree("getTree").getNodeByKey('Links').activate()
+ return false;
+ }
+ },
+ selectMode: 1,
+ debugLevel: 0,
+ activeVisible: false,
+ children: topLevelChildren
+ })
+ treeRoot = $("#overtree").dynatree("getRoot");
+
+ // simulate a click on the previous active node
+ var active = $("#overtree").dynatree("getActiveNode");
+ if (!active) {
+ active = $("#overtree").dynatree("getTree").getNodeByKey("Routers")
+ }
+ activated(active);
+
+ // populate the data for each expanded node
+ updateExpanded();
+ QDRService.addUpdatedAction( "overview", function () {
+ $timeout(updateExpanded);
+ })
+ // update the node list
+ QDRService.startUpdating()
+
+ loadColState($scope.allRouters);
+ loadColState($scope.routerGrid);
+ loadColState($scope.addressesGrid);
+ loadColState($scope.addressGrid);
+ loadColState($scope.linksGrid);
+ loadColState($scope.linkGrid);
+ loadColState($scope.allConnectionGrid);
+ loadColState($scope.connectionGrid);
+
}
})
})
$scope.$on("$destroy", function( event ) {
- if (currentTimer) {
- clearTimeout(currentTimer)
- currentTimer = null;
- }
+ QDRService.stopUpdating()
+ QDRService.delUpdatedAction("overview")
});
- var treeTypeMap = {
- Routers: allRouterInfo,
- Router: routerInfo,
- Addresses: allAddressInfo,
- Address: addressInfo,
- Connections: allConnectionInfo,
- Connection: connectionInfo
- }
}]);
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/js/qdrPlugin.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrPlugin.js b/console/stand-alone/plugin/js/qdrPlugin.js
deleted file mode 100644
index c287342..0000000
--- a/console/stand-alone/plugin/js/qdrPlugin.js
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
-*/
-/**
- * @module QDR
- * @main QDR
- *
- * The main entrypoint for the QDR module
- *
- */
-var QDR = (function(QDR) {
-
- /**
- * @property pluginName
- * @type {string}
- *
- * The name of this plugin
- */
- QDR.pluginName = "QDR";
-
- /**
- * @property log
- * @type {Logging.Logger}
- *
- * This plugin's logger instance
- */
- //HIO QDR.log = Logger.get(QDR.pluginName);
- /**
- * @property templatePath
- * @type {string}
- *
- * The top level path to this plugin's partials
- */
- QDR.srcBase = "plugin/";
- QDR.templatePath = QDR.srcBase + "html/";
- QDR.cssPath = QDR.srcBase + "css/";
-
- /**
- * @property SETTINGS_KEY
- * @type {string}
- *
- * The key used to fetch our settings from local storage
- */
- QDR.SETTINGS_KEY = 'QDRSettings';
- QDR.LAST_LOCATION = "QDRLastLocation";
-
- /**
- * @property module
- * @type {object}
- *
- * This plugin's angularjs module instance
- */
- QDR.module = angular.module(QDR.pluginName, ['ngAnimate', 'ngResource', 'ngRoute', 'ui.grid', 'ui.grid.selection',
- 'ui.grid.autoResize', 'jsonFormatter', 'ui.bootstrap', 'ui.slider'/*, 'minicolors' */]);
-
- // set up the routing for this plugin
- QDR.module.config(function($routeProvider) {
- $routeProvider
- .when('/', {
- templateUrl: QDR.templatePath + 'qdrConnect.html'
- })
- .when('/overview', {
- templateUrl: QDR.templatePath + 'qdrOverview.html'
- })
- .when('/topology', {
- templateUrl: QDR.templatePath + 'qdrTopology.html'
- })
- .when('/list', {
- templateUrl: QDR.templatePath + 'qdrList.html'
- })
- .when('/schema', {
- templateUrl: QDR.templatePath + 'qdrSchema.html'
- })
- .when('/charts', {
- templateUrl: QDR.templatePath + 'qdrCharts.html'
- })
- .when('/connect', {
- templateUrl: QDR.templatePath + 'qdrConnect.html'
- })
- });
-
- QDR.module.config(['$compileProvider', function ($compileProvider) {
- var cur = $compileProvider.aHrefSanitizationWhitelist();
- $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|blob):/);
- cur = $compileProvider.aHrefSanitizationWhitelist();
- }]);
-
- QDR.module.config(function (JSONFormatterConfigProvider) {
- // Enable the hover preview feature
- JSONFormatterConfigProvider.hoverPreviewEnabled = true;
- });
-
- QDR.module.filter('to_trusted', ['$sce', function($sce){
- return function(text) {
- return $sce.trustAsHtml(text);
- };
- }]);
-
- QDR.module.filter('humanify', function (QDRService) {
- return function (input) {
- return QDRService.humanify(input);
- };
- });
-
- QDR.logger = function ($log) {
- var log = $log;
-
- this.debug = function (msg) { msg = "QDR: " + msg; log.debug(msg)};
- this.error = function (msg) {msg = "QDR: " + msg; log.error(msg)}
- this.info = function (msg) {msg = "QDR: " + msg; log.info(msg)}
- this.warn = function (msg) {msg = "QDR: " + msg; log.warn(msg)}
-
- return this;
- }
- // one-time initialization happens in the run function
- // of our module
- QDR.module.run( ["$rootScope", "$location", "$log", "QDRService", "QDRChartService", function ($rootScope, $location, $log, QDRService, QDRChartService) {
- QDR.log = new QDR.logger($log);
- QDR.log.debug("QDR.module.run()")
-
- QDRService.initProton();
- var settings = angular.fromJson(localStorage[QDR.SETTINGS_KEY]);
- var lastLocation = localStorage[QDR.LAST_LOCATION];
- if (!angular.isDefined(lastLocation))
- lastLocation = "/overview";
-
- QDRService.addConnectAction(function() {
- QDRChartService.init(); // initialize charting service after we are connected
- });
- if (settings && settings.autostart) {
- QDRService.addConnectAction(function() {
- $location.path(lastLocation);
- $location.replace();
- $rootScope.$apply();
- });
- QDRService.connect(settings);
- } else {
- setTimeout(function () {
- $location.url('/connect')
- $location.replace();
- }, 100)
- }
-
- $rootScope.$on('$routeChangeSuccess', function() {
- localStorage[QDR.LAST_LOCATION] = $location.$$path;
- });
-
-
- }]);
-
- QDR.module.controller ("QDR.MainController", ['$scope', '$location', function ($scope, $location) {
- QDR.log.debug("started QDR.MainController with location.url: " + $location.url());
- QDR.log.debug("started QDR.MainController with window.location.pathname : " + window.location.pathname);
- $scope.topLevelTabs = [];
- $scope.topLevelTabs.push({
- id: "qdr",
- content: "Qpid Dispatch Router Console",
- title: "Dispatch Router Console",
- isValid: function() { return true; },
- href: function() { return "#connect"; },
- isActive: function() { return true; }
- });
- }])
-
- QDR.module.controller ("QDR.Core", function ($scope, $rootScope) {
- $scope.alerts = [];
- $scope.closeAlert = function(index) {
- $scope.alerts.splice(index, 1);
- };
- $scope.$on('newAlert', function(event, data) {
- $scope.alerts.push(data);
- $scope.$apply();
- });
- $scope.$on("clearAlerts", function () {
- $scope.alerts = [];
- $scope.$apply();
- })
-
- })
-
- return QDR;
-}(QDR || {}));
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/js/qdrSchema.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrSchema.js b/console/stand-alone/plugin/js/qdrSchema.js
index 0e94351..656b159 100644
--- a/console/stand-alone/plugin/js/qdrSchema.js
+++ b/console/stand-alone/plugin/js/qdrSchema.js
@@ -21,9 +21,50 @@ under the License.
*/
var QDR = (function (QDR) {
- QDR.module.controller("QDR.SchemaController", ['$scope', 'QDRService', function($scope, QDRService) {
+ QDR.module.controller("QDR.SchemaController", ['$scope', '$location', 'QDRService', function($scope, $location, QDRService) {
+ if (!QDRService.connected) {
+ QDRService.redirectWhenConnected("schema")
+ return;
+ }
+ // we are currently connected. setup a handler to get notified if we are ever disconnected
+ QDRService.addDisconnectAction( function () {
+ QDRService.redirectWhenConnected("schema")
+ $scope.$apply();
+ })
+
+ var keys2kids = function (tree, obj) {
+
+ if (obj === Object(obj)) {
+ tree.children = []
+ for (var key in obj) {
+ var kid = {title: key}
+ if (obj[key] === Object(obj[key])) {
+ kid.isFolder = true
+ keys2kids(kid, obj[key])
+ } else {
+ kid.title += (': ' + JSON.stringify(obj[key],null,2))
+ }
+ tree.children.push(kid)
+ }
+ }
+ }
+
+ var tree = []
+ for (var key in QDRService.schema) {
+ var kid = {title: key}
+ var val = QDRService.schema[key]
+ if (val === Object(val))
+ keys2kids(kid, val)
+ else
+ kid.title += (': ' + JSON.stringify(val,null,2))
+
+ tree.push(kid);
+ }
+ $('#schema').dynatree({
+ minExpandLevel: 2,
+ children: tree
+ })
- $scope.schema = QDRService.schema;
}]);
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/js/qdrService.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrService.js b/console/stand-alone/plugin/js/qdrService.js
index 758e518..55c6581 100644
--- a/console/stand-alone/plugin/js/qdrService.js
+++ b/console/stand-alone/plugin/js/qdrService.js
@@ -23,7 +23,7 @@ var QDR = (function(QDR) {
// The QDR service handles the connection to
// the server in the background
- QDR.module.factory("QDRService", ['$rootScope', '$http', '$resource', '$location', function($rootScope, $http, $resource, $location) {
+ QDR.module.factory("QDRService", ['$rootScope', '$http', '$timeout', '$resource', '$location', function($rootScope, $http, $timeout, $resource, $location) {
var self = {
rhea: require("rhea"),
@@ -57,21 +57,50 @@ var QDR = (function(QDR) {
executeConnectActions: function() {
self.connectActions.forEach(function(action) {
//QDR.log.debug("executing connect action " + action);
- action.apply();
+ try {
+ action.apply();
+ } catch (e) {
+ // in case the page that registered the handler has been unloaded
+ }
});
self.connectActions = [];
+ if ($location.path().startsWith(QDR.pluginRoot)) {
+ $timeout( function () {
+
+ var searchObject = $location.search();
+ var goto = "overview";
+ if (searchObject.org && searchObject.org !== "connect") {
+ goto = searchObject.org;
+ }
+ $location.search('org', null)
+ $location.path(QDR.pluginRoot +"/" + goto);
+ })
+ }
+
},
executeDisconnectActions: function() {
self.disconnectActions.forEach(function(action) {
- action.apply();
+ try {
+ action.apply();
+ } catch (e) {
+ // in case the page that registered the handler has been unloaded
+ }
});
self.disconnectActions = [];
},
executeUpdatedActions: function() {
for (action in self.updatedActions) {
- self.updatedActions[action].apply();
+ try {
+ self.updatedActions[action].apply();
+ } catch (e) {
+ delete self.updatedActions[action]
+ }
}
},
+ redirectWhenConnected: function (org) {
+ $location.path("/" + QDR.pluginName + "/connect")
+ $location.search('org', org);
+ },
notifyTopologyDone: function() {
//QDR.log.debug("got Toplogy done notice");
@@ -150,12 +179,11 @@ var QDR = (function(QDR) {
onSubscription: function() {
self.getSchema();
- self.topology.get();
},
startUpdating: function () {
- QDR.log.info("startUpdating called")
self.stopUpdating();
+ QDR.log.info("startUpdating called")
self.topology.get();
self.stop = setInterval(function() {
self.topology.get();
@@ -191,6 +219,8 @@ var QDR = (function(QDR) {
},
humanify: function (s) {
+ if (!s || s.length === 0)
+ return s;
var t = s.charAt(0).toUpperCase() + s.substr(1).replace(/[A-Z]/g, ' $&');
return t.replace(".", " ");
},
@@ -255,6 +285,44 @@ var QDR = (function(QDR) {
return d.nodeType ==='on-demand' && (d.properties && d.properties.product === 'qpid-cpp');
},
+ isAConsole: function (properties, connectionId, nodeType, key) {
+ return self.isConsole({properties: properties, connectionId: connectionId, nodeType: nodeType, key: key})
+ },
+ isConsole: function (d) {
+ // TODO: use connection properties when available
+ if (d.properties.console_identifier == 'Dispatch console')
+ return true;
+ // until connection properties can difinitively identify consoles:
+ var connid = d.connectionId;
+ if (connid && d.nodeType === 'normal') {
+ // find all the endpoint links for this router that have this connid
+ var linkInfo = self.topology.nodeInfo()[d.key]['.router.link']
+ var outs = 0, ins = 0;
+ var outaddr, inaddr;
+ linkInfo.results.forEach( function (link) {
+ if (self.valFor(linkInfo.attributeNames, link, 'connectionId') == connid &&
+ self.valFor(linkInfo.attributeNames, link, 'linkType') == 'endpoint') {
+ if (self.valFor(linkInfo.attributeNames, link, 'linkDir') == 'in') {
+ ++ins;
+ inaddr = self.valFor(linkInfo.attributeNames, link, 'owningAddr')
+ }
+ if (self.valFor(linkInfo.attributeNames, link, 'linkDir') == 'out') {
+ ++outs;
+ outaddr = self.valFor(linkInfo.attributeNames, link, 'owningAddr')
+ }
+ return true;
+ }
+ })
+ // consoles have 1 out link with an address that starts with Ltemp. and
+ // 1 in link with no address
+ if (outs == 1 && ins == 1 &&
+ inaddr == null && outaddr.startsWith('Ltemp.')) {
+ return true;
+ }
+ }
+ return false;
+ },
+
/*
* send the management messages that build up the topology
*
@@ -329,9 +397,9 @@ var QDR = (function(QDR) {
// results contains more nodes than actually respond within
// the timeout. However, if the responses we get don't contain
// the missing node, assume we are done.
- QDR.log.debug("timed out waiting for management responses");
+ QDR.log.info("timed out waiting for management responses");
// note: can't use 'this' in a timeout handler
- self.topology.dump("state at timeout");
+ self.topology.miniDump("state at timeout");
// check if _nodeInfo is consistent
if (self.topology.isConsistent()) {
//TODO: notify controllers which node was dropped
@@ -402,60 +470,31 @@ var QDR = (function(QDR) {
if (this._expected[id].indexOf(key) == -1)
this._expected[id].push(key);
},
-/*
-The response looks like:
-{
- ".router": {
- "results": [
- [4, "router/QDR.X", 1, "0", 3, 60, 60, 11, "QDR.X", 30, "interior", "org.apache.qpid.dispatch.router", 5, 12, "router/QDR.X"]
- ],
- "attributeNames": ["raIntervalFlux", "name", "helloInterval", "area", "helloMaxAge", "mobileAddrMaxAge", "remoteLsMaxAge", "addrCount", "routerId", "raInterval", "mode", "type", "nodeCount", "linkCount", "identity"]
- },
- ".connection": {
- "results": [
- ["QDR.B", "connection/0.0.0.0:20002", "operational", "0.0.0.0:20002", "inter-router", "connection/0.0.0.0:20002", "ANONYMOUS", "org.apache.qpid.dispatch.connection", "out"],
- ["QDR.A", "connection/0.0.0.0:20001", "operational", "0.0.0.0:20001", "inter-router", "connection/0.0.0.0:20001", "ANONYMOUS", "org.apache.qpid.dispatch.connection", "out"],
- ["b2de2f8c-ef4a-4415-9a23-000c2f86e85d", "connection/localhost:33669", "operational", "localhost:33669", "normal", "connection/localhost:33669", "ANONYMOUS", "org.apache.qpid.dispatch.connection", "in"]
- ],
- "attributeNames": ["container", "name", "state", "host", "role", "identity", "sasl", "type", "dir"]
- },
- ".router.node": {
- "results": [
- ["QDR.A", null],
- ["QDR.B", null],
- ["QDR.C", "QDR.A"],
- ["QDR.D", "QDR.A"],
- ["QDR.Y", "QDR.A"]
- ],
- "attributeNames": ["routerId", "nextHop"]
- }
-}*/
ondone: function () {
clearTimeout(this.timerHandle);
this._gettingTopo = false;
//this.miniDump();
//this.dump();
self.notifyTopologyDone();
-
},
dump: function (prefix) {
if (prefix)
- QDR.log.debug(prefix);
- QDR.log.debug("---");
+ QDR.log.info(prefix);
+ QDR.log.info("---");
for (var key in this._nodeInfo) {
- QDR.log.debug(key);
+ QDR.log.info(key);
console.dump(this._nodeInfo[key]);
- QDR.log.debug("---");
+ QDR.log.info("---");
}
QDR.log.debug("was still expecting:");
console.dump(this._expected);
},
miniDump: function (prefix) {
if (prefix)
- QDR.log.debug(prefix);
- QDR.log.debug("---");
+ QDR.log.info(prefix);
+ QDR.log.info("---");
console.dump(Object.keys(this._nodeInfo));
- QDR.log.debug("---");
+ QDR.log.info("---");
},
onerror: function (err) {
this._gettingTopo = false;
@@ -523,16 +562,10 @@ The response looks like:
//QDR.log.debug("got all results for " + entity);
// aggregate the responses
var newResponse = {};
- newResponse['aggregates'] = [];
var thisNode = responses[selectedNodeId];
- if (!thisNode) {
- newResponse['attributeNames'] = ['name'];
- newResponse['results'] = [''];
- callback(nodeNames, entity, newResponse);
- return;
- }
newResponse['attributeNames'] = thisNode.attributeNames;
newResponse['results'] = thisNode.results;
+ newResponse['aggregates'] = [];
for (var i=0; i<thisNode.results.length; ++i) {
var result = thisNode.results[i];
var vals = [];
@@ -557,8 +590,8 @@ The response looks like:
if (ent.attributes[key] && ent.attributes[key].graph) {
if (id != selectedNodeId)
aggregate[i].sum += result[i];
- aggregate[i].detail.push({node: self.nameFromId(id)+':', val: result[i]})
}
+ aggregate[i].detail.push({node: self.nameFromId(id)+':', val: result[i]})
})
return true; // stop looping
}
@@ -569,7 +602,7 @@ The response looks like:
// because it was not in the selectedNodeId's results
var vals = [];
result.forEach( function (val) {
- vals.push({sum: val, detail: []})
+ vals.push({sum: val, detail: [{node: self.nameFromId(id), val: val}]})
})
newResponse.aggregates.push(vals)
}
@@ -586,10 +619,24 @@ The response looks like:
ret = self.sendMgmtQuery('GET-SCHEMA')
).then(ret.id, function(response) {
//QDR.log.debug("Got schema response");
+ // remove deprecated
+ for (var entityName in response.entityTypes) {
+ var entity = response.entityTypes[entityName]
+ if (entity.deprecated) {
+ // deprecated entity
+ delete response.entityTypes[entityName]
+ } else {
+ for (var attributeName in entity.attributes) {
+ var attribute = entity.attributes[attributeName]
+ if (attribute.deprecated) {
+ // deprecated attribute
+ delete response.entityTypes[entityName].attributes[attributeName]
+ }
+ }
+ }
+ }
self.schema = response;
- //self.schema = angular.copy(response);
- //self.topology.cleanUp(response);
- self.notifyTopologyDone();
+ self.topology.get();
}, ret.error);
},
@@ -636,8 +683,13 @@ The response looks like:
var application_properties = {
operation: operation
}
- if (attrs.type)
- application_properties.type = attrs.type;
+ var ent = self.schema.entityTypes[entity];
+ var fullyQualifiedType = ent.fullyQualifiedType;
+ if (fullyQualifiedType) {
+ application_properties.type = fullyQualifiedType
+ }
+ else
+ application_properties.type = entity;
if (attrs.name)
application_properties.name = attrs.name;
var msg = {
@@ -676,8 +728,11 @@ The response looks like:
}
if (entity[0] === '.')
entity = entity.substr(1, entity.length-1)
- //return self._send(body, fullAddr, operation, entity);
- return self._send(body, fullAddr, operation, "org.apache.qpid.dispatch." + entity);
+ var prefix = "org.apache.qpid.dispatch."
+ var configs = ["address", "autoLink", "linkRoute"]
+ if (configs.indexOf(entity) > -1)
+ prefix += "router.config."
+ return self._send(body, fullAddr, operation, prefix + entity);
},
sendMgmtQuery: function (operation) {
@@ -742,8 +797,8 @@ The response looks like:
self.sender = null;
self.receiver = null;
self.sendable = false;
+ self.gotTopology = false;
}
-
var maybeStart = function () {
if (okay.connection && okay.sender && okay.receiver && self.sendable && !self.connected) {
QDR.log.info("okay to start")
@@ -757,55 +812,65 @@ The response looks like:
}
var onDisconnect = function () {
//QDR.log.warn("Disconnected");
+ self.connectionError = true;
stop();
self.executeDisconnectActions();
}
QDR.log.debug("****** calling rhea.connect ********")
- var connection = self.rhea.connect({
+ var connection;
+ try {
+ connection = self.rhea.connect({
connection_details:ws('ws://' + baseAddress, ["binary", "AMQWSB10"]),
reconnect:true,
properties: {console_identifier: 'Dispatch console'}
- });
- connection.on('connection_open', function (context) {
- QDR.log.debug("connection_opened")
- okay.connection = true;
- okay.receiver = false;
- okay.sender = false;
- })
- connection.on('disconnected', function (context) {
- onDisconnect();
- self.errorText = "Error: Connection failed"
- self.executeDisconnectActions();
- self.connectionError = true;
- })
- connection.on('connection_close', function (context) {
+ });
+ }
+ catch (e) {
+ QDR.log.debug("exception caught on connect")
+ self.errorText = "Connection failed"
onDisconnect();
- self.errorText = "Disconnected"
- })
-
- var sender = connection.open_sender();
- sender.on('sender_open', function (context) {
- QDR.log.debug("sender_opened")
- okay.sender = true
- maybeStart()
- })
- sender.on('sendable', function (context) {
- //QDR.log.debug("sendable")
- self.sendable = true;
- maybeStart();
- })
+ }
+ if (!self.connectionError) {
+ connection.on('connection_open', function (context) {
+ QDR.log.debug("connection_opened")
+ okay.connection = true;
+ okay.receiver = false;
+ okay.sender = false;
+ })
+ connection.on('disconnected', function (context) {
+ QDR.log.debug("connection disconnected")
+ self.errorText = "Unable to connect"
+ onDisconnect();
+ })
+ connection.on('connection_close', function (context) {
+ QDR.log.debug("connection closed")
+ self.errorText = "Disconnected"
+ onDisconnect();
+ })
- var receiver = connection.open_receiver({source: {dynamic: true}});
- receiver.on('receiver_open', function (context) {
- QDR.log.debug("receiver_opened")
- okay.receiver = true;
- maybeStart()
- })
- receiver.on("message", function (context) {
- self.correlator.resolve(context);
- });
+ var sender = connection.open_sender();
+ sender.on('sender_open', function (context) {
+ QDR.log.debug("sender_opened")
+ okay.sender = true
+ maybeStart()
+ })
+ sender.on('sendable', function (context) {
+ //QDR.log.debug("sendable")
+ self.sendable = true;
+ maybeStart();
+ })
+ var receiver = connection.open_receiver({source: {dynamic: true}});
+ receiver.on('receiver_open', function (context) {
+ QDR.log.debug("receiver_opened")
+ okay.receiver = true;
+ maybeStart()
+ })
+ receiver.on("message", function (context) {
+ self.correlator.resolve(context);
+ });
+ }
}
}
}
@@ -818,8 +883,8 @@ The response looks like:
(function() {
console.dump = function(object) {
if (window.JSON && window.JSON.stringify)
- console.log(JSON.stringify(object,undefined,2));
+ QDR.log.info(JSON.stringify(object,undefined,2));
else
console.log(object);
};
-})();
\ No newline at end of file
+})();
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[06/11] qpid-dispatch git commit: DISPATCH-316 Hawtio and stand-alone
consoles now use common code
Posted by ea...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/index.html
----------------------------------------------------------------------
diff --git a/console/stand-alone/index.html b/console/stand-alone/index.html
index 166d89a..be03d62 100644
--- a/console/stand-alone/index.html
+++ b/console/stand-alone/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
@@ -17,7 +17,7 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
-<html>
+<html xmlns:ng="http://angularjs.org">
<head>
@@ -25,21 +25,18 @@ under the License.
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Qpid Dispatch Console</title>
+ <link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery.tipsy/1.0.2/jquery.tipsy.css" type="text/css"/>
-
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/3.0.7/ui-grid.css" type="text/css"/>
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ng-grid/2.0.11/ng-grid.min.css" type="text/css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery.fancytree/2.15.0/skin-win8/ui.fancytree.css" type="text/css">
-
- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">
-
+ <link rel="stylesheet" href="https://cdn.rawgit.com/mar10/dynatree/master/dist/skin/ui.dynatree.css" type="text/css">
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/twitter-bootstrap/2.2.1/css/bootstrap-combined.min.css" type="text/css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.min.css">
-
- <link rel="stylesheet" href="plugin/css/site-base.css" type="text/css"/>
<link rel="stylesheet" href="plugin/css/plugin.css" type="text/css"/>
- <link rel="stylesheet" href="plugin/css/qdrTopology.css" type="text/css"/>
+ <link rel="stylesheet" href="plugin/css/dispatch.css" type="text/css"/>
+ <link rel="stylesheet" href="plugin/css/site-base.css" type="text/css"/>
<link rel="stylesheet" href="https://cdn.rawgit.com/mohsen1/json-formatter/master/dist/json-formatter.min.css" type="text/css"/>
</head>
@@ -69,16 +66,7 @@ under the License.
<div id="main-body" >
<div id="main" class="container-fluid ng-cloak qdr">
- <div>
- <ul class="nav nav-tabs connected" ng-controller="QDR.NavBarController">
- <li ng-repeat="link in breadcrumbs" ng-show="isValid(link)" ng-class='{active : isActive(link.href), "pull-right" : isRight(link), haschart: hasChart(link)}'>
- <a ng-href="{{link.href}}{{hash}}" ng-bind-html="link.content | to_trusted"></a>
- </li>
- </ul>
- <div class="row-fluid">
- <div ng-view></div>
- </div>
- </div>
+ <div ng-include src="'plugin/html/qdrLayout.html'"></div>
</div>
</div>
</div>
@@ -87,27 +75,27 @@ under the License.
<script src="http://d3js.org/queue.v1.min.js"></script>
<script src="http://d3js.org/topojson.v0.min.js"></script>
- <script src="http://code.jquery.com/jquery-1.12.0.min.js"></script>
+ <script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
+
+ <script src="https://maxcdn.bootstrapcdn.com/twitter-bootstrap/2.2.1/js/bootstrap.min.js"></script>
- <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.5/angular.min.js"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.5/angular-sanitize.min.js"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.5/angular-resource.min.js"></script>
+
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.4.0/ui-bootstrap-tpls.min.js"></script>
- <script src="https://code.angularjs.org/1.4.8/angular.js"></script>
- <script src="https://code.angularjs.org/1.4.8/angular-resource.js"></script>
- <script src="https://code.angularjs.org/1.4.8/angular-route.js"></script>
- <script src="https://code.angularjs.org/1.4.8/angular-animate.js"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.1.0/ui-bootstrap-tpls.min.js"></script>
<script src="https://cdn.rawgit.com/jaz303/tipsy/master/src/javascripts/jquery.tipsy.js"></script>
<script src="https://cdn.rawgit.com/briancray/tooltipsy/master/tooltipsy.min.js"></script>
<script src="https://cdn.rawgit.com/angular-ui/ui-slider/master/src/slider.js"></script>
- <script src="https://cdn.rawgit.com/mohsen1/json-formatter/master/dist/json-formatter.min.js"></script>
-
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/3.0.7/ui-grid.js"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/ng-grid/2.0.11/ng-grid.min.js"></script>
- <script type="text/javascript" src="plugin/js/qdrPlugin.js"></script>
+ <script type="text/javascript" src="plugin/js/dispatchPlugin.js"></script>
<script type="text/javascript" src="plugin/js/qdrOverview.js"></script>
<script type="text/javascript" src="plugin/js/navbar.js"></script>
<script type="text/javascript" src="plugin/js/qdrList.js"></script>
+ <script type="text/javascript" src="plugin/js/qdrListChart.js"></script>
<script type="text/javascript" src="plugin/js/qdrCharts.js"></script>
<script type="text/javascript" src="plugin/js/qdrSchema.js"></script>
<script type="text/javascript" src="plugin/js/qdrService.js"></script>
@@ -117,7 +105,7 @@ under the License.
<script type="text/javascript" src="plugin/lib/rhea-min.js"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.fancytree/2.15.0/jquery.fancytree.js" type="text/javascript"></script>
+ <script src="https://cdn.rawgit.com/mar10/dynatree/master/dist/jquery.dynatree.min.js"></script>
<script type="text/javascript">
angular.element(document.getElementsByTagName('head')).append(angular.element('<base href="' + window.location.pathname + '" />'));
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/css/dispatch.css
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/css/dispatch.css b/console/stand-alone/plugin/css/dispatch.css
new file mode 100644
index 0000000..e59fa36
--- /dev/null
+++ b/console/stand-alone/plugin/css/dispatch.css
@@ -0,0 +1,640 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you 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.
+*/
+
+svg {
+ background-color: transparent;
+ cursor: default;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ -o-user-select: none;
+ user-select: none;
+}
+
+svg:not(.active):not(.ctrl) {
+ cursor: crosshair;
+}
+#end-arrow-selected, #start-arrow-selected {
+ stroke: #00F;
+ fill: #00F;
+}
+
+path.link {
+ fill: none;
+ stroke: #000;
+ stroke-width: 4px;
+ cursor: default;
+}
+
+svg:not(.active):not(.ctrl) path.link {
+ cursor: pointer;
+}
+
+path.link.selected {
+ stroke-dasharray: 10,2;
+ stroke: #00F !important;
+}
+
+
+path.link.highlighted {
+ stroke: #0F0 !important;
+
+}
+
+path.link.temp {
+ opacity: 0.3;
+}
+path.link.temp.over {
+ opacity: 0.8;
+ stroke-dasharray: 10,2;
+}
+
+path.link.dragline {
+ pointer-events: none;
+}
+
+path.link.hidden {
+ stroke-width: 0;
+}
+
+
+circle.node {
+ stroke-width: 1.5px;
+ cursor: pointer;
+ stroke: darkgray;
+ fill: lightgray;
+}
+
+circle.node.reflexive {
+ stroke: #F00 !important;
+ stroke-width: 2.5px;
+}
+circle.node.selected {
+ stroke: #F00 !important;
+ stroke-width: 2px;
+ fill: #e0e0ff !important;
+}
+circle.node.inter-router {
+ fill: #EAEAEA;
+}
+circle.node.normal {
+ fill: #F0F000;
+}
+circle.node.on-demand {
+ fill: #C0FFC0;
+}
+circle.node.on-demand.artemis {
+ fill: #FCC;
+ /*opacity: 0.2; */
+}
+
+circle.node.fixed {
+ stroke-dasharray: 10,2;
+}
+circle.node.temp {
+ stroke: #f80;
+ fill: #f0f0ff;
+}
+
+text {
+ font: 12px sans-serif;
+ pointer-events: none;
+ /*font-family: monospace;*/
+
+}
+
+.tooltipsy
+{
+ padding: 10px;
+/* max-width: 320px;*/
+ color: #303030;
+ background-color: #fcfcfe;
+ border: 1px solid #deca7e;
+ border-radius: 5px;
+}
+
+.tiptable {
+
+}
+.tiptable tr {
+ border-bottom: 1px solid #ccc;
+}
+
+.tiptable tr:last-child {
+ border-bottom: 0px;
+}
+
+.tiptable tr:nth-child(even) {
+ background: #fcfcfe;
+}
+.tiptable tr:nth-child(odd) {
+ background: #FFF
+}
+
+text.id {
+ text-anchor: middle;
+ font-weight: bold;
+}
+
+text.label {
+ text-anchor: start;
+ font-weight: bold;
+}
+
+.row-fluid.tertiary {
+ position: relative;
+ left: 20px;
+}
+
+.row-fluid.tertiary.left {
+ float: left;
+}
+
+.row-fluid.tertiary.panel {
+ width: 410px;
+ /*height: 100%; */
+}
+
+div#topologyForm .ngViewport, div#topologyForm .gridStyle {
+ height: inherit !important;
+ min-height: initial !important;
+ overflow: initial;
+}
+
+div#multiple_details, div#link_details {
+ height: 300px;
+ width: 600px;
+ display: none;
+ padding: 0.5em;
+ border: 1px solid;
+ position: absolute;
+ background-color: white;
+ max-height: 330px !important;
+ overflow: hidden;
+}
+div#multiple_details div.ngRow.selected {
+ background-color: #c9dde1 !important;
+}
+
+div.grid-values {
+ text-align: right;
+}
+
+div.grid-values.ngCellText span {
+ padding-right: 4px;
+}
+
+.panel-adjacent {
+ margin-left: 430px;
+}
+
+#topologyForm.selected {
+ border: 1px solid red;
+}
+#topologyForm {
+ border: 1px solid white;
+ padding: 2px;
+ /* position: relative; */
+ /* top: -8px; */
+}
+div.qdr-topology.pane.left .ngViewport {
+ /* border: 1px solid lightgray; */
+}
+
+#topologyForm > div {
+ width:396px;
+}
+
+/* globe */
+.land {
+ fill: #999;
+ stroke-opacity: 1;
+}
+
+.graticule {
+ fill: none;
+ stroke: black;
+ stroke-width:.5;
+ opacity:.1;
+}
+
+.labels {
+ font: 18px sans-serif;
+ fill: black;
+ opacity: .85;
+ text-anchor: middle;
+}
+
+.noclicks { pointer-events:none; }
+
+.point { opacity:.6; }
+
+.arcs {
+ opacity:.7;
+ stroke: darkgreen;
+ stroke-width: 3;
+}
+.flyers {
+ stroke-width:1;
+ opacity: 0;
+ stroke: darkred;
+}
+.arc, .flyer {
+ stroke-linejoin: round;
+ fill:none;
+}
+.arc { }
+.arc:hover {
+ stroke: darkred;
+}
+.flyer { }
+.flyer:hover {
+ stroke: darkgreen;
+}
+.arc.inter-router {
+ stroke: darkblue;
+}
+
+#addNodeForm {
+ padding: 1em;
+}
+
+
+li.currentStep {
+ font-weight: bold;
+}
+
+.qdrTopology div.panel {
+ position: absolute;
+}
+/*
+.ui-dialog-titlebar {
+ border: 0;
+ background: transparent;
+}
+*/
+
+/*
+.ui-tabs.ui-tabs-vertical {
+ padding: 0;
+ width: 48em;
+}
+.ui-tabs.ui-tabs-vertical .ui-widget-header {
+ border: none;
+}
+.ui-tabs.ui-tabs-vertical .ui-tabs-nav {
+ float: left;
+ width: 10em;
+ background: #CCC;
+ border-radius: 4px 0 0 4px;
+ border-right: 1px solid gray;
+}
+.ui-tabs.ui-tabs-vertical .ui-tabs-nav li {
+ clear: left;
+ width: 100%;
+ margin: 0.1em 0;
+ border: 1px solid gray;
+ border-width: 1px 0 1px 1px;
+ border-radius: 4px 0 0 4px;
+ overflow: hidden;
+ position: relative;
+ right: -2px;
+ z-index: 2;
+}
+.ui-tabs.ui-tabs-vertical .ui-tabs-nav li a {
+ display: block;
+ width: 100%;
+ padding: 0.1em 1em;
+}
+.ui-tabs.ui-tabs-vertical .ui-tabs-nav li a:hover {
+ cursor: pointer;
+}
+.ui-tabs.ui-tabs-vertical .ui-tabs-nav li.ui-tabs-active {
+ margin-bottom: 0.2em;
+ padding-bottom: 0;
+ border-right: 1px solid white;
+}
+.ui-tabs.ui-tabs-vertical .ui-tabs-nav li:last-child {
+ margin-bottom: 10px;
+}
+.ui-tabs.ui-tabs-vertical .ui-tabs-panel {
+ float: left;
+ width: 34em;
+ border-left: 1px solid gray;
+ border-radius: 0;
+ position: relative;
+ left: -1px;
+}
+
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected {
+ right: -3px !important;
+}
+
+.ui-tabs li i.ui-icon {
+ display: inline-block;
+}
+*/
+.ui-tabs .ui-tabs-panel {
+ /* padding-top: 0 !important; */
+}
+
+.ui-widget-content fieldset {
+ float: left;
+ padding: 0 1em 0 0;
+}
+
+.entity-description {
+ color: #960;
+ font-size: 90%;
+}
+
+.attr-description {
+ padding-top: 1.5em;
+ float: right;
+ width: 17em;
+}
+.attr-annotations {
+ padding-top: 2.5em;
+ clear: both;
+}
+.attr-annotations > span {
+ padding-top: 0.5em;
+ border-top: 1px dashed darkgray;
+ display: block;
+}
+
+.attr-type {
+ color: #990;
+ font-size: 85%;
+}
+.attr-required {
+ color: red;
+ font-size: 85%;
+}
+.attr-unique {
+ color: green;
+ font-size: 85%;
+}
+
+#tabs.nodeEntities {
+ border: 0;
+}
+
+#tabs ul.nodeTabs {
+ background: #fff;
+}
+
+#tabs #Container {
+ border-left: 1px solid #aaa;
+}
+
+#tabs.ui-tabs .ui-tabs-nav li {
+ border-bottom: 1px solid #aaa !important;
+}
+
+.entity-fields {
+ /* height: 400px; */
+ overflow-y: scroll;
+ overflow-x: hidden;
+}
+
+div.boolean label:first-child {
+ float: left;
+ margin-right: 1em;
+}
+div.boolean {
+ padding-bottom: 1em;
+}
+
+.entity-fields label {
+ font-weight: 600;
+ margin-top: 0.5em;
+ display: inline;
+}
+
+.aggregate {
+ text-align: right;
+}
+
+.aggregate i {
+ float: right;
+ margin: 3px 3px 3px 8px;
+}
+
+.aggregate .hastip {
+ padding: 5px;
+}
+
+.subTip .tipsy-inner {
+ background-color: white;
+ color: black;
+ font-size: 1.3em;
+ border: 1px solid black;
+}
+
+.subTip .tipsy-arrow-n { border-bottom-color: black; }
+.subTip .tipsy-arrow-s { border-top-color: black; }
+.subTip .tipsy-arrow-e { border-left-color: black; }
+.subTip .tipsy-arrow-w { border-right-color: black; }
+
+
+.contextMenu {
+ display:none;
+ position:absolute;
+ left:30px;
+ top:-30px;
+ z-index:999;
+ /* width:300px; */
+}
+.contextMenu ul {
+ width:300px;
+ margin:0;
+ /* padding:10px; */
+ list-style:none;
+ background:#fff;
+ color:#333;
+ font-weight: 600;
+ /* -moz-border-radius:5px; -webkit-border-radius:5px; border-radius:5px; */
+ -moz-box-shadow:5px 5px 5px #ddd; -webkit-box-shadow:5px 5px 5px #999; box-shadow:5px 5px 5px #ddd;
+ border: 1px solid #aaa;
+}
+.contextMenu ul li {
+ padding:5px 10px;
+ /* border-bottom: solid 1px #ccc; */
+}
+.contextMenu ul li:hover {
+ background:#4a90d9; color:#fff;
+}
+.contextMenu ul li:last-child {
+ border:none;
+}
+
+.na {
+ display: none;
+}
+.contextMenu ul li.new {
+ display: block;
+}
+.contextMenu ul li.adding, .contextMenu ul li.adding + li {
+ display: block;
+}
+.contextMenu ul li.force-display {
+ display: block;
+}
+.contextMenu ul li.context-separator {
+ background-color: lightgray;
+ height: 1px;
+ padding: 0;
+}
+
+.ui-tabs.ui-tabs-vertical .ui-tabs-nav li.separated {
+ margin-top: 1em;
+}
+
+#crosssection {
+ display: none;
+ position: absolute;
+ top: 200px;
+ left: 600px;
+}
+
+.node circle {
+/* fill: rgb(31, 119, 180);
+ fill-opacity: .25; */
+ fill: #cfe2f3;
+ fill-opacity: .98;
+ stroke: black;
+ stroke-width: 3px;
+}
+
+circle.subcircle {
+ stroke-width: 1px;
+ /* stroke-dasharray: 2; */
+ fill-opacity: 0;
+ stroke: darkgray;
+}
+
+.leaf circle {
+ fill: #6fa8dc;
+ fill-opacity: 0.95;
+ stroke-width: 3px;
+}
+
+.leaf circle[title] {
+ font-family: monospace;
+
+}
+
+#svg_legend {
+ position: absolute;
+ top: 110px;
+ right: 0;
+ border: 1px solid #ccc;
+ border-radius: 5px;
+ background-color: #fcfcfc;
+ margin-right: 1.3em;
+ padding: 1em;
+}
+
+#svg_legend svg {
+ height: 235px;
+ width: 180px;
+}
+
+#multiple_details div.gridStyle {
+/* height: 50em; */
+ min-height: 70px !important;
+ height: auto !important;
+}
+
+#multiple_details .ngViewport {
+ height: auto !important;
+}
+
+#multiple_details .gridCellButton button, #link_details .gridCellButton button {
+ margin: .25em .4em;
+ font-size: 12px;
+ height: 2em;
+ padding-top: .1em;
+}
+
+#linkFilter {
+ display: none;
+ padding: 0.5em;
+ border: 1px solid grey;
+ background-color: #F0F0F0;
+ position: absolute;
+}
+
+span.filter-icon {
+ padding-left: 1em;
+}
+
+button.filter-close {
+ width: 15px;
+ height: 20px;
+ padding: 0;
+ position: absolute;
+ right: 4px;
+ top: 4px;
+}
+
+div.filter-title h6 {
+ margin: 0;
+}
+
+.links button.btn-filter {
+ padding: 0 1em 0 0;
+ margin-left: 1em;
+ font-size: 1em;
+}
+
+button.btn-filter {
+ visibility: hidden;
+}
+span.dynatree-expanded button.btn-filter,
+a.dynatree-title:hover button.btn-filter {
+ visibility: visible;
+}
+
+div.hdash-button a {
+ color: white;
+}
+
+.linkDirIn {
+ color: red;
+ background-color: #f3f3f3;
+}
+
+.linkDirOut {
+ color: blue;
+ background-color: white;
+}
+
+div.topoGrid .ui-grid-viewport {
+ overflow: hidden !important;
+}
+
+@-moz-document url-prefix() {
+ .btn {padding: 2px 12px 8px !important;}
+}
+
+.ui-fancytree.fancytree-container {
+ font-size: 14px;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/css/plugin.css
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/css/plugin.css b/console/stand-alone/plugin/css/plugin.css
index 0d9f34d..db318cf 100644
--- a/console/stand-alone/plugin/css/plugin.css
+++ b/console/stand-alone/plugin/css/plugin.css
@@ -21,37 +21,6 @@ main-display > .span8 {
position: relative;
}
-.nickname-window,
-.channel-window,
-.main-window {
- position: absolute;
- top: 2px;
- bottom: 2px;
- left: 4px;
- right: 4px;
- /* border: 1px solid #d4d4d4;
- border-radius: 4px;*/
- overflow-y: auto;
- overflow-x: hidden;
-}
-
-.nickname-window > .nickname-window-inner,
-.channel-window > .channel-window-inner,
-.main-window > .main-window-inner {
- position: static;
-}
-
-.channel-window-inner > ul > li {
- cursor: pointer;
- padding: 0;
- border-bottom: 1px solid #EEEEEE;
-}
-
-
-.channel-window-inner > ul > li > span:hover {
- background-color: #EAEAEA;
-}
-
ul.qdrListNodes > li > span {
padding: 6px 20px; 6px; 6px;
display: block;
@@ -65,12 +34,11 @@ ul.qdrListNodes > li > span {
.qdrList div.gridDetails {
-
width: auto;
}
.selectedItems {
- margin-left: 21em;
+ /* margin-left: 21em; */
}
.qdrListPane {
@@ -81,93 +49,13 @@ ul.qdrListNodes > li > span {
width: auto;
}
-.nickname-window-inner > ul > li {
- cursor: pointer;
-}
-
-.channel-window {
- bottom: 40px;
-}
-
-.main-window {
- border: none;
- top: 46px;
- bottom: 46px;
-}
-
-.main-window.no-topic {
- top: 2px;
-}
-
-.topic-window {
- position: absolute;
- left: 10px;
- right: 10px;
- top: 2px;
- height: 20px;
- overflow: hidden;
- z-index: 50;
- border-bottom-left-radius: 4px;
- border-bottom-right-radius: 4px;
- border-left: 1px solid #d4d4d4;
- border-right: 1px solid #d4d4d4;
- border-bottom: 1px solid #d4d4d4;
- background: white;
- padding: 10px;
-}
-
-.input-widget {
- background: white;
- position: absolute;
- bottom: 2px;
- left: 2px;
- right: 2px;
- height: 40px;
- z-index: 50;
-}
-
-.input-widget > form {
- position: relative;
-}
-
-.input-widget > form > div {
- position: absolute;
- left: 2px;
- top: 2px;
- bottom: 2px;
- right: 84px;
-}
-
-.input-widget > form > div > input[type="text"] {
- width: 100%;
-}
-
-.input-widget > form > input[type="submit"] {
- position: absolute;
- right: 2px;
- top: 3px;
-}
-
-.input-widget > form > input {
- margin-bottom: 0;
-}
-
-.channel-control-buttons {
- position: absolute;
- background: white;
- bottom: 2px;
- left: 2px;
- right: 2px;
- z-index: 50;
-}
-
div.listAttrName {
padding-top: 5px;
}
div.listAttrName i.icon-bar-chart {
float: right;
- margin: 5px;
+ margin: 3px 5px;
}
div.listAttrName i.icon-bar-chart.active, div.hastip i.icon-bar-chart.active, li.haschart i {
@@ -221,25 +109,48 @@ div.centered {
margin: 0;
}
+/* dialog */
div.aChart {
height: 200px;
width: 400px;
margin: 1em;
}
+/* dashboard */
+div.aChart.hDash {
+ /* width: 21em; */
+ /* height: 17em; */
+ width: 100%;
+ height: 87%;
+ margin: 0;
+ padding: 0;
+
+}
div.chartContainer {
float: left;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
}
-div.d3Chart path {
- stroke: black;
+/* the x and y axis lines */
+.d3Chart g.axis path.domain {
stroke-width: 1;
- opacity: 0.5;
+ stroke: black;
+}
+
+/* the line surrounding the area chart */
+div.d3Chart path {
+/* stroke: black; */
+ stroke-width: 0;
+/* opacity: 0.5; */
}
+/* the line above the area chart */
+/* the color gets overridden */
div.d3Chart path.line {
stroke: steelblue;
- stroke-width: 1;
+ stroke-width: 1.5;
fill: none;
opacity: 1;
}
@@ -300,6 +211,9 @@ div.d3Chart {
padding: 1em 0;
border: 1px solid #C0C0C0;
}
+div.d3Chart.hDash {
+ border: 0px;
+}
div.d3Chart .axis path {
display: inherit;
@@ -342,6 +256,10 @@ div.chartContainer div.aChart {
margin-top: 0.5em;
}
+div.qdr-attributes .tree-header select {
+ width: 100%;
+}
+
div#main.qdr div ul.nav li.active a {
background-color: #e0e0ff !important;
color: #000000;
@@ -353,9 +271,20 @@ div#main.qdr .selected, .box.selected {
}
/* the selected node on the list page */
-div.qdrList li.active {
+div.qdrList li.active, ul.qdrListNodes li.active {
+ background-color: #e0e0ff;
+}
+
+div.qdr-attributes span.dynatree-selected a {
background-color: #e0e0ff;
}
+div.qdr-attributes.pane, div.qdr-topology.pane {
+ position: absolute;
+ margin-left: 10px;
+}
+div.qdr-topology.pane.left {
+ width: auto;
+}
/* the selected row in the name table */
div#main.qdr div.qdrList div.selected {
@@ -431,7 +360,10 @@ div.chartOptions span.minicolors-swatch {
padding: 0 0 0 24px !important;
}
-
+div.colorPicker div.colorText {
+ display: inline-block;
+ width: 10em;
+}
div.colorPicker div:nth-of-type(1), /* first span under div.colorPicker */
div.minicolors{
float:left;
@@ -468,6 +400,9 @@ div.tabbable .tab-pane {
border-left: 1px solid #ddd;
border-bottom: 1px solid #ddd;
}
+div.dlg-large div.tabbable .tab-pane {
+ margin-left: 11em;
+}
div.tabbable ul.nav-tabs {
margin-bottom: 0;
@@ -497,15 +432,34 @@ ul.qdrTopoModes {
text-align: right;
}
+.grid-align-value .ngCellText {
+ padding-right: 10px;
+}
+
.overview .ngRow:hover {
background:#e0e0ff;
}
+.qdr-overview.pane.left, .qdr-attributes.pane.left {
+ top: 100px;
+}
+.qdr-topology.pane.left {
+ top: 104px;
+}
+.qdr-overview.pane.left, .qdr-attributes.pane.left, .qdr-topology.pane.left {
+ left: 10px;
+}
+
.treeContainer {
width: 250px;
float: left;
}
+#entityNames {
+ width: 20em;
+ float: left;
+}
+
.treeDetails {
margin-left: 260px;
}
@@ -545,8 +499,10 @@ div.chartOptions label:nth-of-type(2) {
}
div.chartOptions label {
font-weight: normal;
+ display: inline-block;
}
+/*
.form-horizontal .control-label {
float: left;
width: 160px;
@@ -593,16 +549,18 @@ input[type="text"], input[type="number"], input[type="password"] {
.login input[type="checkbox"] {
margin-top: 0.75em;
}
+*/
-#login-container {
- width: 18.5em;
+#dispatch-login-container {
+ /* width: 18.5em; */
margin-top: 2em;
}
-
+/*
div.login.container {
-/* width: 550px; */
- margin-top: 4em;
+ width: 550px;
}
+*/
+
#overtree .fancytree-container {
border: 0px;
@@ -657,6 +615,201 @@ div.login.container {
opacity:1;
}
+.overview .table-striped tr:hover td {
+ background-color: #e0e0ff !important;
+}
+
+#entityNames div.ngViewport {
+ overflow-x: hidden;
+}
+
+.connect-column.connect-form {
+ width: 20em;
+}
+
+.chartLabels button a {
+ text-decoration: none;
+}
+
+.fancytree-ico-c.router .fancytree-icon {
+
+}
+
+.tabs-left .nav-tabs {
+ float: left;
+}
+.tabs-left .nav-tabs > li {
+/* float: initial; */
+}
+
+div.modal.dlg-large {
+ width: 53em;
+}
+
+button.hdash-button a {
+ text-decoration: none;
+ color: #fff;
+}
+
+div.widget-body > div {
+ height: 100%;
+}
+
+div.qdrCharts {
+ height: 100%;
+}
+
+ul.dispatch-view {
+ margin-bottom: 0 !important;
+}
+
+.qdr-overview.pane.left span:not(.dynatree-has-children) .dynatree-icon:before,
+.qdr-attributes.pane.left span:not(.dynatree-has-children) .dynatree-icon:before {
+ color: green;
+}
+
+span:not(.dynatree-has-children).address .dynatree-icon:before,
+span:not(.dynatree-has-children).router\.address .dynatree-icon:before {
+ content: "\f0ac";
+}
+
+span:not(.dynatree-has-children).connection.external .dynatree-icon:before,
+span:not(.dynatree-has-children).connection.normal .dynatree-icon:before {
+ content: "\f08e";
+}
+span:not(.dynatree-has-children).connection.external.quiesced .dynatree-icon:before {
+ content: "\f14c";
+ color: red;
+}
+
+span:not(.dynatree-has-children).connection.inter-router .dynatree-icon:before {
+ content: "\f152";
+}
+span:not(.dynatree-has-children).no-data .dynatree-icon:before {
+ content: "\f05e";
+ color: red !important;
+}
+span:not(.dynatree-has-children).loading .dynatree-icon:before {
+ content: "\f254";
+}
+span:not(.dynatree-has-children).router\.node .dynatree-icon:before {
+ content: "\f013";
+}
+span:not(.dynatree-has-children).connector .dynatree-icon:before {
+ content: "\f126";
+}
+span:not(.dynatree-has-children).container .dynatree-icon:before {
+ content: "\f16c";
+}
+span:not(.dynatree-has-children).log .dynatree-icon:before {
+ content: "\f0f6";
+}
+span:not(.dynatree-has-children).router\.link.inter-router .dynatree-icon:before {
+ content: "\f04e";
+}
+span:not(.dynatree-has-children).router\.link.endpoint .dynatree-icon:before {
+ content: "\f051";
+}
+span:not(.dynatree-has-children).listener .dynatree-icon:before {
+ content: "\f025";
+}
+span:not(.dynatree-has-children).connection .dynatree-icon:before {
+ content: "\f07e";
+}
+span:not(.dynatree-has-children).waypoint .dynatree-icon:before {
+ content: "\f0ec";
+}
+span:not(.dynatree-has-children).router .dynatree-icon:before {
+ content: "\f047";
+}
+span:not(.dynatree-has-children).fixedAddress .dynatree-icon:before {
+ content: "\f015";
+}
+span:not(.dynatree-has-children).linkRoutePattern .dynatree-icon:before {
+ content: "\f039";
+}
+span:not(.dynatree-has-children).allocator .dynatree-icon:before {
+ content: "\f170";
+}
+
+.ngCellText {
+/* color: #333333; */
+}
+
+.changed {
+ color: #339933;
+}
+
+div.dispatch-router div.help {
+ width: auto;
+ padding: 1em;
+ background-color: lavender;
+ border-radius: 6px;
+ margin-top: 1em;
+ text-align: center;
+}
+
+div.operations tr:nth-child(even) {
+ background: #f3f3f3;
+}
+div.operations tr:nth-child(odd), div.operations tr:last-child {
+ background: #fff;
+}
+
+div.operations tr input {
+ margin: 0;
+ padding: 3px 6px;
+}
+div.operations table {
+ width: 100%;
+}
+div.operations th {
+ width: 50%;
+ border-bottom: 1px solid #cccccc;
+ text-align: left;
+}
+div.operations td:nth-child(odd), div.operations th:nth-child(odd) {
+ border-right: 1px solid #cccccc;
+}
+div.operations td:nth-child(odd) {
+ padding-left: 0;
+}
+div.operations td:nth-child(even), div.operations th:nth-child(even) {
+ padding-left: 5px;
+}
+div.operations th {
+ padding: 5px;
+}
+div.operations .tab-pane.active {
+ padding: 12px 12px 12px 0;
+}
+div.operations label {
+ padding-top: 4px;
+ margin-bottom: 4px;
+}
+.qdrListActions .ngGrid {
+ /*min-height: 40em;
+ height: 100%; */
+}
+div.qdrListActions .ngViewport {
+ height: initial !important;
+}
+
+div.operations .boolean {
+ padding-bottom: 0;
+}
+
+table.log-entry {
+ margin-bottom: 1em;
+ border-top: 1px solid black;
+}
+
+table.log-entry pre {
+ background-color: #f5f5f5;
+ color: inherit;
+ margin: 0;
+}
+
circle.node.normal.console {
fill: lightcyan;
}
@@ -683,3 +836,39 @@ text.qpid-cpp.on-demand {
font-size: 18px;
font-weight: bold;
}
+
+i.red {
+ color: red;
+}
+
+.qdrListActions div.delete {
+ width: 20em;
+ margin: auto;
+ border: 1px solid #eaeaea;
+ height: 5em;
+ padding: 4em;
+ background-color: #fcfcfc;
+}
+
+.btn:focus {
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+}
+
+select:focus, input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus {
+ outline:3px solid rgba(82, 168, 236, 0.6);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+
+btn.disabled, .btn[disabled] {
+ opacity: 0.35;
+}
+
+#dispatch-login-container .ng-invalid-range {
+ border-color: #e9322d !important;
+}
+
+div#durationSlider, div#rateSlider {
+ margin-top: 1em;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/css/qdrTopology.css
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/css/qdrTopology.css b/console/stand-alone/plugin/css/qdrTopology.css
deleted file mode 100644
index f8cffed..0000000
--- a/console/stand-alone/plugin/css/qdrTopology.css
+++ /dev/null
@@ -1,562 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
-*/
-
-svg {
- background-color: transparent;
- cursor: default;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- -o-user-select: none;
- user-select: none;
-}
-
-svg:not(.active):not(.ctrl) {
- cursor: crosshair;
-}
-#end-arrow-selected, #start-arrow-selected {
- stroke: #00F;
- fill: #00F;
-}
-
-path.link {
- fill: none;
- stroke: #000;
- stroke-width: 4px;
- cursor: default;
-}
-
-svg:not(.active):not(.ctrl) path.link {
- cursor: pointer;
-}
-
-path.link.selected {
- stroke-dasharray: 10,2;
- stroke: #00F !important;
-}
-
-
-path.link.highlighted {
- stroke: #0F0 !important;
-
-}
-
-path.link.temp {
- opacity: 0.3;
-}
-path.link.temp.over {
- opacity: 0.8;
- stroke-dasharray: 10,2;
-}
-
-path.link.dragline {
- pointer-events: none;
-}
-
-path.link.hidden {
- stroke-width: 0;
-}
-
-
-circle.node {
- stroke-width: 1.5px;
- cursor: pointer;
- stroke: darkgray;
- fill: lightgray;
-}
-
-circle.node.reflexive {
- stroke: #F00 !important;
- stroke-width: 2.5px;
-}
-circle.node.selected {
- stroke: #F00 !important;
- stroke-width: 2px;
- fill: #e0e0ff !important;
-}
-circle.node.inter-router {
- fill: #EAEAEA;
-}
-circle.node.normal {
- fill: #F0F000;
-}
-circle.node.on-demand {
- fill: #C0FFC0;
-}
-circle.node.on-demand.artemis {
- fill: #FCC;
- /*opacity: 0.2; */
-}
-
-circle.node.fixed {
- stroke-dasharray: 10,2;
-}
-circle.node.temp {
- stroke: #f80;
- fill: #f0f0ff;
-}
-
-text {
- font: 12px sans-serif;
- pointer-events: none;
- /*font-family: monospace;*/
-
-}
-
-.tooltipsy
-{
- padding: 10px;
-/* max-width: 320px;*/
- color: #303030;
- background-color: #fcfcfe;
- border: 1px solid #deca7e;
- border-radius: 5px;
-}
-
-.tiptable {
-
-}
-.tiptable tr {
- border-bottom: 1px solid #ccc;
-}
-
-.tiptable tr:last-child {
- border-bottom: 0px;
-}
-
-.tiptable tr:nth-child(even) {
- background: #fcfcfe;
-}
-.tiptable tr:nth-child(odd) {
- background: #FFF
-}
-
-text.id {
- text-anchor: middle;
- font-weight: bold;
-}
-
-text.label {
- text-anchor: start;
- font-weight: bold;
-}
-
-.row-fluid.tertiary {
- position: relative;
- left: 20px;
-}
-
-.row-fluid.tertiary.left {
- float: left;
-}
-
-.row-fluid.tertiary.panel {
- width: 410px;
- /*height: 100%; */
-}
-
-/*, div.qdrTopology div#multiple_details .ngViewport*/
-div#topologyForm .ngViewport, div#topologyForm .gridStyle {
- height: inherit !important;
- min-height: initial !important;
- overflow: initial;
-}
-
-div#multiple_details {
- height: 300px;
- width: 500px;
- display: none;
- padding: 1em;
- border: 1px solid;
- position: absolute;
- background-color: white;
- max-height: 330px !important;
- overflow: hidden;
-}
-
-.panel-adjacent {
- margin-left: 430px;
-}
-
-#topologyForm.selected {
- border: 1px solid red;
-}
-#topologyForm {
- border: 1px solid white;
- padding: 2px;
- /* position: relative; */
- /* top: -8px; */
-}
-div.qdr-topology.pane.left .ngViewport {
- /* border: 1px solid lightgray; */
-}
-
-#topologyForm > div {
- width:396px;
-}
-
-/* globe */
-.land {
- fill: #999;
- stroke-opacity: 1;
-}
-
-.graticule {
- fill: none;
- stroke: black;
- stroke-width:.5;
- opacity:.1;
-}
-
-.labels {
- font: 18px sans-serif;
- fill: black;
- opacity: .85;
- text-anchor: middle;
-}
-
-.noclicks { pointer-events:none; }
-
-.point { opacity:.6; }
-
-.arcs {
- opacity:.7;
- stroke: darkgreen;
- stroke-width: 3;
-}
-.flyers {
- stroke-width:1;
- opacity: 0;
- stroke: darkred;
-}
-.arc, .flyer {
- stroke-linejoin: round;
- fill:none;
-}
-.arc { }
-.arc:hover {
- stroke: darkred;
-}
-.flyer { }
-.flyer:hover {
- stroke: darkgreen;
-}
-.arc.inter-router {
- stroke: darkblue;
-}
-
-#addNodeForm {
- padding: 1em;
-}
-
-
-li.currentStep {
- font-weight: bold;
-}
-
-.qdrTopology div.panel {
- position: absolute;
-}
-/*
-.ui-dialog-titlebar {
- border: 0;
- background: transparent;
-}
-*/
-
-/*
-.ui-tabs.ui-tabs-vertical {
- padding: 0;
- width: 48em;
-}
-.ui-tabs.ui-tabs-vertical .ui-widget-header {
- border: none;
-}
-.ui-tabs.ui-tabs-vertical .ui-tabs-nav {
- float: left;
- width: 10em;
- background: #CCC;
- border-radius: 4px 0 0 4px;
- border-right: 1px solid gray;
-}
-.ui-tabs.ui-tabs-vertical .ui-tabs-nav li {
- clear: left;
- width: 100%;
- margin: 0.1em 0;
- border: 1px solid gray;
- border-width: 1px 0 1px 1px;
- border-radius: 4px 0 0 4px;
- overflow: hidden;
- position: relative;
- right: -2px;
- z-index: 2;
-}
-.ui-tabs.ui-tabs-vertical .ui-tabs-nav li a {
- display: block;
- width: 100%;
- padding: 0.1em 1em;
-}
-.ui-tabs.ui-tabs-vertical .ui-tabs-nav li a:hover {
- cursor: pointer;
-}
-.ui-tabs.ui-tabs-vertical .ui-tabs-nav li.ui-tabs-active {
- margin-bottom: 0.2em;
- padding-bottom: 0;
- border-right: 1px solid white;
-}
-.ui-tabs.ui-tabs-vertical .ui-tabs-nav li:last-child {
- margin-bottom: 10px;
-}
-.ui-tabs.ui-tabs-vertical .ui-tabs-panel {
- float: left;
- width: 34em;
- border-left: 1px solid gray;
- border-radius: 0;
- position: relative;
- left: -1px;
-}
-
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected {
- right: -3px !important;
-}
-
-.ui-tabs li i.ui-icon {
- display: inline-block;
-}
-*/
-.ui-tabs .ui-tabs-panel {
- /* padding-top: 0 !important; */
-}
-
-.ui-widget-content fieldset {
- float: left;
- padding: 0 1em 0 0;
-}
-
-.entity-description {
- color: #960;
- font-size: 90%;
-}
-
-.attr-description {
- padding-top: 1.5em;
- float: right;
- width: 17em;
-}
-.attr-annotations {
- padding-top: 2.5em;
- clear: both;
-}
-.attr-annotations > span {
- padding-top: 0.5em;
- border-top: 1px dashed darkgray;
- display: block;
-}
-
-.attr-type {
- color: #990;
- font-size: 85%;
-}
-.attr-required {
- color: red;
- font-size: 85%;
-}
-.attr-unique {
- color: green;
- font-size: 85%;
-}
-
-#tabs.nodeEntities {
- border: 0;
-}
-
-#tabs ul.nodeTabs {
- background: #fff;
-}
-
-#tabs #Container {
- border-left: 1px solid #aaa;
-}
-
-#tabs.ui-tabs .ui-tabs-nav li {
- border-bottom: 1px solid #aaa !important;
-}
-
-.entity-fields {
- /* height: 400px; */
- overflow-y: scroll;
- overflow-x: hidden;
-}
-
-div.boolean label:first-child {
- float: left;
- margin-right: 1em;
-}
-div.boolean {
- padding-bottom: 1em;
-}
-
-.entity-fields label {
- font-weight: 600;
- margin-top: 0.5em;
- display: inline;
-}
-
-.aggregate {
- text-align: right;
-}
-
-.aggregate i {
- float: right;
- margin: 3px 3px 3px 8px;
-}
-
-.aggregate .hastip {
- padding: 5px;
-}
-
-.subTip .tipsy-inner {
- background-color: white;
- color: black;
- font-size: 1.3em;
- border: 1px solid black;
-}
-
-.subTip .tipsy-arrow-n { border-bottom-color: black; }
-.subTip .tipsy-arrow-s { border-top-color: black; }
-.subTip .tipsy-arrow-e { border-left-color: black; }
-.subTip .tipsy-arrow-w { border-right-color: black; }
-
-
-.contextMenu {
- display:none;
- position:absolute;
- left:30px;
- top:-30px;
- z-index:999;
- /* width:300px; */
-}
-.contextMenu ul {
- width:300px;
- margin:0;
- /* padding:10px; */
- list-style:none;
- background:#fff;
- color:#333;
- font-weight: 600;
- /* -moz-border-radius:5px; -webkit-border-radius:5px; border-radius:5px; */
- -moz-box-shadow:5px 5px 5px #ddd; -webkit-box-shadow:5px 5px 5px #999; box-shadow:5px 5px 5px #ddd;
- border: 1px solid #aaa;
-}
-.contextMenu ul li {
- padding:5px 10px;
- /* border-bottom: solid 1px #ccc; */
-}
-.contextMenu ul li:hover {
- background:#4a90d9; color:#fff;
-}
-.contextMenu ul li:last-child {
- border:none;
-}
-
-.na {
- display: none;
-}
-.contextMenu ul li.new {
- display: block;
-}
-.contextMenu ul li.adding, .contextMenu ul li.adding + li {
- display: block;
-}
-.contextMenu ul li.force-display {
- display: block;
-}
-.contextMenu ul li.context-separator {
- background-color: lightgray;
- height: 1px;
- padding: 0;
-}
-
-.ui-tabs.ui-tabs-vertical .ui-tabs-nav li.separated {
- margin-top: 1em;
-}
-
-#crosssection {
- display: none;
- position: absolute;
- top: 200px;
- left: 600px;
-}
-
-.node circle {
-/* fill: rgb(31, 119, 180);
- fill-opacity: .25; */
- fill: #cfe2f3;
- fill-opacity: .98;
- stroke: black;
- stroke-width: 3px;
-}
-
-circle.subcircle {
- stroke-width: 1px;
- /* stroke-dasharray: 2; */
- fill-opacity: 0;
- stroke: black;
-}
-
-.leaf circle {
- fill: #6fa8dc;
- fill-opacity: 0.95;
- stroke-width: 3px;
-}
-
-.leaf circle[title] {
- font-family: monospace;
-
-}
-
-#svg_legend {
- position: absolute;
- top: 110px;
- right: 0;
- border: 1px solid #ccc;
- border-radius: 5px;
- background-color: #fcfcfc;
- margin-right: 1.3em;
- padding: 1em;
-}
-
-#svg_legend svg {
- height: 235px;
- width: 180px;
-}
-
-#multiple_details div.gridStyle {
-/* height: 50em; */
- min-height: 70px !important;
- height: auto !important;
-}
-
-#multiple_details .ngViewport {
- height: auto !important;
-}
-
-div.topoGrid .ui-grid-viewport {
- overflow: hidden !important;
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/css/site-base.css
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/css/site-base.css b/console/stand-alone/plugin/css/site-base.css
index e22476b..7c7ebf6 100644
--- a/console/stand-alone/plugin/css/site-base.css
+++ b/console/stand-alone/plugin/css/site-base.css
@@ -21,7 +21,7 @@ under the License.
}
* {
- font-family: sans-serif;
+ font-family: 'Open Sans', sans-serif;
}
a:focus {
@@ -2004,8 +2004,8 @@ div#main div ul.nav li a.nav-primary .caret {
font-size: 20px;
}
-#main {
- margin-top: 44px !important;
+div#main.qdr {
+ margin-top: 40px !important;
}
dd.file-list {
@@ -3344,7 +3344,7 @@ fs-donut svg g text.units {
/* hack to work around strange tabset behavior */
tabset > .tabbable > ul {
- display: none;
+/* display: none; */
}
/* end hack */
@@ -4504,3 +4504,224 @@ div#main div ul.nav {
background-repeat: repeat-x;
box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
}
+
+ul.dynatree-container {
+ background: inherit;
+}
+ul.dynatree-container li {
+ background: inherit;
+}
+
+i.expandable-indicator {
+ color: #666;
+}
+
+span.dynatree-expander {
+ color: #728271;
+}
+
+span.dynatree-icon {
+ color: #EECA7C;
+}
+span:not(.dynatree-has-children) .dynatree-icon:before {
+ color: gray;
+}
+
+span.dynatree-empty,
+span.dynatree-vline,
+span.dynatree-connector,
+span.dynatree-expander,
+span.dynatree-icon,
+span.dynatree-checkbox,
+span.dynatree-radio,
+span.dynatree-drag-helper-img,
+#dynatree-drop-marker
+{
+ font-family: FontAwesome;
+ font-weight: normal;
+ font-style: normal;
+ display: inline-block;
+ text-decoration: inherit;
+ background-image: none;
+ vertical-align: middle;
+}
+
+.dynatree-checkbox {
+ color: #888888
+}
+
+/* Dynatree checkbox */
+span.dynatree-checkbox:before
+{
+ margin-top: 1px;
+ background-position: 0 0;
+ cursor: pointer;
+ content: "";
+}
+
+span.dynatree-checkbox:before:hover
+{
+ background-position: 0 0;
+ content: "";
+}
+
+.dynatree-selected span.dynatree-checkbox:before
+{
+ margin-top: 1px;
+ background-position: 0 0;
+ cursor: pointer;
+ content: "\f00c";
+}
+
+.dynatree-selected span.dynatree-checkbox:before:hover
+{
+ background-position: 0 0;
+ content: "\f00c";
+}
+
+
+.dynatree-expander {
+ color: #888888
+}
+
+/* Dynatree expander */
+span.dynatree-expander:before
+{
+ margin-top: 1px;
+ background-position: 0 0;
+ cursor: pointer;
+ content: "\f054";
+}
+
+span.dynatree-expander:before:hover
+{
+ background-position: 0 0;
+ content: "\f054";
+}
+
+.dynatree-exp-e span.dynatree-expander:before, /* Expanded, not delayed, not last sibling */
+.dynatree-exp-ed span.dynatree-expander:before, /* Expanded, delayed, not last sibling */
+.dynatree-exp-el span.dynatree-expander:before, /* Expanded, not delayed, last sibling */
+.dynatree-exp-edl span.dynatree-expander:before /* Expanded, delayed, last sibling */
+{
+ background-position: 0 0;
+ content: "\f078";
+}
+.dynatree-exp-e span.dynatree-expander:before:hover, /* Expanded, not delayed, not last sibling */
+.dynatree-exp-ed span.dynatree-expander:before:hover, /* Expanded, delayed, not last sibling */
+.dynatree-exp-el span.dynatree-expander:before:hover, /* Expanded, not delayed, last sibling */
+.dynatree-exp-edl span.dynatree-expander:before:hover /* Expanded, delayed, last sibling */
+{
+ background-position: 0 0;
+ content: "\f0da";
+}
+
+/* closed folder */
+.dynatree-ico-cf span.dynatree-icon:before {
+ background-position: 0 0;
+ content: "\f07b";
+}
+
+/* open folder */
+.dynatree-ico-ef span.dynatree-icon:before {
+ background-position: 0 0;
+ content: "\f07c";
+}
+
+span.dynatree-icon:before {
+ background-position: 0px 0px;
+ content: "\f013";
+}
+
+span.dynatree-folder a {
+ font-weight: normal;
+}
+
+div.treeContainer ul.dynatree-container {
+ border: 0px;
+}
+
+.pane {
+ position: fixed;
+ bottom: 0;
+ top: 70px;
+ height: auto;
+ width: 300px;
+}
+
+.pane>.pane-wrapper {
+ position: relative;
+ height: 100%;
+ width: 100%;
+ overflow: hidden;
+}
+
+.pane.left .pane-viewport {
+ margin-left: 10px;
+ right: 5px;
+ margin-right: 0;
+}
+
+.pane-viewport {
+ border-top: 1px solid #d4d4d4;
+}
+.pane-viewport {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ overflow: auto;
+ margin-right: 10px;
+}
+
+.pane-content {
+ float: none;
+ position: static;
+}
+.pane-content {
+ width: auto;
+ height: auto;
+}
+
+.pane.left .pane-bar {
+ border-right: 1px solid #d4d4d4;
+}
+.pane.left .pane-bar, .pane.right {
+ right: 0;
+}
+.pane-bar {
+ background: white;
+}
+.pane-bar {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 5px;
+ cursor: ew-resize;
+ height: 100%;
+}
+
+div#overview-controller, div#list-controller {
+ padding-left: 300px;
+}
+
+.ngViewport.ng-scope{
+ height: auto !important;
+ overflow-y: hidden;
+}
+
+.ngTopPanel.ng-scope, .ngHeaderContainer{
+ width: auto !important;
+}
+
+.qdr-overview.pane.left, .qdr-attributes.pane.left, .qdr-topology.pane.left {
+ top: 70px;
+}
+
+div.chartContainer {
+ width: auto;
+}
+
+div.chartOptions div.duration {
+ width: 30em !important;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/html/qdrCharts.html
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/html/qdrCharts.html b/console/stand-alone/plugin/html/qdrCharts.html
index ccb7b5a..dc41a37 100644
--- a/console/stand-alone/plugin/html/qdrCharts.html
+++ b/console/stand-alone/plugin/html/qdrCharts.html
@@ -29,7 +29,7 @@ under the License.
<div ng-init="chartsLoaded()"></div>
</div>
<div ng-hide="hasCharts()" class="centered">
- There are no charts. To add charts to this page, click on a <i class="icon-bar-chart"></i> icon on the <button ng-click="showListPage()"><i class="icon-list "></i> List</button> page.
+ There are no charts. To add charts to this page, click on a <i class="icon-bar-chart"></i> icon on the <button ng-click="showListPage()"><i class="icon-list "></i> Entities</button> page.
</div>
</div>
@@ -44,36 +44,37 @@ under the License.
</div>
<div class="modal-body">
<div id="{{svgDivId}}" class="d3Chart"></div>
- <uib-tabset>
- <uib-tab heading="Type">
+ <tabset>
+ <tab heading="Type">
<legend>Chart type</legend>
- <label><input type="radio" ng-model="dialogChart.type" value="value" ng-change="chartChanged()" /> Value Chart</label>
- <label><input type="radio" ng-model="dialogChart.type" value="rate" ng-change="chartChanged()" /> Rate Chart</label>
+ <label><input type="radio" ng-model="dialogChart.type" value="value" /> Value Chart</label>
+ <label><input type="radio" ng-model="dialogChart.type" value="rate" /> Rate Chart</label>
<div class="dlg-slider" ng-show="dialogChart.type=='rate'">
<span>Rate Window: {{rateWindow}} second{{rateWindow > 1 ? "s" : ""}}</span>
- <div class="slider" ui-slider="slider.options" ng-model="rateWindow"></div>
+ <div id="rateSlider"></div>
</div>
<div style="clear:both;"> </div>
- </uib-tab>
- <uib-tab heading="Colors">
+ </tab>
+ <tab ng-hide="$parent.chart.aggregate()" heading="Colors">
<legend>Chart colors</legend>
<div class="colorPicker">
- <div>Area</div><input minicolors="areaColor" id="position-bottom-left" type="text" ng-model="dialogChart.areaColor" />
+ <label>Line: <input id="lineColor" name="lineColor" type="color" /></label>
</div>
<div class="colorPicker">
- <div>Line</div><input minicolors="lineColor" id="position-bottom-left" type="text" ng-model="dialogChart.lineColor" />
+ <label>Area: <input id="areaColor" name="areaColor" type="color" /></label>
</div>
<div style="clear:both;"> </div>
- </uib-tab>
- <uib-tab heading="Duration">
+ </tab>
+ <tab heading="Duration">
<legend>Chart duration</legend>
<div class="dlg-slider duration">
- <span>Show data for past {{dialogChart.visibleDuration}} minute{{dialogChart.visibleDuration > 1 ? "s" : ""}}</span> <div class="slider" ui-slider="duration.options" ng-model="dialogChart.visibleDuration"></div>
+ <span>Show data for past {{dialogChart.visibleDuration}} minute{{dialogChart.visibleDuration > 1 ? "s" : ""}}</span>
+ <div id="durationSlider"></div>
</div>
<div style="clear:both;"> </div>
- </uib-tab>
- </uib-tabset>
+ </tab>
+ </tabset>
</div>
<div class="modal-footer">
<button class="btn btn-success" type="button" ng-click="apply()">Apply to existing chart</button>
@@ -81,88 +82,5 @@ under the License.
<button class="btn btn-primary" type="button" ng-click="okClick()">Close</button>
</div>
</div>
-<!--
- <div class="chartOptions" title="Configure chart" ng-controller="QDR.ChartDialogController">
- <p class="dialogHeader">Title: <input type="text" ng-model="userTitle" /></p>
- <div id="{{svgDivId}}" class="d3Chart"></div>
- <p></p>
- <uib-tabset>
- <uib-tab heading="Type">
- <legend>Chart type</legend>
- <label><input type="radio" ng-model="dialogChart.type" value="value" ng-change="chartChanged()" /> Value Chart</label>
- <label><input type="radio" ng-model="dialogChart.type" value="rate" ng-change="chartChanged()" /> Rate Chart</label>
-
- <div class="dlg-slider" ng-show="dialogChart.type=='rate'">
- <span>Rate Window: {{rateWindow}} second{{rateWindow > 1 ? "s" : ""}}</span>
- <div class="slider" ui-slider="slider.options" ng-model="rateWindow"></div>
- </div>
- <div style="clear:both;"> </div>
- </uib-tab>
- <uib-tab heading="Colors">
- <legend>Chart colors</legend>
- <div class="colorPicker">
- <div>Area</div><input minicolors="areaColor" id="position-bottom-left" type="text" ng-model="dialogChart.areaColor" />
- </div>
- <div class="colorPicker">
- <div>Line</div><input minicolors="lineColor" id="position-bottom-left" type="text" ng-model="dialogChart.lineColor" />
- </div>
- <div style="clear:both;"> </div>
- </uib-tab>
- <uib-tab heading="Duration">
- <legend>Chart duration</legend>
- <div class="dlg-slider duration">
- <span>Show data for past {{dialogChart.visibleDuration}} minute{{dialogChart.visibleDuration > 1 ? "s" : ""}}</span> <div class="slider" ui-slider="duration.options" ng-model="dialogChart.visibleDuration"></div>
- </div>
- <div style="clear:both;"> </div>
-
- </uib-tab>
- </uib-tabset>
-
- <tabset>
- <tab heading="Type">
- <div>
- <legend>Chart type</legend>
- <label>
- <input type="radio" ng-model="dialogChart.type" value="value" ng-change="chartChanged()" />
- Value Chart
- </label>
- <label class="rateGroup">
- <input type="radio" ng-model="dialogChart.type" value="rate" ng-change="chartChanged()" /> Rate Chart
- </label>
- <div class="dlg-slider" ng-show="dialogChart.type=='rate'">
- <span>Rate Window: {{rateWindow}} second{{rateWindow > 1 ? "s" : ""}}</span> <div class="slider" ui-slider="slider.options" ng-model="rateWindow"></div>
- </div>
- </div>
- <div style="clear:both;"> </div>
- </tab>
- <tab heading="Colors">
- <div>
- <legend>Chart colors</legend>
- <div class="colorPicker">
- <div>Area</div><input minicolors="areaColor" id="position-bottom-left" type="text" ng-model="dialogChart.areaColor" />
- </div>
- <div class="colorPicker">
- <div>Line</div><input minicolors="lineColor" id="position-bottom-left" type="text" ng-model="dialogChart.lineColor" />
- </div>
- </div>
- <div style="clear:both;"> </div>
- </tab>
- <tab heading="Duration">
- <div>
- <legend>Chart duration</legend>
- </div>
- <div class="dlg-slider duration">
- <span>Show data for past {{dialogChart.visibleDuration}} minute{{dialogChart.visibleDuration > 1 ? "s" : ""}}</span> <div class="slider" ui-slider="duration.options" ng-model="dialogChart.visibleDuration"></div>
- </div>
- <div style="clear:both;"> </div>
- </tab>
- </tabset>
- <div class="okButton">
- <button ng-click="apply()">Apply to existing chart</button>
- <button ng-click="copyToDashboard()">Create new chart</button>
- <button ng-click="okClick()">Close</button>
- </div>
- </div>
--->
</script>
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/html/qdrConnect.html
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/html/qdrConnect.html b/console/stand-alone/plugin/html/qdrConnect.html
index f1fd0b8..2ea3afa 100644
--- a/console/stand-alone/plugin/html/qdrConnect.html
+++ b/console/stand-alone/plugin/html/qdrConnect.html
@@ -36,66 +36,44 @@ under the License.
</div>
</div>
<div class="connect-column connect-form">
- <div class="span2 offset4">
- <!-- <div simple-form name="settings" data="formConfig" entity="formEntity"></div> -->
- <form class="form-horizontal no-bottom-margin" novalidate name="settings" action="" method="post">
- <fieldset>
- <div class="control-group">
- <label class="control-label">Address: </label>
- <div class="controls">
- <input type="text" description="Router address" ng-model="formEntity.address" name="address" required="required" autofocus="autofocus" class="ng-pristine ng-valid ng-valid-required">
- <span class="help-block"></span>
- </div>
+ <form class="hawtio-form form-horizontal no-bottom-margin" novalidate ng-submit="connect()" name="settings">
+ <fieldset>
+ <div class="control-group" ng-show="true">
+ <label class="strong control-label">Address: </label>
+ <div class="controls">
+ <input tabindex="1" type="text" ng-model="formEntity.address" placeholder="localhost" name="address" autofocus="autofocus" class="ng-pristine ng-valid ng-valid-required"></div>
+ </div>
+ <div class="control-group" ng-show="true">
+ <label tabindex="-1" class="control-label" title="Ports to connect to, by default 5673">Port: </label>
+ <div class="controls">
+ <input tabindex="2" posint type="number" placeholder="5673" tooltip="Ports to connect to, by default 5673" ng-model="formEntity.port" name="port" title="Ports to connect to, by default 5673">
+ <span ng-show="settings.port.$error.range">Must be 1 through 65535</span>
</div>
- <div class="control-group">
- <label class="control-label" title="Port to connect to, by default 5673">Port: </label>
- <div class="controls">
- <input type="number" description="Router port" tooltip="Ports to connect to, by default 5672" ng-model="formEntity.port" name="port" title="Port to connect to, by default 5673" class="ng-scope ng-pristine ng-valid ng-valid-number">
- <span class="help-block"></span>
- </div>
- </div>
- <!--
- <div class="control-group">
- <label class="control-label">Username: </label>
- <div class="controls">
- <input type="text" description="User Name" ng-model="formEntity.username" name="username" class="ng-pristine ng-valid">
- <span class="help-block"></span>
- </div>
- </div>
- <div class="control-group">
- <label class="control-label">Password: </label>
- <div class="controls">
- <input type="password" description="Password" ng-model="formEntity.password" name="password" class="ng-pristine ng-valid">
- <span class="help-block"></span>
- </div>
- </div>
- -->
- <div class="control-group">
- <label class="control-label" title="Whether or not the connection should be started as soon as you navigate to the console">Autostart: </label>
- <div class="controls">
- <input type="checkbox" description="Connect at startup" tooltip="Whether or not the connection should be started as soon as you navigate to the console" ng-model="formEntity.autostart" name="autostart" title="Whether or not the connection should be started as soon as you log into hawtio" class="ng-scope ng-pristine ng-valid">
- <span class="help-block"></span>
- </div>
- </div>
- <input type="submit" style="position: absolute; left: -9999px; width: 1px; height: 1px;">
- </fieldset>
- </form>
- <p></p>
- <div>
- <button class="btn btn-primary pull-right" ng-disabled="settings.$invalid" ng-click="connect()">{{buttonText()}}</button>
- </div>
- </div>
+ </div>
+ <div class="control-group" ng-show="true">
+ <label tabindex="-1" class="control-label" title="Whether or not the connection should be started as soon as you log into hawtio">Autostart: </label>
+ <div class="controls">
+ <input tabindex="3" type="checkbox" tooltip="Whether or not the connection should be started as soon as you log into hawtio" ng-model="formEntity.autostart" name="autostart" title="Whether or not the connection should be started as soon as you log into hawtio"
+ class="ng-scope ng-pristine ng-valid"></div>
+ </div>
+ <input tabindex="-1" type="submit" style="position: absolute; left: -9999px; width: 1px; height: 1px;">
+ <p></p>
+ <div>
+ <button type="submit" tabindex="4" class="btn btn-primary pull-right" ng-disabled="settings.$invalid">{{buttonText()}}</button>
+ <!-- <button tabindex="-1" class="btn btn-secondary pull-right" ng-click="connect1()">Debug</button> -->
+ </div>
+ </fieldset>
+ </form>
</div>
</div>
</div>
- <div class="span4 centered" ng-show="connecting">
- <i class="icon-spin icon-spinner icon-4x"></i>
- <p>Please wait, connecting now...</p>
- </div>
- <div class="centered" ng-show="connectionError">
- <p>There was a connection error: {{connectionErrorText}}</p>
- </div>
+ <div class="centered" ng-show="connecting">
+ <i class="icon-spin icon-spinner icon-4x"></i>
+ <p>Please wait, connecting now...</p>
+ </div>
+ <div class="centered" ng-show="connectionError">
+ <p>There was a connection error: {{connectionErrorText}}</p>
+ </div>
- <div class="span4"></div>
</div>
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/html/qdrLayout.html
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/html/qdrLayout.html b/console/stand-alone/plugin/html/qdrLayout.html
index d164f8a..208e390 100644
--- a/console/stand-alone/plugin/html/qdrLayout.html
+++ b/console/stand-alone/plugin/html/qdrLayout.html
@@ -16,11 +16,11 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
-<ul class="nav nav-tabs connected" ng-controller="QDR.NavBarController">
- <li ng-repeat="link in breadcrumbs" ng-show="isValid(link)" ng-class='{active : isActive(link.href), "pull-right" : isRight(link), haschart: hasChart(link)}'>
- <a ng-href="{{link.href}}{{hash}}" ng-bind-html="link.content | to_trusted"></a>
+<ul class="nav nav-tabs connected dispatch-view" ng-controller="QDR.NavBarController">
+ <li ng-repeat="link in breadcrumbs" title="{{link.title}}" ng-show="isValid(link)" ng-class='{active : isActive(link.href), "pull-right" : isRight(link), haschart: hasChart(link)}'>
+ <a ng-href="{{link.href}}{{hash}}" ng-bind-html-unsafe="link.content"></a>
</li>
</ul>
-<div class="row-fluid">
+<div class="row-fluid dispatch-router">
<div ng-view></div>
</div>
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/html/qdrList.html
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/html/qdrList.html b/console/stand-alone/plugin/html/qdrList.html
index 156b21a..9d1379e 100644
--- a/console/stand-alone/plugin/html/qdrList.html
+++ b/console/stand-alone/plugin/html/qdrList.html
@@ -16,41 +16,73 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
-<div class="main-display row-fluid qdrList" ng-controller="QDR.ListController">
- <ul class="nav nav-tabs qdrListNodes">
- <li ng-repeat="node in nodes" ng-click="selectNode(node)" ng-class="{active : isNodeSelected(node.id)}"> <span>{{node.name}}</span> </li>
- </ul>
+<div id="list-controller" ng-controller="QDR.ListController" ng-include="tmplListTree"></div>
+
+<script type="text/ng-template" id="listGrid.html">
<div class="row-fluid qdrListActions">
- <ul class="nav nav-tabs ng-scope">
- <li ng-repeat="entity in entities" ng-class="{active : isActionActive(entity.name)}" ng-click="selectAction(entity.name)" >
- <a title="{{entity.title}}" data-placement="bottom"> {{entity.humanName}} </a></li>
+ <ul class="nav nav-tabs">
+ <li ng-repeat="mode in modes" ng-show="isValid(mode)" ng-click="selectMode(mode)" ng-class="{active : isModeSelected(mode)}" title="{{mode.title}}" ng-bind-html-unsafe="mode.content"> </li>
</ul>
- <div class="gridStyle" ng-style="getTableHeight()" ui-grid-auto-resize ui-grid-selection ui-grid="gridDef"></div>
- <div class="selectedItems">
- <div ng-style="getDetailsTableHeight()" ui-grid-auto-resize ui-grid-selection ui-grid="details"></div>
+ <h4>{{selectedRecordName}}</h4>
+ <div ng-show="currentMode.id === 'attributes'" class="selectedItems">
+ <div ng-show="selectedRecordName === selectedEntity" class="no-content">There are no {{selectedEntity | safePlural}}</div>
+ <div ng-hide="selectedRecordName === selectedEntity" ng-grid="details"></div>
+ </div>
+ <div ng-show="currentMode.id === 'delete'">
+ <div class="delete" ng-show="selectedRecordName !== selectedEntity">
+ <button class="btn btn-primary" ng-click="remove()">Delete</button> {{selectedRecordName}}
</div>
- </div>
-</div>
-<!--
- This is the template for the graph dialog that is displayed. It uses the
- dialogCtrl controller in qdrList.js.
--->
-<script type="text/ng-template" id="template-from-script.html">
- <div class="modal-header">
- <h3 class="modal-title">Chart {{chart.attr() | humanify}}</h3>
- </div>
- <div class="modal-body">
- <div id="{{svgDivId}}" class="d3Chart"></div>
- </div>
- <div class="modal-footer">
- <span ng-hide="isOnChartsPage()">
- <button class="btn btn-success" type="button" ng-click="addChartsPage()"><i class="icon-bar-chart"></i> Add</button> this chart to the Charts page.
- </span>
- <span ng-show="isOnChartsPage()">
- <button class="btn btn-danger" type="button" ng-click="delChartsPage()">Remove</button> this chart from the <button class="btn btn-success" type="button" ng-click="showChartsPage()"><i class="icon-bar-chart"></i> Charts</button> page.
- </span>
- <button class="btn btn-primary" type="button" ng-click="ok()">Close</button>
+ <div ng-hide="selectedRecordName !== selectedEntity">
+ There are no {{selectedEntity}}s
+ </div>
+ </div>
+ <div class="operations" ng-show="currentMode.id === 'operations'">
+ <fieldset ng-show="operation != ''">
+ <table>
+ <tr>
+ <th>Attribute</th>
+ <th>Value</th>
+ </tr>
+ <tr title="{{attribute.title}}" ng-repeat="attribute in detailFields">
+ <td><label for="{{attribute.name}}">{{attribute.name | humanify}}</label></td>
+ <!-- we can't do <input type="{angular expression}"> because... jquery throws an exception because... -->
+ <td>
+ <div ng-if="attribute.input == 'input'">
+ <!-- ng-pattern="testPattern(attribute)" -->
+ <input ng-if="attribute.type == 'number'" type="number" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.rawValue" ng-required="attribute.required" class="ui-widget-content ui-corner-all"/>
+ <input ng-if="attribute.type == 'text'" type="text" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.attributeValue" ng-required="attribute.required" class="ui-widget-content ui-corner-all"/>
+ <textarea ng-if="attribute.type == 'textarea'" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.attributeValue" ng-required="attribute.required" class="ui-widget-content ui-corner-all"></textarea>
+ <span ng-if="attribute.type == 'disabled'" >{{getAttributeValue(attribute)}}</span>
+ </div>
+ <div ng-if="attribute.input == 'select'">
+ <select id="{{attribute.name}}" ng-model="attribute.selected" ng-options="item for item in attribute.rawtype track by item"></select>
+ </div>
+ <div ng-if="attribute.input == 'boolean'" class="boolean">
+ <label><input type="radio" ng-model="attribute.rawValue" ng-value="true"> True</label>
+ <label><input type="radio" ng-model="attribute.rawValue" ng-value="false"> False</label>
+ </div>
+ </td>
+ </tr>
+ <tr><td></td><td><button class="btn btn-primary" type="button" ng-click="ok()">{{operation | Pascalcase}}</button></td></tr>
+ </table>
+ </fieldset>
+ </div>
+ <div ng-show="currentMode.id === 'log'">
+ <table class="log-entry" ng-repeat="entry in logResults track by $index">
+ <tr>
+ <td align="left" colspan="2">{{entry.time}}</td>
+ </tr>
+ <tr>
+ <td>Type</td><td>{{entry.type}}</td>
+ </tr>
+ <tr>
+ <td>Source</td><td>{{entry.source}}:{{entry.line}}</td>
+ </tr>
+ <tr>
+ <td valign="middle">Message</td><td valign="middle"><pre>{{entry.message}}</pre></td>
+ </tr>
+ </table>
+ </div>
</div>
</script>
-
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/html/qdrOverview.html
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/html/qdrOverview.html b/console/stand-alone/plugin/html/qdrOverview.html
index d63ea0e..e3876ee 100644
--- a/console/stand-alone/plugin/html/qdrOverview.html
+++ b/console/stand-alone/plugin/html/qdrOverview.html
@@ -16,61 +16,99 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
-<div ng-controller="QDR.OverviewController">
+<div id="overview-controller" ng-controller="QDR.OverviewController" ng-include="tmplOverviewTree"></div>
- <div class="treeContainer">
- <div id="overtree"></div>
+<script type="text/ng-template" id="overviewGrid.html">
+ <div class="gridDetails" ng-include="template.url"></div>
+ <div id="linkFilter">
+ <div class="filter-title">
+ <h6>Filter by link type</h6>
+ <button ng-click="filterClose()" type="button" class="btn btn-primary filter-close">x</button>
+ </div>
+ <select ng-init="currentLinkFilter = 'endpoint'" ng-model="currentLinkFilter" ng-change="setLinkFilter(currentLinkFilter)">
+ <option value="">All link types</option>
+ <option value="endpoint" selected>Endpoints only</option>
+ </select>
</div>
-
- <div class="treeDetails" ng-include="template.url"></div>
-</div>
-
-
+</script>
<!-- the following scripts are content that gets loaded into the above div that has the temple.url -->
<script type="text/ng-template" id="routers.html">
<div class="row-fluid">
<h3>Routers</h3>
<div class="overview">
- <div class="gridStyle" ng-style="getGridHeight(allRouters)" ui-grid-auto-resize ui-grid-selection ui-grid="allRouters"></div>
+ <div class="gridStyle" ng-grid="allRouters"></div>
</div>
</div>
</script>
<script type="text/ng-template" id="router.html">
<div class="row-fluid">
- <h3>Router {{router.data.title}}</h3>
- <div ng-style="getGridHeight(routerGrid)" ui-grid-auto-resize ui-grid="routerGrid" class="gridStyle noHighlight"></div>
+ <h3>Router {{router.data.title}} attributes</h3>
+ <div class="gridStyle noHighlight" ng-grid="routerGrid"></div>
</div>
</script>
<script type="text/ng-template" id="addresses.html">
<div class="row-fluid">
- <h3>Addresses</h3>
- <div class="overview">
- <div class="gridStyle" ng-style="getGridHeight(addressGrid)" ui-grid-auto-resize ui-grid-selection ui-grid="addressGrid"></div>
- </div>
+ <h3>Addresses</h3>
+ <div class="overview">
+ <div class="gridStyle" ng-grid="addressesGrid"></div>
+ </div>
</div>
</script>
<script type="text/ng-template" id="address.html">
<div class="row-fluid">
- <h3>Address {{address.data.title}}</h3>
- <div ng-style="getGridHeight(addressGrid)" ui-grid-auto-resize class="gridStyle noHighlight" ui-grid="addressGrid"></div>
+ <h3>Address {{address.data.title}}</h3>
+ <div class="gridStyle noHighlight" ng-grid="addressGrid"></div>
+ </div>
+</script>
+<script type="text/ng-template" id="links.html">
+ <div class="row-fluid">
+ <h3>Links</h3>
+ <div class="gridStyle" ng-grid="linksGrid"></div>
+ </div>
+</script>
+<script type="text/ng-template" id="link.html">
+ <div class="row-fluid">
+ <h3>Link {{link.data.title}}</h3>
+ <div class="gridStyle noHighlight" ng-grid="linkGrid"></div>
</div>
</script>
<script type="text/ng-template" id="connections.html">
<div class="row-fluid">
<h3>Connections</h3>
<div class="overview">
- <div class="gridStyle" ng-style="getGridHeight(allConnectionGrid)" ui-grid-auto-resize ui-grid-selection ui-grid="allConnectionGrid"></div>
+ <div class="gridStyle" ng-grid="allConnectionGrid"></div>
</div>
</div>
</script>
<script type="text/ng-template" id="connection.html">
<div class="row-fluid">
- <h3>Connection {{connection.data.title}}</h3>
- <div ng-style="getGridHeight(connectionGrid)" ui-grid-auto-resize class="gridStyle noHighlight" ui-grid="connectionGrid"></div>
+ <ul class="nav nav-tabs">
+ <li ng-repeat="mode in connectionModes" ng-show="isValid(mode)" ng-click="selectMode(mode)" ng-class="{active : isModeSelected(mode)}" title="{{mode.title}}" ng-bind-html-unsafe="mode.content"> </li>
+ </ul>
+ <div ng-show="currentMode.id === 'attributes'" class="selectedItems">
+ <h3>Connection {{connection.data.title}}</h3>
+ <div class="gridStyle noHighlight" ng-grid="connectionGrid"></div>
+ </div>
+ <div ng-show="currentMode.id === 'links'" class="selectedItems">
+ <h3>External links for connection {{connection.data.title}}</h3>
+ <!-- <button title="{{quiesceState.buttonText}} links" type="button" ng-hide="quiesceHide()" ng-class="quiesceClass()" class="btn" ng-click="quiesceAllClicked()" ng-disabled="quiesceState.buttonDisabled">{{quiesceState.buttonText}}</button> -->
+ <div class="gridStyle noHighlight" ng-grid="connectionLinksGrid"></div>
+ </div>
</div>
</script>
+<script type="text/ng-template" id="titleHeaderCellTemplate.html">
+ <div title="{{col.displayName}}" class="ngHeaderSortColumn {{col.headerClass}}" ng-style="{'cursor': col.cursor}" ng-class="{ 'ngSorted': !noSortVisible }">
+ <div ng-click="col.sort($event)" ng-class="'colt' + col.index" class="ngHeaderText">{{col.displayName}}</div>
+ <div class="ngSortButtonDown" ng-show="col.showSortButtonDown()"></div>
+ <div class="ngSortButtonUp" ng-show="col.showSortButtonUp()"></div>
+ <div class="ngSortPriority">{{col.sortPriority}}</div>
+ </div>
+</script>
+<script type="text/ng-template" id="titleCellTemplate.html">
+ <div title="{{row.entity[col.field]}}" class="ngCellText">{{row.entity[col.field]}}</div>
+</script>
<script type="text/ng-template" id="logs.html">
<div class="row-fluid">
<h3>Logs</h3>
@@ -81,3 +119,21 @@ under the License.
<h3>Log {{log.data.title}}</h3>
</div>
</script>
+
+<script type="text/ng-template" id="linkRowTemplate.html">
+ <div ng-class="{linkDirIn: row.getProperty('linkDir') == 'in', linkDirOut: row.getProperty('linkDir') == 'out'}">
+ <div ng-style="{ 'cursor': row.cursor }" ng-repeat="col in renderedColumns" ng-class="col.colIndex()" class="ngCell {{col.cellClass}}">
+ <div class="ngVerticalBar" ng-style="{height: rowHeight}" ng-class="{ ngVerticalBarVisible: !$last }"> </div>
+ <div ng-cell></div>
+ </div>
+ </div>
+</script>
+
+<script type="text/ng-template" id="linkAggTemplate.html">
+ <div ng-click='row.toggleExpand(); saveGroupState()' ng-style='rowStyle(row)' class='ngAggregate ng-scope' style='top: 0px; height: 48px; left: 0px;'>
+ <span class='ngAggregateText ng-binding'>
+ {{row.label CUSTOM_FILTERS}} ({{row.totalChildren()}} {{AggItemsLabel}})
+ </span>
+ <div ng-class="{true: 'ngAggArrowCollapsed', false: 'ngAggArrowExpanded'}[row.collapsed]"></div>
+ </div>
+</script>
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/html/qdrSchema.html
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/html/qdrSchema.html b/console/stand-alone/plugin/html/qdrSchema.html
index 15ebb46..33f6951 100644
--- a/console/stand-alone/plugin/html/qdrSchema.html
+++ b/console/stand-alone/plugin/html/qdrSchema.html
@@ -17,5 +17,5 @@ specific language governing permissions and limitations
under the License.
-->
<div class="main-display row-fluid" ng-controller="QDR.SchemaController">
- <json-formatter json="schema" open="2"></json-formatter>
-</div>
\ No newline at end of file
+ <div id="schema"></div>
+</div>
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/html/qdrTopology.html
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/html/qdrTopology.html b/console/stand-alone/plugin/html/qdrTopology.html
index 2c21b21..3ac2194 100644
--- a/console/stand-alone/plugin/html/qdrTopology.html
+++ b/console/stand-alone/plugin/html/qdrTopology.html
@@ -22,11 +22,11 @@ under the License.
<!-- <div ng-repeat="form in forms" ng-show="isVisible(form)" ng-class='{selected : isSelected(form)}'> -->
<div ng-show="form == 'router'">
<h4>Router Info</h4>
- <div class="topoGrid" ng-style="getTableHeight(attributes)" ui-grid-auto-resize ui-grid="topoGridOptions"></div>
+ <div class="gridStyle" ng-grid="topoGridOptions"></div>
</div>
<div ng-show="form == 'connection'">
<h4>Connection Info</h4>
- <div class="topoGrid" ng-style="getTableHeight(attributes)" ui-grid-auto-resize ui-grid="topoGridOptions"></div>
+ <div class="gridStyle" ng-grid="topoGridOptions"></div>
</div>
<div id="addNodeForm" ng-show="form == 'add'">
<h4>Add a new router</h4>
@@ -74,9 +74,26 @@ under the License.
<div id="svg_legend"></div>
<div id="multiple_details">
<div class="gridStyle" ng-grid="multiDetails"></div>
+ </div>
+ <div id="link_details">
+ <div class="gridStyle" ng-grid="linkDetails"></div>
</div>
</div>
</div>
+
+
+<script type="text/ng-template" id="titleHeaderCellTemplate.html">
+ <div title="{{col.displayName}}" class="ngHeaderSortColumn {{col.headerClass}}" ng-style="{'cursor': col.cursor}" ng-class="{ 'ngSorted': !noSortVisible }">
+ <div ng-click="col.sort($event)" ng-class="'colt' + col.index" class="ngHeaderText">{{col.displayName}}</div>
+ <div class="ngSortButtonDown" ng-show="col.showSortButtonDown()"></div>
+ <div class="ngSortButtonUp" ng-show="col.showSortButtonUp()"></div>
+ <div class="ngSortPriority">{{col.sortPriority}}</div>
+ </div>
+</script>
+<script type="text/ng-template" id="titleCellTemplate.html">
+ <div title="{{row.entity[col.field]}}" class="ngCellText">{{row.entity[col.field]}}</div>
+</script>
+
<!--
This is the template for the node edit dialog that is displayed.
-->
@@ -86,21 +103,21 @@ under the License.
</div>
<div class="modal-body">
<form novalidate name="editForm">
- <div class="tabbable tabs-left">
- <ul class="nav nav-tabs">
- <li ng-repeat="entity in entities" ng-click="setActive(entity.tabName)" ng-class="{separated: entity.tabName == 'listener0'}">
- <a href="#{{entity.tabName}}" data-toggle="tab"><i ng-if="entity.icon !== ''" ng-class="entity.icon ? 'ui-icon-arrowthick-1-w' : 'ui-icon-arrowthick-1-e'" class="ui-icon"></i>{{entity.humanName}}</a>
- </li>
- </ul>
- <div class="tab-content">
- <div id="{{entity.tabName}}" ng-repeat="entity in entities" ng-show="isActive(entity.tabName)" class="entity-fields">
+
+ <tabset vertical="true" class="tabs-left">
+ <tab ng-repeat="entity in entities"> <!-- ng-class="{separated: entity.tabName == 'listener0'}" -->
+ <tab-heading>
+ <i ng-if="entity.icon !== ''" ng-class="entity.icon ? 'ui-icon-arrowthick-1-w' : 'ui-icon-arrowthick-1-e'" class="ui-icon"></i>{{entity.humanName}}
+ </tab-heading>
<div class="entity-description">{{entity.description}}</div>
<fieldset>
<div ng-mouseenter="showDescription(attribute, $event)" ng-repeat="attribute in entity.attributes">
<label for="{{attribute.name}}">{{attribute.humanName}}</label>
+<!-- we can't do <input type="{angular expression}"> because... jquery throws an exception because... -->
<div ng-if="attribute.input == 'input'">
<!-- ng-pattern="testPattern(attribute)" -->
- <input type="{{attribute.type}}" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.value" ng-required="attribute.required" class="ui-widget-content ui-corner-all">
+ <input ng-if="attribute.type == 'number'" type="number" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.value" ng-required="attribute.required" class="ui-widget-content ui-corner-all"/>
+ <input ng-if="attribute.type == 'text'" type="text" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.value" ng-required="attribute.required" class="ui-widget-content ui-corner-all"/>
</div>
<div ng-if="attribute.input == 'select'">
<select id="{{attribute.name}}" ng-model="attribute.selected" ng-options="item for item in attribute.rawtype"></select>
@@ -119,63 +136,16 @@ under the License.
<div class="attr-annotations" ng-repeat="annotation in entity.annotatedBy">
<span>You can also enter the <button ng-click="selectAnnotationTab(annotation)">{{annotation}}</button> values.</span>
</div>
- </div>
- </div>
- </div>
+ </tab>
+ </tabset>
+
+
</form>
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" ng-click="download()">Download</button>
<button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button>
</div>
-
-<!--
-
-
- <div class="nodeOptions" title="Configure new router">
- <form novalidate name="editForm">
- <div id="tabs" class="nodeEntities">
- <ul class="nodeTabs">
- <li ng-repeat="entity in entities" ng-class="{separated: entity.tabName == 'listener0'}">
-
- <a href="#{{entity.tabName}}"><i ng-if="entity.icon !== ''" ng-class="entity.icon ? 'ui-icon-arrowthick-1-w' : 'ui-icon-arrowthick-1-e'" class="ui-icon"></i>{{entity.humanName}}</a>
- </li>
- </ul>
- <div id="{{entity.tabName}}" ng-repeat="entity in entities" class="entity-fields">
- <div class="entity-description">{{entity.description}}</div>
- <fieldset>
- <div ng-mouseenter="showDescription(attribute, $event)" ng-repeat="attribute in entity.attributes">
- <label for="{{attribute.name}}">{{attribute.humanName}}</label>
- <div ng-if="attribute.input == 'input'">
- <input type="{{attribute.type}}" name="{{attribute.name}}" id="{{attribute.name}}" ng-model="attribute.value" ng-pattern="testPattern(attribute)" ng-required="attribute.required" class="ui-widget-content ui-corner-all">
- </div>
- <div ng-if="attribute.input == 'select'">
- <select id="{{attribute.name}}" ng-model="attribute.selected" ng-options="item for item in attribute.rawtype"></select>
- </div>
- <div ng-if="attribute.input == 'boolean'" class="boolean">
- <label><input type="radio" ng-model="attribute.value" value="true"> True</label>
- <label><input type="radio" ng-model="attribute.value" value="false"> False</label>
- </div>
- </div>
- </fieldset>
- <div class="attr-description">{{attributeDescription}}
- <div class="attr-type">{{attributeType}}</div>
- <div class="attr-required">{{attributeRequired}}</div>
- <div class="attr-unique">{{attributeUnique}}</div>
- </div>
- <div class="attr-annotations" ng-repeat="annotation in entity.annotatedBy">
- <span>You can also enter the <button ng-click="selectAnnotationTab(annotation)">{{annotation}}</button> values.</span>
- </div>
- </div>
- </div>
- </form>
-
- <div class="okButton">
- <button ng-click="download()">Download</button>
- <button ng-click="cancel()">Cancel</button>
- </div>
- </div>
- -->
</script>
<script type="text/ng-template" id="config-file-header.html">##
@@ -199,6 +169,32 @@ under the License.
</script>
<script type="text/ng-template" id="download-dialog-template.html">
+ <div class="modal-header">
+ <h3 class="modal-title">Configure new router</h3>
+ </div>
+ <div class="modal-body">
+
+ <label title="Show descriptions and default values in confile files"><input type="checkbox" ng-model="verbose"> Verbose output</label>
+ <div>
+ <button ng-click="download()">Download</button>
+ <button class="btn" zero-clipboard data-clipboard-text="{{output}}" title="Copy to clipboard">
+ <i class="icon-copy"></i>
+ </button> configuration file for {{newRouterName}}
+ </div>
+ <div ng-repeat="part in parts">
+ <button ng-click="downloadPart(part)">Download</button>
+ <button class="btn" zero-clipboard data-clipboard-text="{{part.output}}" title="Copy to clipboard">
+ <i class="icon-copy"></i>
+ </button> connector section for {{part.name}}
+ </div>
+
+ </div>
+ <div class="modal-footer">
+ <button class="btn btn-primary" type="button" ng-click="done()">Done</button>
+ </div>
+
+<!--
+
<div title="Configure new router">
<label title="Show descriptions and default values in confile files"><input type="checkbox" ng-model="verbose"> Verbose output</label>
@@ -220,5 +216,6 @@ under the License.
</div>
</div>
+-->
</script>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[04/11] qpid-dispatch git commit: DISPATCH-316 Hawtio and stand-alone
consoles now use common code
Posted by ea...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/js/qdrList.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrList.js b/console/stand-alone/plugin/js/qdrList.js
index 7352d82..c752a8f 100644
--- a/console/stand-alone/plugin/js/qdrList.js
+++ b/console/stand-alone/plugin/js/qdrList.js
@@ -28,36 +28,105 @@ var QDR = (function(QDR) {
*
* Controller for the main interface
*/
- QDR.module.controller("QDR.ListController", ['$scope', '$location', 'uiGridConstants', 'QDRService', 'QDRChartService', '$uibModal',
- function ($scope, $location, uiGridConstants, QDRService, QDRChartService, $uibModal) {
+ QDR.module.controller("QDR.ListController", ['$scope', '$location', '$dialog', '$filter', 'QDRService', 'QDRChartService',
+ function ($scope, $location, $dialog, $filter, QDRService, QDRChartService) {
- //QDR.log.debug("started List controller");
- if (!angular.isDefined(QDRService.schema))
- return;
- $scope.selectedAction = localStorage['QDRSelectedAction'];
+ var updateIntervalHandle = undefined;
+ var updateInterval = 5000;
+ var ListExpandedKey = "QDRListExpanded";
+ $scope.details = {};
+
+ $scope.tmplListTree = QDR.templatePath + 'tmplListTree.html';
+ $scope.selectedEntity = localStorage['QDRSelectedEntity'] || "address";
$scope.selectedNode = localStorage['QDRSelectedNode'];
$scope.selectedNodeId = localStorage['QDRSelectedNodeId'];
$scope.selectedRecordName = localStorage['QDRSelectedRecordName'];
-
- var excludedEntities = ["management", "org.amqp.management", "operationalEntity", "entity", "configurationEntity", "dummy", "console"];
- var aggregateEntities = ["router.address"];
-
- $scope.entities = [];
- for (var entity in QDRService.schema.entityTypes) {
- if (excludedEntities.indexOf(entity) == -1) {
- $scope.entities.push( {
- title: angular.isDefined(QDRService.schema.entityTypes[entity].description) ? QDRService.schema.entityTypes[entity].description : '',
- humanName: QDRService.humanify(entity),
- name: entity}
- );
+ $scope.nodes = []
+ $scope.currentNode = undefined;
+ $scope.modes = [{
+ content: '<a><i class="icon-list"></i> Attributes</a>',
+ id: 'attributes',
+ op: 'READ',
+ title: "View router attributes",
+ isValid: function () { return true; }
+ },
+ {
+ content: '<a><i class="icon-edit"></i> Update</a>',
+ id: 'operations',
+ op: 'UPDATE',
+ title: "Update this attribute",
+ isValid: function () { return $scope.operations.indexOf(this.op) > -1 }
+ },
+ {
+ content: '<a><i class="icon-plus"></i> Create</a>',
+ id: 'operations',
+ op: 'CREATE',
+ title: "Create a new attribute",
+ isValid: function () { return $scope.operations.indexOf(this.op) > -1 }
+ },
+ {
+ content: '<a><i class="icon-remove"></i> Delete</a>',
+ id: 'delete',
+ op: 'DELETE',
+ title: "Delete",
+ isValid: function () { return $scope.operations.indexOf(this.op) > -1 }
+ },
+ {
+ content: '<a><i class="icon-eye-open"></i> Fetch</a>',
+ id: 'log',
+ op: 'GET-LOG',
+ title: "Fetch recent log entries",
+ isValid: function () { return ($scope.selectedEntity === 'log') }
+ }
+ ];
+ $scope.operations = []
+ $scope.currentMode = $scope.modes[0];
+ $scope.isModeSelected = function (mode) {
+ return mode === $scope.currentMode;
+ }
+ $scope.selectMode = function (mode) {
+ $scope.currentMode = mode;
+ if (mode.id === 'log') {
+ $scope.logResults = "getting recent log entries...";
+ QDRService.sendMethod($scope.currentNode.id, $scope.selectedEntity, {}, $scope.currentMode.op, function (nodeName, entity, response, context) {
+ $scope.logResults = response.filter( function (entry) {
+ return entry[0] === $scope.detailsObject.module
+ }).sort( function (a, b) {
+ return b[5] - a[5]
+ }).map( function (entry) {
+ return {
+ type: entry[1],
+ message: entry[2],
+ source: entry[3],
+ line: entry[4],
+ time: Date(entry[5]).toString()
+ }
+ })
+ $scope.$apply();
+ })
}
}
- if (!angular.isDefined($scope.selectedAction)) {
- $scope.selectedAction = $scope.entities[0].name;
- //QDR.log.debug("defaulted selectedAction to " + $scope.selectedAction);
+ $scope.isValid = function (mode) {
+ return mode.isValid()
}
+ if (!QDRService.connected) {
+ // we are not connected. we probably got here from a bookmark or manual page reload
+ QDRService.redirectWhenConnected("list");
+ return;
+ }
+ // we are currently connected. setup a handler to get notified if we are ever disconnected
+ QDRService.addDisconnectAction( function () {
+ QDRService.redirectWhenConnected("list")
+ $scope.$apply();
+ })
+
$scope.nodes = QDRService.nodeList().sort(function (a, b) { return a.name.toLowerCase() > b.name.toLowerCase()});
+ // unable to get node list? Bail.
+ if ($scope.nodes.length == 0) {
+ $location.path("/" + QDR.pluginName + "/connect")
+ $location.search('org', "list");
+ }
if (!angular.isDefined($scope.selectedNode)) {
//QDR.log.debug("selectedNode was " + $scope.selectedNode);
if ($scope.nodes.length > 0) {
@@ -66,124 +135,417 @@ var QDR = (function(QDR) {
//QDR.log.debug("forcing selectedNode to " + $scope.selectedNode);
}
}
+ var setCurrentNode = function () {
+ $scope.nodes.some( function (node, i) {
+ if (node.name === $scope.selectedNode) {
+ $scope.currentNode = $scope.nodes[i]
+ return true;
+ }
+ })
+ }
+ setCurrentNode();
+ if ($scope.currentNode == undefined) {
+ if ($scope.nodes.length > 0) {
+ $scope.selectedNode = $scope.nodes[0].name;
+ $scope.selectedNodeId = $scope.nodes[0].id;
+ $scope.currentNode = $scope.nodes[0];
+ }
+ }
- $scope.isActionActive = function(name) {
- //QDR.log.debug("isActionActive(" + name + ") selectedAction is " + $scope.selectedAction);
- return $scope.selectedAction === name;
- };
- $scope.isNodeSelected = function (id) {
- return $scope.selectedNodeId === id;
+ var excludedEntities = ["management", "org.amqp.management", "operationalEntity", "entity", "configurationEntity", "dummy", "console"];
+ var aggregateEntities = ["router.address"];
+ var classOverrides = {
+ "connection": function (row) {
+ return row.role.value;
+ },
+ "router.link": function (row) {
+ return row.linkType.value;
+ }
+ }
+
+ var lookupOperations = function () {
+ var ops = QDRService.schema.entityTypes[$scope.selectedEntity].operations.filter( function (op) { return op !== 'READ'});
+ $scope.operation = ops.length ? ops[0] : "";
+ return ops;
+ }
+
+ var entityTreeChildren = [];
+ var expandedList = angular.fromJson(localStorage[ListExpandedKey]) || [];
+ var sortedEntities = Object.keys(QDRService.schema.entityTypes).sort();
+ sortedEntities.forEach( function (entity) {
+ if (excludedEntities.indexOf(entity) == -1) {
+ if (!angular.isDefined($scope.selectedEntity)) {
+ $scope.selectedEntity = entity;
+ $scope.operations = lookupOperations()
+ }
+ var e = new Folder(entity)
+ e.typeName = "entity"
+ e.key = entity
+ e.expand = (expandedList.indexOf(entity) > -1)
+ var placeHolder = new Folder("loading...")
+ placeHolder.addClass = "loading"
+ e.children = [placeHolder]
+ entityTreeChildren.push(e)
+ }
+ })
+ $scope.treeReady = function () {
+ $('#entityTree').dynatree({
+ onActivate: onTreeSelected,
+ onExpand: onTreeNodeExpanded,
+ selectMode: 1,
+ activeVisible: false,
+ debugLevel: 0,
+ children: entityTreeChildren
+ })
+ restartUpdate(); // start getting the data now that the tree is created
+ updateExpandedEntities();
};
+ var onTreeNodeExpanded = function (expanded, node) {
+ // save the list of entities that are expanded
+ var tree = $("#entityTree").dynatree("getTree");
+ var list = [];
+ tree.visit( function (tnode) {
+ if (tnode.isExpanded()) {
+ list.push(tnode.data.key)
+ }
+ })
+ localStorage[ListExpandedKey] = JSON.stringify(list)
+
+ if (expanded)
+ onTreeSelected(node);
+ }
+ // a tree node was selected
+ var onTreeSelected = function (selectedNode) {
+ if ($scope.currentMode.id === 'operations')
+ $scope.currentMode = $scope.modes[0];
+ else if ($scope.currentMode.id === 'log')
+ $scope.selectMode($scope.currentMode)
+ else if ($scope.currentMode.id === 'delete') {
+ // clicked on a tree node while on the delete screen -> switch to attribute screen
+ $scope.currentMode = $scope.modes[0];
+ }
+ if (selectedNode.data.typeName === "entity") {
+ $scope.selectedEntity = selectedNode.data.key;
+ $scope.operations = lookupOperations()
+ } else if (selectedNode.data.typeName === 'attribute') {
+ $scope.selectedEntity = selectedNode.parent.data.key;
+ $scope.operations = lookupOperations()
+ $scope.selectedRecordName = selectedNode.data.key;
+ updateDetails(selectedNode.data.details); // update the table on the right
+ $("#entityTree").dynatree("getRoot").visit(function(node){
+ node.select(false);
+ });
+ selectedNode.select();
+ }
+ $scope.$apply();
+ }
+ // fill in an empty results recoord based on the entities schema
+ var fromSchema = function (entityName) {
+ var row = {}
+ var schemaEntity = QDRService.schema.entityTypes[entityName]
+ for (attr in schemaEntity.attributes) {
+ var entity = schemaEntity.attributes[attr]
+ var value = ""
+ if (angular.isDefined(entity['default']))
+ value = entity['default']
+ row[attr] = {
+ value: value,
+ type: entity.type,
+ graph: false,
+ title: entity.description,
+ aggregate: false,
+ aggregateTip: '',
+ 'default': entity['default']
+ }
+ }
+ return row;
+ }
+ $scope.hasCreate = function () {
+ var schemaEntity = QDRService.schema.entityTypes[$scope.selectedEntity]
+ return (schemaEntity.operations.indexOf("CREATE") > -1)
+ }
+
+ var stopUpdating = function () {
+ if (angular.isDefined(updateIntervalHandle)) {
+ clearInterval(updateIntervalHandle);
+ }
+ updateIntervalHandle = undefined;
+ }
+
+ // the data for the selected entity is available, populate the tree
+ var updateEntityChildren = function (entity, tableRows, expand) {
+ var tree = $("#entityTree").dynatree("getTree");
+ if (!tree.getNodeByKey) {
+ return stopUpdating()
+ }
+ var node = tree.getNodeByKey(entity)
+ var updatedDetails = false;
+ var scrollTreeDiv = $('.qdr-attributes.pane.left .pane-viewport')
+ var scrollTop = scrollTreeDiv.scrollTop();
+ node.removeChildren();
+ if (tableRows.length == 0) {
+ node.addChild({
+ addClass: "no-data",
+ typeName: "none",
+ title: "no data",
+ key: node.data.key + ".1"
+ })
+ if (expand) {
+ updateDetails(fromSchema(entity));
+ $scope.selectedRecordName = entity;
+ }
+ } else {
+ tableRows.forEach( function (row) {
+ var addClass = entity;
+ if (classOverrides[entity]) {
+ addClass += " " + classOverrides[entity](row);
+ }
+ var child = {
+ typeName: "attribute",
+ addClass: addClass,
+ key: row.name.value,
+ title: row.name.value,
+ details: row
+ }
+ if (row.name.value === $scope.selectedRecordName) {
+ if (expand)
+ updateDetails(row); // update the table on the right
+ child.select = true;
+ updatedDetails = true;
+ }
+ node.addChild(child)
+ })
+ }
+ // if the selectedRecordName was not found, select the 1st one
+ if (expand && !updatedDetails && tableRows.length > 0) {
+ var row = tableRows[0];
+ $scope.selectedRecordName = row.name.value;
+ var node = tree.getNodeByKey($scope.selectedRecordName);
+ node.select(true);
+ updateDetails(row) // update the table on the right
+ }
+ scrollTreeDiv.scrollTop(scrollTop)
+ }
+
+ var schemaProps = function (entityName, key, currentNode) {
+ var typeMap = {integer: 'number', string: 'text', path: 'text', boolean: 'boolean', map: 'textarea'};
+
+ var entity = QDRService.schema.entityTypes[entityName]
+ var value = entity.attributes[key]
+ // skip identity and depricated fields
+ if (!value)
+ return {input: 'input', type: 'disabled', required: false, selected: "", rawtype: 'string', disabled: true, 'default': ''}
+ var description = value.description || ""
+ var val = value['default'];
+ var disabled = (key == 'identity' || description.startsWith('Deprecated'))
+ // special cases
+ if (entityName == 'log' && key == 'module') {
+ return {input: 'input', type: 'disabled', required: false, selected: "", rawtype: 'string', disabled: true, 'default': ''}
+ }
+ if (entityName === 'linkRoutePattern' && key === 'connector') {
+ // turn input into a select. the values will be populated later
+ value.type = []
+ // find all the connector names and populate the select
+ QDRService.getNodeInfo(currentNode.id, '.connector', ['name'], function (nodeName, dotentity, response) {
+ $scope.detailFields.some( function (field) {
+ if (field.name === 'connector') {
+ field.rawtype = response.results.map (function (result) {return result[0]})
+ return true;
+ }
+ })
+ });
+ }
+ return { name: key,
+ humanName: QDRService.humanify(key),
+ description:value.description,
+ type: disabled ? 'disabled' : typeMap[value.type],
+ rawtype: value.type,
+ input: typeof value.type == 'string' ? value.type == 'boolean' ? 'boolean' : 'input'
+ : 'select',
+ selected: val ? val : undefined,
+ 'default': value['default'],
+ value: val,
+ required: value.required,
+ unique: value.unique,
+ disabled: disabled
+ };
+ }
+ $scope.getAttributeValue = function (attribute) {
+ var value = attribute.attributeValue;
+ if ($scope.currentMode.op === "CREATE" && attribute.name === 'identity')
+ value = "<assigned by system>"
+ return value;
+ }
+
+ // update the table on the right
+ var updateDetails = function (row) {
+ var details = [];
+ $scope.detailsObject = {};
+ var attrs = Object.keys(row).sort();
+ attrs.forEach( function (attr) {
+ var changed = $scope.detailFields.filter(function (old) {
+ return (old.name === attr) ? old.graph && old.rawValue != row[attr].value : false;
+ })
+ var schemaEntity = schemaProps($scope.selectedEntity, attr, $scope.currentNode)
+ details.push( {
+ attributeName: QDRService.humanify(attr),
+ attributeValue: attr === 'port' ? row[attr].value : QDRService.pretty(row[attr].value),
+ name: attr,
+ changed: changed.length,
+ rawValue: row[attr].value,
+ graph: row[attr].graph,
+ title: row[attr].title,
+ aggregateValue: QDRService.pretty(row[attr].aggregate),
+ aggregateTip: row[attr].aggregateTip,
+
+ input: schemaEntity.input,
+ type: schemaEntity.type,
+ required: schemaEntity.required,
+ selected: schemaEntity.selected,
+ rawtype: schemaEntity.rawtype,
+ disabled: schemaEntity.disabled,
+ 'default': schemaEntity['default']
+ })
+ $scope.detailsObject[attr] = row[attr].value;
+ })
+ setTimeout(applyDetails, 1, details)
+ }
+
+ var applyDetails = function (details) {
+ $scope.detailFields = details;
+ aggregateColumn();
+ $scope.$apply();
+ // ng-grid bug? the entire table doesn't always draw unless a reflow is triggered;
+ $(window).trigger('resize');
+ }
+
+ var restartUpdate = function () {
+ stopUpdating();
+ updateTableData($scope.selectedEntity, true);
+ updateIntervalHandle = setInterval(updateExpandedEntities, updateInterval);
+ }
+ var updateExpandedEntities = function () {
+ var tree = $("#entityTree").dynatree("getTree");
+ if (tree.visit) {
+ tree.visit( function (node) {
+ if (node.isExpanded()) {
+ updateTableData(node.data.key, node.data.key === $scope.selectedEntity)
+ }
+ })
+ } else {
+ stopUpdating();
+ }
+ }
$scope.selectNode = function(node) {
- //QDR.log.debug("setting selectedNode to " + node.name);
$scope.selectedNode = node.name;
$scope.selectedNodeId = node.id;
- //QDR.log.debug("location is " + $location.url());
- $location.search('n', node.name);
- };
- $scope.selectAction = function(action) {
- $scope.selectedAction = action;
- $location.search('a', action);
- //QDR.log.debug("selectAction called with " + action + " location is now " + $location.url());
+ setCurrentNode();
+ restartUpdate();
};
-
- $scope.$watch('selectedAction', function(newValue, oldValue) {
+ $scope.$watch('selectedEntity', function(newValue, oldValue) {
if (newValue !== oldValue) {
- localStorage['QDRSelectedAction'] = $scope.selectedAction;
- //QDR.log.debug("saving selectedAction as " + $scope.selectedAction + " newValue is " + newValue);
+ localStorage['QDRSelectedEntity'] = $scope.selectedEntity;
+ restartUpdate();
+ $scope.operations = lookupOperations()
}
})
$scope.$watch('selectedNode', function(newValue, oldValue) {
if (newValue !== oldValue) {
localStorage['QDRSelectedNode'] = $scope.selectedNode;
localStorage['QDRSelectedNodeId'] = $scope.selectedNodeId;
- //QDR.log.debug("saving selectedNode as " + $scope.selectedNode + " newValue is " + newValue);
}
})
$scope.$watch('selectedRecordName', function(newValue, oldValue) {
if (newValue != oldValue) {
localStorage['QDRSelectedRecordName'] = $scope.selectedRecordName;
- //QDR.log.debug("saving selectedRecordName as " + $scope.selectedRecordName);
}
})
- $scope.tableRows = [];
- var selectedRowIndex = 0;
- var updateTableData = function (entity) {
- var gotNodeInfo = function (nodeName, dotentity, response) {
- //QDR.log.debug("got results for " + nodeName);
- //console.dump(response);
+ /* Called periodically to refresh the data on the page */
+ var updateTableData = function (entity, expand) {
+ if (!QDRService.connected) {
+ // we are no longer connected. bail back to the connect page
+ $location.path("/" + QDR.pluginName + "/connect")
+ $location.search('org', "list");
+ return;
+ }
+ // don't update the data when on the operations tab
+ if ($scope.currentMode.id === 'operations') {
+ return;
+ }
+ var gotNodeInfo = function (nodeName, dotentity, response) {
+ var tableRows = [];
var records = response.results;
var aggregates = response.aggregates;
var attributeNames = response.attributeNames;
- var nameIndex = attributeNames.indexOf("name");
- var ent = QDRService.schema.entityTypes[entity];
- var tableRows = [];
- for (var i=0; i<records.length; ++i) {
- var record = records[i];
- var aggregate = aggregates ? aggregates[i] : undefined;
- var row = {};
- var rowName;
- if (nameIndex > -1) {
- rowName = record[nameIndex];
- } else {
- QDR.log.error("response attributeNames did not contain a name field");
- console.dump(response.attributeNames);
- return;
- }
- if (rowName == $scope.selectedRecordName)
- selectedRowIndex = i;
- for (var j=0; j<attributeNames.length; ++j) {
- var col = attributeNames[j];
- row[col] = {value: record[j], type: undefined, graph: false, title: '', aggregate: '', aggregateTip: ''};
- if (ent) {
- var att = ent.attributes[col];
- if (att) {
- row[col].type = att.type;
- row[col].graph = att.graph;
- row[col].title = att.description;
-
- if (aggregate) {
- if (att.graph) {
- row[col].aggregate = att.graph ? aggregate[j].sum : '';
- var tip = [];
- aggregate[j].detail.forEach( function (line) {
- tip.push(line);
- })
- row[col].aggregateTip = angular.toJson(tip);
+ // If !attributeNmes then there was an error getting the records for this entity
+ if (attributeNames) {
+ var nameIndex = attributeNames.indexOf("name");
+ var identityIndex = attributeNames.indexOf("identity");
+ var ent = QDRService.schema.entityTypes[entity];
+ for (var i=0; i<records.length; ++i) {
+ var record = records[i];
+ var aggregate = aggregates ? aggregates[i] : undefined;
+ var row = {};
+ var rowName;
+ if (nameIndex > -1) {
+ rowName = record[nameIndex];
+ if (!rowName && identityIndex > -1) {
+ rowName = record[nameIndex] = (dotentity + '/' + record[identityIndex])
+ }
+ }
+ if (!rowName) {
+ QDR.log.error("response attributeNames did not contain a name field");
+ console.dump(response.attributeNames);
+ return;
+ }
+ for (var j=0; j<attributeNames.length; ++j) {
+ var col = attributeNames[j];
+ row[col] = {value: record[j], type: undefined, graph: false, title: '', aggregate: '', aggregateTip: ''};
+ if (ent) {
+ var att = ent.attributes[col];
+ if (att) {
+ row[col].type = att.type;
+ row[col].graph = att.graph;
+ row[col].title = att.description;
+
+ if (aggregate) {
+ if (att.graph) {
+ row[col].aggregate = att.graph ? aggregate[j].sum : '';
+ var tip = [];
+ aggregate[j].detail.forEach( function (line) {
+ tip.push(line);
+ })
+ row[col].aggregateTip = angular.toJson(tip);
+ }
}
}
}
}
+ tableRows.push(row);
}
- tableRows.push(row);
}
- setTimeout(selectRow, 0, tableRows);
- }
+ tableRows.sort( function (a, b) { return a.name.value.localeCompare(b.name.value) })
+ setTimeout(selectRow, 0, {entity: dotentity, rows: tableRows, expand: expand});
+ }
// if this entity should show an aggregate column, send the request to get the info for this entity from all the nedes
if (aggregateEntities.indexOf(entity) > -1) {
var nodeInfo = QDRService.topology.nodeInfo();
QDRService.getMultipleNodeInfo(Object.keys(nodeInfo), entity, [], gotNodeInfo, $scope.selectedNodeId);
} else {
- QDRService.getNodeInfo($scope.selectedNodeId, '.' + entity, [], gotNodeInfo);
+ QDRService.getNodeInfo($scope.selectedNodeId, entity, [], gotNodeInfo);
}
};
// tableRows are the records that were returned, this populates the left hand table on the page
- var selectRow = function (tableRows) {
- $scope.tableRows = tableRows;
- // must apply scope here to update the tableRows before selecting the row
- $scope.$apply();
- $scope.gridApi.selection.selectRow($scope.tableRows[selectedRowIndex]);
+ var selectRow = function (info) {
+ updateEntityChildren(info.entity, info.rows, info.expand);
fixTooltips();
}
- $scope.getTableHeight = function() {
- return {height: ($scope.tableRows.length * 30) + "px"};
- };
var titleFromAlt = function (alt) {
if (alt && alt.length) {
var data = angular.fromJson(alt);
@@ -214,261 +576,144 @@ var QDR = (function(QDR) {
var title = titleFromAlt(tip.getAttribute('alt'))
tip.setAttribute('original-title', title)
}
-/*
- $(tip).tipsy({html: true, className: 'subTip', opacity: 1, title: function () {
- var alt = this.getAttribute('alt');
- if (alt && alt.length) {
- var data = angular.fromJson(alt);
- var table = "<table class='tiptable'><tbody>";
- data.forEach (function (row) {
- table += "<tr>";
- table += "<td>" + row.node + "</td><td align='right'>" + QDRService.pretty(row.val) + "</td>";
- table += "</tr>"
- })
- table += "</tbody></table>"
- return table;
- }
- return '';
- } });
- */
})
}
- $scope.selectedEntity = undefined;
- for (var i=0; i<$scope.entities.length; ++i) {
- if ($scope.selectedAction === $scope.entities[i].name) {
- $scope.selectedEntity = $scope.entities[i].name;
- break;
- }
- }
- if (!angular.isDefined($scope.selectedEntity)) {
- $scope.selectedAction = $scope.entities[0].name;
- $scope.selectedEntity = $scope.entities[0].name;
- }
- var savedCharts = angular.fromJson(localStorage['QDRListCharts']);
- var getCurrentSavedCharts = function () {
- if (angular.isDefined(savedCharts)) {
- if (angular.isDefined(savedCharts[$scope.selectedEntity])) {
- //graphFields = savedCharts[$scope.selectedEntity];
- }
- } else {
- savedCharts = {};
- }
- }
- getCurrentSavedCharts();
-
- //QDR.log.debug("using entity of " + $scope.selectedEntity);
- var stop = undefined;
-
- // The left-hand table that lists the names
- var gridCols = [
- { field: 'name',
- displayName: '',
- cellTemplate: '<div class="ngCellText"><span ng-cell-text>{{row.entity.name.value}}</span></div>'
- }
- ];
- // the table on the left of the page contains the name field for each record that was returned
- $scope.gridDef = {
- data: 'tableRows',
- hideHeader: true,
- showHeader: false,
- enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
- enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
- columnDefs: gridCols,
- enableColumnResize: true,
- multiSelect: false,
- enableRowHeaderSelection: false,
- noUnselect: true,
- enableSelectAll: false,
- enableRowSelection: true,
- onRegisterApi: function (gridApi) {
- $scope.gridApi = gridApi;
- gridApi.selection.on.rowSelectionChanged($scope, function(row) {
- if (row.isSelected) {
- selectedRowIndex = row.rowIndex;
- $scope.selectedRecordName = row.entity.name.value;
- var details = [];
- // for each field in the new row, add a row in the details grid
- for (var name in row.entity) {
- details.push( { attributeName: QDRService.humanify(name),
- attributeValue: QDRService.pretty(row.entity[name].value),
- type: row.entity[name].type,
- name: name,
- rawValue: row.entity[name].value,
- graph: row.entity[name].graph,
- title: row.entity[name].title,
- aggregateValue: QDRService.pretty(row.entity[name].aggregate),
- aggregateTip: row.entity[name].aggregateTip})
- }
- setTimeout(updateDetails, 10, details);
- }
- });
- }
- };
$scope.detailFields = [];
- updateDetails = function (details) {
- $scope.detailFields = details;
- $scope.$apply();
- }
-
- $scope.isFieldGraphed = function(rowEntity, aggregate) {
- var dot = !aggregate ? '.' : '';
- return QDRChartService.isAttrCharted($scope.selectedNodeId, dot + $scope.selectedEntity, $scope.selectedRecordName, rowEntity.name);
- }
$scope.addToGraph = function(rowEntity) {
- var chart = QDRChartService.registerChart($scope.selectedNodeId, "." + $scope.selectedEntity, $scope.selectedRecordName, rowEntity.name, 1000);
- doDialog("template-from-script.html", chart);
- reset();
+ var chart = QDRChartService.registerChart(
+ {nodeId: $scope.selectedNodeId,
+ entity: "." + $scope.selectedEntity,
+ name: $scope.selectedRecordName,
+ attr: rowEntity.name,
+ forceCreate: true});
+ doDialog(chart);
}
$scope.addAllToGraph = function(rowEntity) {
- var chart = QDRChartService.registerChart($scope.selectedNodeId,
- $scope.selectedEntity,
- $scope.selectedRecordName,
- rowEntity.name,
- 1000,
- false,
- true);
- doDialog("template-from-script.html", chart);
- reset();
+ var chart = QDRChartService.registerChart({
+ nodeId: $scope.selectedNodeId,
+ entity: $scope.selectedEntity,
+ name: $scope.selectedRecordName,
+ attr: rowEntity.name,
+ type: "rate",
+ rateWindow: udateInterval,
+ visibleDuration: 1,
+ forceCreate: true,
+ aggregate: true});
+ doDialog(chart);
}
- var detailCols = [
- {
- field: 'attributeName',
- cellTemplate: '<div title="{{row.entity.title}}" class="listAttrName">{{row.entity.name}}<i ng-if="row.entity.graph" ng-click="grid.appScope.addToGraph(row.entity)" ng-class="{\'active\': grid.appScope.isFieldGraphed(row.entity, false), \'icon-bar-chart\': row.entity.graph == true }"></i></div>',
- displayName: 'Attribute'
- },
- {
- field: 'attributeValue',
- displayName: 'Value'
- }
- ];
- if (aggregateEntities.indexOf($scope.selectedEntity) > -1) {
- detailCols.push(
- {
- width: '10%',
- field: 'aggregateValue',
- displayName: 'Aggregate',
- cellTemplate: '<div class="hastip" alt="{{row.entity.aggregateTip}}">{{row.entity.aggregateValue}}<i ng-if="row.entity.graph" ng-click="grid.appScope.addAllToGraph(row.entity)" ng-class="{\'active\': grid.appScope.isFieldGraphed(row.entity, true), \'icon-bar-chart\': row.entity.graph == true }"></i></div>',
- cellClass: 'aggregate'
- }
- )
+ $scope.detailCols = [];
+ var aggregateColumn = function () {
+ if ((aggregateEntities.indexOf($scope.selectedEntity) > -1 && $scope.detailCols.length != 3) ||
+ (aggregateEntities.indexOf($scope.selectedEntity) == -1 && $scope.detailCols.length != 2)) {
+ // column defs have to be reassigned and not spliced, so no push/pop
+ $scope.detailCols = [
+ {
+ field: 'attributeName',
+ displayName: 'Attribute',
+ cellTemplate: '<div title="{{row.entity.title}}" class="listAttrName">{{row.entity[col.field]}}<i ng-if="row.entity.graph" ng-click="addToGraph(row.entity)" ng-class="{\'icon-bar-chart\': row.entity.graph == true }"></i></div>'
+ },
+ {
+ field: 'attributeValue',
+ displayName: 'Value',
+ cellTemplate: '<div class="ngCellText" ng-class="{\'changed\': row.entity.changed == 1}"><span>{{row.getProperty(col.field)}}</span></div>'
+ }
+ ]
+ if (aggregateEntities.indexOf($scope.selectedEntity) > -1) {
+ $scope.detailCols.push(
+ {
+ width: '10%',
+ field: 'aggregateValue',
+ displayName: 'Aggregate',
+ cellTemplate: '<div class="hastip" alt="{{row.entity.aggregateTip}}"><span ng-class="{\'changed\': row.entity.changed == 1}">{{row.entity[col.field]}}</span><i ng-if="row.entity.graph" ng-click="addAllToGraph(row.entity)" ng-class="{\'icon-bar-chart\': row.entity.graph == true }"></i></div>',
+ cellClass: 'aggregate'
+ }
+ )
+ }
+ }
+ if ($scope.selectedRecordName === "")
+ $scope.detailCols = [];
}
// the table on the right of the page contains a row for each field in the selected record in the table on the left
$scope.details = {
data: 'detailFields',
- columnDefs: detailCols,
- enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
- enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
+ columnDefs: "detailCols",
enableColumnResize: true,
multiSelect: false,
- enableRowHeaderSelection: false,
- noUnselect: true,
- enableSelectAll: false,
- enableRowSelection: true
+ beforeSelectionChange: function() {
+ return false;
+ }
};
-
- updateTableData($scope.selectedEntity);
- stop = setInterval(updateTableData, 5000, $scope.selectedEntity);
- $scope.getDetailsTableHeight = function() {
- return {height: ($scope.detailFields.length * 30) + "px"};
- };
-
$scope.$on("$destroy", function( event ) {
//QDR.log.debug("scope destroyed for qdrList");
- reset();
- if (angular.isDefined(stop)) {
- clearInterval(stop);
- stop = undefined;
- };
+ stopUpdating();
});
- var reset = function () {
- if ($scope.context) {
- $scope.context.stop();
- $scope.context = null;
+ function gotMethodResponse (nodeName, entity, response, context) {
+ var statusCode = context.message.application_properties.statusCode;
+ if (statusCode < 200 || statusCode >= 300) {
+ Core.notification('error', context.message.application_properties.statusDescription);
+ //QDR.log.debug(context.message.application_properties.statusDescription)
+ } else {
+ var note = entity + " " + $filter('Pascalcase')($scope.currentMode.op) + "d"
+ Core.notification('success', note);
+ $scope.selectMode($scope.modes[0]);
+ restartUpdate();
}
- };
+ }
+ $scope.ok = function () {
+ var attributes = {}
+ $scope.detailFields.forEach( function (field) {
+ var value = field.rawValue;
+ if (field.input === 'input') {
+ if (field.type === 'text' || field.type === 'disabled')
+ value = field.attributeValue;
+ } else if (field.input === 'select') {
+ value = field.selected;
+ } else if (field.input === 'boolean') {
+ value = field.rawValue
+ }
+ if (value === "")
+ value = undefined;
- function doDialog(template, chart) {
+ if ((value && value != field['default']) || field.required || (field.name === 'role')) {
+ if (field.name !== 'identity')
+ attributes[field.name] = value
+ }
+ })
+ QDRService.sendMethod($scope.currentNode.id, $scope.selectedEntity, attributes, $scope.currentMode.op, gotMethodResponse)
+ }
+ $scope.remove = function () {
+ var attributes = {type: $scope.selectedEntity, name: $scope.selectedRecordName}
+ QDRService.sendMethod($scope.currentNode.id, $scope.selectedEntity, attributes, $scope.currentMode.op, gotMethodResponse)
+ }
- var modalInstance = $uibModal.open({
- animation: true,
- templateUrl: template,
- controller: 'QDR.ListChartController',
+ function doDialog(chart) {
+ var d = $dialog.dialog({
+ backdrop: true,
+ keyboard: true,
+ backdropClick: true,
+ templateUrl: QDR.templatePath + 'tmplListChart.html',
+ controller: "QDR.ListChartController",
resolve: {
- chart: function () {
- return chart;
- }
- }
+ chart: function() {
+ return chart
+ },
+ nodeName: function () {
+ return $scope.selectedNode
+ }
+ }
});
- };
-
- }]);
+ d.open().then(function(result) { console.log("d.open().then"); });
- QDR.module.controller('QDR.ListChartController', function ($scope, $uibModalInstance, $location, QDRChartService, chart) {
-
- $scope.chart = chart;
- $scope.dialogSvgChart = null;
- $scope.updateTimer = null;
- $scope.svgDivId = "dialogChart"; // the div id for the svg chart
-
- $scope.showChartsPage = function () {
- cleanup();
- $uibModalInstance.close();
- $location.path("/charts");
- };
-
- $scope.addChartsPage = function () {
- QDRChartService.addDashboard($scope.chart);
- };
-
- $scope.delChartsPage = function () {
- QDRChartService.delDashboard($scope.chart);
};
+ }]);
- $scope.isOnChartsPage = function () {
- return $scope.chart.dashboard;
- }
-
- var showChart = function () {
- // the chart divs are generated by angular and aren't available immediately
- var div = angular.element("#" + $scope.svgDivId);
- if (!div.width()) {
- setTimeout(showChart, 100);
- return;
- }
- dialogSvgChart = new QDRChartService.AreaChart($scope.chart, $location.$$path);
- $scope.dialogSvgChart = dialogSvgChart;
- updateDialogChart();
- }
- showChart();
-
- var updateDialogChart = function () {
- if ($scope.dialogSvgChart)
- $scope.dialogSvgChart.tick($scope.svgDivId);
- $scope.updateTimer = setTimeout(updateDialogChart, 1000);
- }
-
- var cleanup = function () {
- if ($scope.updateTimer) {
- clearTimeout($scope.updateTimer);
- $scope.updateTimer = null;
- }
- if (!$scope.chart.dashboard)
- QDRChartService.unRegisterChart(chart); // remove the chart
-
- }
- $scope.ok = function () {
- cleanup();
- $uibModalInstance.close();
- };
-
- });
return QDR;
} (QDR || {}));
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/js/qdrListChart.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrListChart.js b/console/stand-alone/plugin/js/qdrListChart.js
new file mode 100644
index 0000000..e654b19
--- /dev/null
+++ b/console/stand-alone/plugin/js/qdrListChart.js
@@ -0,0 +1,109 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you 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.
+*/
+/**
+ * @module QDR
+ */
+var QDR = (function(QDR) {
+
+ QDR.module.controller('QDR.ListChartController', function ($scope, dialog, $dialog, $location, QDRChartService, chart, nodeName) {
+ $scope.chart = chart;
+ $scope.dialogSvgChart = null;
+ var updateTimer = null;
+ $scope.svgDivId = "dialogChart"; // the div id for the svg chart
+
+ $scope.showChartsPage = function () {
+ cleanup();
+ dialog.close(true);
+ $location.path(QDR.pluginRoot + "/charts");
+ };
+
+ $scope.addHChart = function () {
+ QDRChartService.addHDash($scope.chart);
+ cleanup();
+ dialog.close(true);
+ }
+
+ $scope.addToDashboardLink = function () {
+ var href = "#/" + QDR.pluginName + "/charts";
+ var size = angular.toJson({
+ size_x: 2,
+ size_y: 2
+ });
+
+ var params = angular.toJson({chid: $scope.chart.id()});
+ var title = "Dispatch - " + nodeName;
+ return "/hawtio/#/dashboard/add?tab=dashboard" +
+ "&href=" + encodeURIComponent(href) +
+ "&routeParams=" + encodeURIComponent(params) +
+ "&title=" + encodeURIComponent(title) +
+ "&size=" + encodeURIComponent(size);
+ };
+
+
+ $scope.addChartsPage = function () {
+ QDRChartService.addDashboard($scope.chart);
+ };
+
+ $scope.delChartsPage = function () {
+ QDRChartService.delDashboard($scope.chart);
+ };
+
+ $scope.isOnChartsPage = function () {
+ return $scope.chart.dashboard;
+ }
+
+ var showChart = function () {
+ // the chart divs are generated by angular and aren't available immediately
+ var div = angular.element("#" + $scope.svgDivId);
+ if (!div.width()) {
+ setTimeout(showChart, 100);
+ return;
+ }
+ dialogSvgChart = new QDRChartService.AreaChart($scope.chart);
+ $scope.dialogSvgChart = dialogSvgChart;
+ updateDialogChart();
+ }
+ showChart();
+
+ var updateDialogChart = function () {
+ if ($scope.dialogSvgChart)
+ $scope.dialogSvgChart.tick($scope.svgDivId);
+ if (updateTimer)
+ clearTimeout(updateTimer)
+ updateTimer = setTimeout(updateDialogChart, 1000);
+ }
+
+ var cleanup = function () {
+ if (updateTimer) {
+ clearTimeout(updateTimer);
+ updateTimer = null;
+ }
+ if (!$scope.chart.hdash && !$scope.chart.dashboard)
+ QDRChartService.unRegisterChart($scope.chart); // remove the chart
+
+ }
+ $scope.ok = function () {
+ cleanup();
+ dialog.close(true);
+ };
+
+ });
+ return QDR;
+
+} (QDR || {}));
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[09/11] qpid-dispatch git commit: DISPATCH-316 Hawtio and stand-alone
consoles now use common code
Posted by ea...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js b/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js
deleted file mode 100644
index aad0cdf..0000000
--- a/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js
+++ /dev/null
@@ -1,1426 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
-*/
-/**
- * @module QDR
- */
-/**
- * @module QDR
- */
-var QDR = (function (QDR) {
-
- /**
- * @method OverviewController
- * @param $scope
- * @param QDRService
- * @param QDRChartServer
- * dialogServer
- * $location
- *
- * Controller that handles the QDR overview page
- */
- QDR.module.controller("QDR.OverviewController", ['$scope', 'QDRService', '$location', 'localStorage', '$timeout', function($scope, QDRService, $location, localStorage, $timeout) {
-
- console.log("QDR.OverviewControll started with location of " + $location.path() + " and connection of " + QDRService.connected);
- var columnStateKey = 'QDRColumnKey.';
- var OverviewExpandedKey = "QDROverviewExpanded"
- var OverviewActivatedKey = "QDROverviewActivated"
-
- // we want attributes to be listed first, so add it at index 0
- $scope.subLevelTabs = [{
- content: '<i class="icon-list"></i> Attributes',
- title: "View the attribute values on your selection",
- isValid: function (workspace) { return true; },
- href: function () { return "#/" + QDR.pluginName + "/attributes"; },
- index: 0
- },
- {
- content: '<i class="icon-leaf"></i> Operations',
- title: "Execute operations on your selection",
- isValid: function (workspace) { return true; },
- href: function () { return "#/" + QDR.pluginName + "/operations"; },
- index: 1
- }]
- $scope.activeTab = $scope.subLevelTabs[0];
- $scope.setActive = function (nav) {
- $scope.activeTab = nav;
- }
- $scope.isValid = function (nav) {
- return nav.isValid()
- }
- $scope.isActive = function (nav) {
- return nav == $scope.activeTab;
- }
- $scope.linkFields = []
- $scope.link = null;
- var refreshInterval = 5000
- $scope.modes = [
- {title: 'Overview', name: 'Overview', right: false}
- ];
-
- $scope.templates =
- [ { name: 'Routers', url: 'routers.html'},
- { name: 'Router', url: 'router.html'},
- { name: 'Addresses', url: 'addresses.html'},
- { name: 'Address', url: 'address.html'},
- { name: 'Links', url: 'links.html'},
- { name: 'Link', url: 'link.html'},
- { name: 'Connections', url: 'connections.html'},
- { name: 'Connection', url: 'connection.html'},
- { name: 'Logs', url: 'logs.html'},
- { name: 'Log', url: 'log.html'}
- ];
- var topLevelChildren = [];
-
- $scope.allRouterSelected = function (row ) {
- console.log("row selected" + row)
- }
- function afterSelectionChange(rowItem, checkAll) {
- var nodeId = rowItem.entity.nodeId;
- $("#overtree").dynatree("getTree").activateKey(nodeId);
- }
-
- $scope.allRouterFields = [];
- $scope.allRouterSelections = [];
- $scope.allRouters = {
- saveKey: 'allRouters',
- data: 'allRouterFields',
- columnDefs: [
- {
- field: 'routerId',
- saveKey: 'allRouters',
- displayName: 'Router'
- },
- {
- field: 'area',
- displayName: 'Area'
- },
- {
- field: 'mode',
- displayName: 'Mode'
- },
- {
- field: 'connections',
- displayName: 'External connections'
- },
- {
- field: 'addrCount',
- displayName: 'Address count'
- },
- {
- field: 'linkCount',
- displayName: 'Link count'
- }
- ],
- enableColumnResize: true,
- multiSelect: false,
- selectedItems: $scope.allRouterSelections,
- afterSelectionChange: function(data) {
- if (data.selected) {
- var selItem = $scope.allRouterSelections[0]
- var nodeId = selItem.nodeId
- // activate Routers->nodeId in the tree
- $("#overtree").dynatree("getTree").activateKey(nodeId);
-
- }
- }
- };
-
- // get info for all routers
- var allRouterInfo = function () {
- var nodeIds = QDRService.nodeIdList()
- var expected = Object.keys(nodeIds).length
- var received = 0;
- var allRouterFields = [];
- var gotNodeInfo = function (nodeName, entity, response) {
- var results = response.results;
- var name = QDRService.nameFromId(nodeName)
- var connections = 0;
- results.forEach( function (result) {
- var role = QDRService.valFor(response.attributeNames, result, "role")
- if (role != 'inter-router') {
- ++connections
- }
- })
- allRouterFields.push({routerId: name, connections: connections, nodeId: nodeName})
- ++received
- if (expected == received) {
- allRouterFields.sort ( function (a,b) { return a.routerId < b.routerId ? -1 : a.routerId > b.routerId ? 1 : 0})
- // now get each router's node info
- QDRService.getMultipleNodeInfo(nodeIds, "router", [], function (nodeIds, entity, responses) {
- for(var r in responses) {
- var result = responses[r]
- var routerId = QDRService.valFor(result.attributeNames, result.results[0], "routerId")
- allRouterFields.some( function (connField) {
- if (routerId === connField.routerId) {
- result.attributeNames.forEach ( function (attrName) {
- connField[attrName] = QDRService.valFor(result.attributeNames, result.results[0], attrName)
- })
- return true
- }
- return false
- })
- }
- $scope.allRouterFields = allRouterFields
- }, nodeIds[0], false)
- }
- }
- nodeIds.forEach ( function (nodeId, i) {
- QDRService.getNodeInfo(nodeId, ".connection", ["role"], gotNodeInfo)
- })
- loadColState($scope.allRouters)
- updateRouterTree(nodeIds)
- }
-
- $scope.routerFields = []
- $scope.routerGrid = {
- saveKey: 'routerGrid',
- data: 'routerFields',
- columnDefs: [
- {
- field: 'attribute',
- displayName: 'Attribute',
- saveKey: 'routerGrid',
- width: '40%'
- },
- {
- field: 'value',
- displayName: 'Value',
- width: '40%'
- }
- ],
- enableColumnResize: true,
- multiSelect: false
- }
-
- // get info for a single router
- var routerInfo = function (node) {
- $scope.router = node
-
- $scope.routerFields = [];
- $scope.allRouterFields.some( function (field) {
- if (field.routerId === node.data.title) {
- Object.keys(field).forEach ( function (key) {
- if (key !== '$$hashKey')
- $scope.routerFields.push({attribute: key, value: field[key]})
- })
- return true
- }
- })
- loadColState($scope.routerGrid);
- }
-
- $scope.addressesData = []
- $scope.selectedAddresses = []
- $scope.addressesGrid = {
- saveKey: 'addressesGrid',
- data: 'addressesData',
- columnDefs: [
- {
- field: 'address',
- saveKey: 'addressesGrid',
- displayName: 'address'
- },
- {
- field: 'class',
- displayName: 'class'
- },
- {
- field: 'phase',
- displayName: 'phase',
- cellClass: 'grid-align-value'
- },
- {
- field: 'inproc',
- displayName: 'in-proc'
- },
- {
- field: 'local',
- displayName: 'local',
- cellClass: 'grid-align-value'
- },
- {
- field: 'remote',
- displayName: 'remote',
- cellClass: 'grid-align-value'
- },
- {
- field: 'in',
- displayName: 'in',
- cellClass: 'grid-align-value'
- },
- {
- field: 'out',
- displayName: 'out',
- cellClass: 'grid-align-value'
- }
- ],
- enableColumnResize: true,
- multiSelect: false,
- selectedItems: $scope.selectedAddresses,
- afterSelectionChange: function(data) {
- if (data.selected) {
- var selItem = data.entity;
- var nodeId = selItem.uid
- $("#overtree").dynatree("getTree").activateKey(nodeId);
- }
- }
- };
-
- // get info for all addresses
- var allAddressInfo = function () {
- var gotAllAddressFields = function ( addressFields ) {
- // update the grid's data
- addressFields.sort ( function (a,b) { return a.address < b.address ? -1 : a.address > b.address ? 1 : 0})
- addressFields[0].title = addressFields[0].address
- for (var i=1; i<addressFields.length; ++i) {
- if (addressFields[i].address === addressFields[i-1].address) {
- addressFields[i-1].title = addressFields[i-1].address + " (" + addressFields[i-1]['class'] + ")"
- addressFields[i].title = addressFields[i].address + " (" + addressFields[i]['class'] + ")"
- } else
- addressFields[i].title = addressFields[i].address
- }
- $scope.addressesData = addressFields
-
- // repopulate the tree's child nodes
- updateAddressTree(addressFields)
- }
- getAllAddressFields(gotAllAddressFields)
- loadColState($scope.addressesGrid);
- }
-
- var getAllAddressFields = function (callback) {
- var nodeIds = QDRService.nodeIdList()
- var addr_class = function (addr) {
- if (!addr) return "-"
- if (addr[0] == 'M') return "mobile"
- if (addr[0] == 'R') return "router"
- if (addr[0] == 'A') return "area"
- if (addr[0] == 'L') return "local"
- if (addr[0] == 'C') return "link-incoming"
- if (addr[0] == 'D') return "link-outgoing"
- return "unknown: " + addr[0]
- }
-
- var addr_text = function (addr) {
- if (!addr)
- return "-"
- if (addr[0] == 'M')
- return addr.substring(2)
- else
- return addr.substring(1)
- }
-
- var addr_phase = function (addr) {
- if (!addr)
- return "-"
- if (addr[0] == 'M')
- return addr[1]
- return ''
- }
-
- var identity_clean = function (identity) {
- if (!identity)
- return "-"
- var pos = identity.indexOf('/')
- if (pos >= 0)
- return identity.substring(pos + 1)
- return identity
- }
-
- var addressFields = []
- QDRService.getMultipleNodeInfo(nodeIds, "router.address", [], function (nodeIds, entity, response) {
- response.aggregates.forEach( function (result) {
- var prettySum = function (field) {
- var fieldIndex = response.attributeNames.indexOf(field)
- if (fieldIndex < 0) {
- return "-"
- }
- var val = result[fieldIndex].sum
- return QDRService.pretty(val)
- }
-
- var uid = QDRService.valFor(response.attributeNames, result, "identity").sum
- var identity = identity_clean(uid)
-
- addressFields.push({
- address: addr_text(identity),
- 'class': addr_class(identity),
- phase: addr_phase(identity),
- inproc: prettySum("inProcess"),
- local: prettySum("subscriberCount"),
- remote: prettySum("remoteCount"),
- 'in': prettySum("deliveriesIngress"),
- out: prettySum("deliveriesEgress"),
- thru: prettySum("deliveriesTransit"),
- toproc: prettySum("deliveriesToContainer"),
- fromproc:prettySum("deliveriesFromContainer"),
- uid: uid
- })
- })
- callback(addressFields)
- }, nodeIds[0])
- }
-
- var updateLinkGrid = function ( linkFields ) {
- $scope.linkFields = linkFields
- // if we have a selected link
- if ($scope.link) {
- // find the selected link in the array of all links
- var links = $scope.linkFields.filter(function (link) {
- return link.name === $scope.link.data.fields.name;
- })
- if (links.length > 0) {
- // linkInfo() is the function that is called by dynatree when a link is selected
- // It is passed a dynatree node. We need to simulate that node type to update the link grid
- linkInfo({data: {title: links[0].title, fields: links[0]}})
- }
- }
- }
-
- // get info for a all links
- $scope.selectedLinks = []
- $scope.linksGrid = {
- saveKey: 'linksGrid',
- data: 'linkFields',
- columnDefs: [
- {
- field: 'link',
- displayName: 'Link',
- groupable: false,
- saveKey: 'linksGrid',
- width: '12%'
- },
- {
- field: 'linkType',
- displayName: 'Link type',
- groupable: false,
- width: '10%'
- },
- {
- field: 'linkDir',
- displayName: 'Link dir',
- groupable: false,
- width: '8%'
- },
- {
- field: 'adminStatus',
- displayName: 'Admin status',
- groupable: false,
- width: '10%'
- },
- {
- field: 'operStatus',
- displayName: 'Oper status',
- groupable: false,
- width: '10%'
- },
- {
- field: 'deliveryCount',
- displayName: 'Delivery Count',
- groupable: false,
- cellClass: 'grid-align-value',
- width: '12%'
- },
- {
- field: 'rate',
- displayName: 'Rate',
- groupable: false,
- cellClass: 'grid-align-value',
- width: '8%'
- },
- {
- field: 'uncounts',
- displayName: 'Outstanding',
- groupable: false,
- cellClass: 'grid-align-value',
- width: '10%'
- },
- {
- field: 'owningAddr',
- displayName: 'Address',
- groupable: false,
- width: '20%'
- }
- ],
- enableColumnResize: true,
- enableColumnReordering: true,
- showColumnMenu: true,
- rowTemplate: 'linkRowTemplate.html',
- // aggregateTemplate: "linkAggTemplate.html",
- multiSelect: false,
- selectedItems: $scope.selectedLinks,
- afterSelectionChange: function(data) {
- if (data.selected) {
- var selItem = data.entity;
- var nodeId = selItem.uid
- $("#overtree").dynatree("getTree").activateKey(nodeId);
- }
- }
- };
-
-
- $scope.$on('ngGridEventColumns', function (e, columns) {
- var saveInfo = columns.map( function (col) {
- return [col.width, col.visible]
- })
- var saveKey = columns[0].colDef.saveKey
- if (saveKey)
- localStorage.setItem(columnStateKey+saveKey, JSON.stringify(saveInfo));
- })
-
- var loadColState = function (grid) {
- if (!grid)
- return;
- var columns = localStorage.getItem(columnStateKey+grid.saveKey);
- if (columns) {
- var cols = JSON.parse(columns);
- cols.forEach( function (col, index) {
- grid.columnDefs[index].width = col[0];
- grid.columnDefs[index].visible = col[1]
- })
- }
- }
- var allLinkInfo = function () {
- getAllLinkFields([updateLinkGrid, updateLinkTree])
- loadColState($scope.linksGrid);
- }
-
- var getAllLinkFields = function (callbacks) {
- var nodeIds = QDRService.nodeIdList()
- var linkFields = []
- var now = Date.now()
- var rate = function (response, result) {
- var name = QDRService.valFor(response.attributeNames, result, "linkName").sum
- var oldname = $scope.linkFields.filter(function (link) {
- return link.linkName === name
- })
- if (oldname.length > 0) {
- var elapsed = (now - oldname[0].timestamp) / 1000;
- var delivered = QDRService.valFor(response.attributeNames, result, "deliveryCount").sum - oldname[0].rawDeliveryCount
- //QDR.log.debug("elapsed " + elapsed + " delivered " + delivered)
- return elapsed > 0 ? parseFloat(Math.round((delivered/elapsed) * 100) / 100).toFixed(2) : 0;
- } else {
- //QDR.log.debug("unable to find old linkName")
- return 0
- }
- }
- QDRService.getMultipleNodeInfo(nodeIds, "router.link", [], function (nodeIds, entity, response) {
- response.aggregates.forEach( function (result) {
- var prettySum = function (field) {
- var fieldIndex = response.attributeNames.indexOf(field)
- if (fieldIndex < 0) {
- return "-"
- }
- var val = result[fieldIndex].sum
- return QDRService.pretty(val)
- }
- var uncounts = function () {
- var und = QDRService.valFor(response.attributeNames, result, "undeliveredCount").sum
- var uns = QDRService.valFor(response.attributeNames, result, "unsettledCount").sum
- return und + uns
- }
- var nameIndex = response.attributeNames.indexOf('name')
- var linkName = function () {
- var details = result[nameIndex].detail
- var names = []
- details.forEach( function (detail) {
- if (detail.node.endsWith(':'))
- names.push(detail.node.slice(0, -1))
- else
- names.push(detail.node)
- })
- //var namestr = names.join('-')
- var namestr = names.length > 0 ? names[0] : ""
- return namestr + ':' + QDRService.valFor(response.attributeNames, result, "identity").sum
- }
- var fixAddress = function () {
- var owningAddr = QDRService.valFor(response.attributeNames, result, "owningAddr").sum || ""
- /*
- - "L*" => "* (local)"
- - "M0*" => "* (direct)"
- - "M1*" => "* (dequeue)"
- - "MX*" => "* (phase X)"
- */
- var address = undefined;
- var starts = {'L': '(local)', 'M0': '(direct)', 'M1': '(dequeue)'}
- for (var start in starts) {
- if (owningAddr.startsWith(start)) {
- var ends = owningAddr.substr(start.length)
- address = ends + " " + starts[start]
- break;
- }
- }
- if (!address) {
- // check for MX*
- if (owningAddr.length > 3) {
- if (owningAddr[0] === 'M') {
- var phase = parseInt(owningAddress.substr(1))
- if (phase && !isNaN(phase)) {
- var phaseStr = phase + "";
- var star = owningAddress.substr(2 + phaseStr.length)
- address = star + " " + "(phase " + phaseStr + ")"
- }
- }
- }
- }
- return address || owningAddr;
- }
-
- var adminStatus = QDRService.valFor(response.attributeNames, result, "adminStatus").sum
- var operStatus = QDRService.valFor(response.attributeNames, result, "operStatus").sum
- var linkName = linkName()
- var linkType = QDRService.valFor(response.attributeNames, result, "linkType").sum
- if ($scope.currentLinkFilter === "" || $scope.currentLinkFilter === linkType) {
- linkFields.push({
- link: linkName,
- title: linkName,
- uncounts: uncounts(),
- operStatus: operStatus,
- adminStatus:adminStatus,
- owningAddr: fixAddress(),
- deliveryCount:prettySum("deliveryCount") + " ",
- rawDeliveryCount: QDRService.valFor(response.attributeNames, result, "deliveryCount").sum,
- name: QDRService.valFor(response.attributeNames, result, "name").sum,
- linkName: QDRService.valFor(response.attributeNames, result, "linkName").sum,
- capacity: QDRService.valFor(response.attributeNames, result, "capacity").sum,
- connectionId: QDRService.valFor(response.attributeNames, result, "connectionId").sum,
- linkDir: QDRService.valFor(response.attributeNames, result, "linkDir").sum,
- linkType: linkType,
- peer: QDRService.valFor(response.attributeNames, result, "peer").sum,
- type: QDRService.valFor(response.attributeNames, result, "type").sum,
- undeliveredCount: QDRService.valFor(response.attributeNames, result, "undeliveredCount").sum,
- unsettledCount: QDRService.valFor(response.attributeNames, result, "unsettledCount").sum,
- uid: linkName,
- timestamp: now,
- rate: rate(response, result)
- })
- }
- })
- callbacks.forEach( function (cb) {
- cb(linkFields)
- })
- }, nodeIds[0])
- }
-
- $scope.allConnectionFields = []
- $scope.allConnectionSelections = [];
- $scope.allConnectionGrid = {
- saveKey: 'allConnGrid',
- data: 'allConnectionFields',
- columnDefs: [
- {
- field: 'host',
- saveKey: 'allConnGrid',
- displayName: 'host'
- },
- {
- field: 'container',
- displayName: 'container'
- },
- {
- field: 'role',
- displayName: 'role'
- },
- {
- field: 'dir',
- displayName: 'dir'
- },
- {
- field: 'security',
- displayName: 'security'
- },
- {
- field: 'authentication',
- displayName: 'authentication'
- }
- ],
- enableColumnResize: true,
- multiSelect: false,
- selectedItems: $scope.allConnectionSelections,
- afterSelectionChange: function(data) {
- if (data.selected) {
- var selItem = $scope.allConnectionSelections[0]
- var nodeId = selItem.host
- // activate Routers->nodeId in the tree
- $("#overtree").dynatree("getTree").activateKey(nodeId);
- }
- }
- };
- // get info for a all connections
- var allConnectionInfo = function () {
- var nodeIds = QDRService.nodeIdList()
- updateConnectionTree(nodeIds)
- $scope.allConnectionFields = [];;
- var connectionNodes = $("#overtree").dynatree("getTree").getNodeByKey('Connections').getChildren()
- connectionNodes.forEach( function (connection) {
- $scope.allConnectionFields.push(connection.data.fields)
- })
- loadColState($scope.allConnectionGrid);
- }
-
- $scope.addressFields = []
- $scope.addressGrid = {
- saveKey: 'addGrid',
- data: 'addressFields',
- columnDefs: [
- {
- field: 'attribute',
- displayName: 'Attribute',
- saveKey: 'addGrid',
- width: '40%'
- },
- {
- field: 'value',
- displayName: 'Value',
- width: '40%'
- }
- ],
- enableColumnResize: true,
- multiSelect: false
- }
-
- // get info for a single address
- var addressInfo = function (address) {
- if (!address)
- return;
- $scope.address = address
- $scope.addressFields = [];
-
- var fields = Object.keys(address.data.fields)
- fields.forEach( function (field) {
- if (field != "title" && field != "uid")
- $scope.addressFields.push({attribute: field, value: address.data.fields[field]})
- })
- loadColState($scope.addressGrid);
- }
-
- $scope.singleLinkFields = []
- $scope.linkGrid = {
- saveKey: 'linkGrid',
- data: 'singleLinkFields',
- columnDefs: [
- {
- field: 'attribute',
- displayName: 'Attribute',
- width: '40%'
- },
- {
- field: 'value',
- displayName: 'Value',
- width: '40%'
- }
- ],
- enableColumnResize: true,
- multiSelect: false
- }
-
- // display the grid detail info for a single link
- var linkInfo = function (link) {
- if (!link)
- return;
- $scope.link = link
-
- $scope.singleLinkFields = [];
- var fields = Object.keys(link.data.fields)
- var excludeFields = ["title", "uid", "uncounts", "rawDeliveryCount", "timestamp"]
- fields.forEach( function (field) {
- if (excludeFields.indexOf(field) == -1)
- $scope.singleLinkFields.push({attribute: field, value: link.data.fields[field]})
- })
- loadColState($scope.linkGrid);
- }
-
- // get info for a single connection
- $scope.connectionModes = [{
- content: '<a><i class="icon-list"></i> Attriutes</a>',
- id: 'attributes',
- title: "View connection attributes",
- isValid: function () { return true; }
- },
- {
- content: '<a><i class="icon-link"></i> Links</a>',
- id: 'links',
- title: "Show links",
- isValid: function () { return true }
- }
- ];
- $scope.currentMode = $scope.connectionModes[0];
- $scope.isModeSelected = function (mode) {
- return mode === $scope.currentMode;
- }
- $scope.connectionLinks = [];
- var updateConnectionLinks = function () {
- var n = $scope.connection.data.fields
- var key = n.routerId
- var nodeInfo = QDRService.topology.nodeInfo();
- var links = nodeInfo[key]['.router.link'];
- var linkTypeIndex = links.attributeNames.indexOf('linkType');
- var connectionIdIndex = links.attributeNames.indexOf('connectionId');
- $scope.connectionLinks = [];
- links.results.forEach( function (link) {
- if (link[linkTypeIndex] === 'endpoint' && link[connectionIdIndex] === n.identity) {
- var l = {};
- l.owningAddr = QDRService.valFor(links.attributeNames, link, 'owningAddr');
- l.dir = QDRService.valFor(links.attributeNames, link, 'linkDir');
- if (l.owningAddr && l.owningAddr.length > 2)
- if (l.owningAddr[0] === 'M')
- l.owningAddr = l.owningAddr.substr(2)
- else
- l.owningAddr = l.owningAddr.substr(1)
-
- l.adminStatus = QDRService.valFor(links.attributeNames, link, 'adminStatus');
- l.operStatus = QDRService.valFor(links.attributeNames, link, 'operStatus');
- l.identity = QDRService.valFor(links.attributeNames, link, 'identity')
- l.connectionId = QDRService.valFor(links.attributeNames, link, 'connectionId')
-/*
- l.deliveryCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'deliveryCount'));
- l.undeliveredCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'undeliveredCount'));
- l.unsettledCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'unsettledCount'));
-*/
- // ---------------------------------------------
- // TODO: remove this fake quiescing/reviving logic when the routers do the work
- if ($scope.quiesceState.linkStates[l.identity])
- l.adminStatus = $scope.quiesceState.linkStates[l.identity];
- if ($scope.quiesceState.operStates[l.identity])
- l.operStatus = $scope.quiesceState.operStates[l.identity];
- if ($scope.quiesceState.state == 'quiescing') {
- if (l.adminStatus === 'enabled') {
- var chance = Math.floor(Math.random() * 2);
- if (chance == 1) {
- l.adminStatus = 'disabled';
- $scope.quiesceState.linkStates[l.identity] = 'disabled';
- $scope.quiesceState.operStates[l.identity] = 'idle';
- }
- }
- }
- if ($scope.quiesceState.state == 'reviving') {
- if (l.adminStatus === 'disabled') {
- var chance = Math.floor(Math.random() * 2);
- if (chance == 1) {
- l.adminStatus = 'enabled';
- $scope.quiesceState.linkStates[l.identity] = 'enabled';
- $scope.quiesceState.operStates[l.identity] = 'up';
- }
- }
- }
- if ($scope.quiesceState.linkStates[l.identity] === 'disabled') {
- l.unsettledCount = 0;
- l.undeliveredCount = 0;
- l.operState = 'idle'
- $scope.quiesceState.operStates[l.identity] = l.operState
- } else {
- l.deliveryCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'deliveryCount'));
- l.undeliveredCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'undeliveredCount'));
- l.unsettledCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'unsettledCount'));
- l.operState = 'up'
- $scope.quiesceState.operStates[l.identity] = l.operState
- }
- // ---------------------------------------------
-
- $scope.connectionLinks.push(l)
- }
- })
- $scope.connectionLinksGrid.updateState()
- }
-
- $scope.selectMode = function (mode) {
- $scope.currentMode = mode;
- if (mode.id === 'links') {
- QDRService.addUpdatedAction("connectionLinks", updateConnectionLinks)
- updateConnectionLinks();
- } else {
- QDRService.delUpdatedAction("connectionLinks");
- }
- }
- $scope.isValid = function (mode) {
- return mode.isValid()
- }
- $scope.quiesceState = {
- state: 'enabled',
- buttonText: 'Quiesce',
- buttonDisabled: false,
- linkStates: {},
- operStates: {}
- }
- $scope.quiesceAllClicked = function () {
- var state = $scope.quiesceState.state;
- if (state === 'enabled') {
- // start quiescing all links
- $scope.quiesceState.state = 'quiescing';
- } else if (state === 'quiesced') {
- // start reviving all links
- $scope.quiesceState.state = 'reviving';
- }
- $scope.connectionLinksGrid.updateState();
- }
- $scope.quiesceClass = function (row) {
- var stateClassMap = {
- enabled: 'btn-primary',
- quiescing: 'btn-warning',
- reviving: 'btn-warning',
- quiesced: 'btn-danger'
- }
- return stateClassMap[$scope.quiesceState.state];
- }
- $scope.quiesceLinkClass = function (row) {
- var stateClassMap = {
- enabled: 'btn-primary',
- disabled: 'btn-danger'
- }
- return stateClassMap[row.entity.adminStatus]
- }
- $scope.quiesceLink = function (row) {
- var state = row.entity.adminStatus === 'enabled' ? 'disabled' : 'enabled';
- var operState = state === 'enabled' ? 'up' : 'idle';
- $scope.quiesceState.linkStates[row.entity.identity] = state;
- $scope.quiesceState.operStates[row.entity.identity] = operState;
- }
- $scope.quiesceLinkDisabled = function (row) {
- return false;
- }
- $scope.quiesceLinkText = function (row) {
- return row.entity.adminStatus === 'disabled' ? "Revive" : "Quiesce";
- }
- $scope.quiesceHide = function () {
- return $scope.connectionLinks.length == 0;
- }
- $scope.connectionLinksGrid = {
- saveKey: 'connLinksGrid',
-
- data: 'connectionLinks',
- updateState: function () {
- var state = $scope.quiesceState.state;
-
- // count enabled and disabled links for this connection
- var enabled = 0, disabled = 0;
- $scope.connectionLinks.forEach ( function (link) {
- if (link.adminStatus === 'enabled')
- ++enabled;
- if (link.adminStatus === 'disabled')
- ++disabled;
- })
-
- var linkCount = $scope.connectionLinks.length;
- if (linkCount == 0) {
- $scope.quiesceState.buttonText = 'Quiesce';
- $scope.quiesceState.buttonDisabled = false;
- $scope.quiesceState.state = 'enabled'
- return;
- }
- // if state is quiescing and any links are enabled, button should say 'Quiescing' and be disabled
- if (state === 'quiescing' && (enabled > 0)) {
- $scope.quiesceState.buttonText = 'Quiescing';
- $scope.quiesceState.buttonDisabled = true;
- } else
- // if state is enabled and all links are disabled, button should say Revive and be enabled. set state to quisced
- // if state is quiescing and all links are disabled, button should say 'Revive' and be enabled. set state to quiesced
- if ((state === 'quiescing' || state === 'enabled') && (disabled === linkCount)) {
- $scope.quiesceState.buttonText = 'Revive';
- $scope.quiesceState.buttonDisabled = false;
- $scope.quiesceState.state = 'quiesced'
- } else
- // if state is reviving and any links are disabled, button should say 'Reviving' and be disabled
- if (state === 'reviving' && (disabled > 0)) {
- $scope.quiesceState.buttonText = 'Reviving';
- $scope.quiesceState.buttonDisabled = true;
- } else
- // if state is reviving or quiesced and all links are enabled, button should say 'Quiesce' and be enabled. set state to enabled
- if ((state === 'reviving' || state === 'quiesced') && (enabled === linkCount)) {
- $scope.quiesceState.buttonText = 'Quiesce';
- $scope.quiesceState.buttonDisabled = false;
- $scope.quiesceState.state = 'enabled'
- }
-
- if ($scope.quiesceState.state === 'quiesced') {
- d3.selectAll('.external.connection.dynatree-active')
- .classed('quiesced', true)
- } else {
- d3.selectAll('.external.connection.dynatree-active.quiesced')
- .classed('quiesced', false)
- }
- },
- columnDefs: [
- {
- field: 'adminStatus',
- cellTemplate: "titleCellTemplate.html",
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- saveKey: 'connLinksGrid',
- displayName: 'Admin state'
- },
- {
- field: 'operStatus',
- cellTemplate: "titleCellTemplate.html",
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- displayName: 'Oper state'
- },
- {
- field: 'dir',
- cellTemplate: "titleCellTemplate.html",
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- displayName: 'dir'
- },
- {
- field: 'owningAddr',
- cellTemplate: "titleCellTemplate.html",
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- displayName: 'Address'
- },
- {
- field: 'deliveryCount',
- displayName: 'Delivered',
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- cellClass: 'grid-values'
-
- },
- {
- field: 'undeliveredCount',
- displayName: 'Undelivered',
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- cellClass: 'grid-values'
- },
- {
- field: 'unsettledCount',
- displayName: 'Unsettled',
- headerCellTemplate: 'titleHeaderCellTemplate.html',
- cellClass: 'grid-values'
- }/*,
- {
- cellClass: 'gridCellButton',
- cellTemplate: '<button title="{{quiesceLinkText(row)}} this link" type="button" ng-class="quiesceLinkClass(row)" class="btn" ng-click="quiesceLink(row)" ng-disabled="quiesceLinkDisabled(row)">{{quiesceLinkText(row)}}</button>'
- }*/
- ]
- }
-
- $scope.connectionFields = []
- $scope.connectionGrid = {
- saveKey: 'connGrid',
- data: 'connectionFields',
- columnDefs: [
- {
- field: 'attribute',
- displayName: 'Attribute',
- saveKey: 'connGrid',
- width: '40%'
- },
- {
- field: 'value',
- displayName: 'Value',
- width: '40%'
- }
- ],
- enableColumnResize: true,
- multiSelect: false
- }
-
- var connectionInfo = function (connection) {
- $scope.connection = connection
-
- $scope.connectionFields = [];
- var fields = Object.keys(connection.data.fields)
- fields.forEach( function (field) {
- $scope.connectionFields.push({attribute: field, value: connection.data.fields[field]})
- })
- $scope.selectMode($scope.currentMode)
- loadColState($scope.connectionGrid);
- }
-
- // get info for a all logs
- var allLogInfo = function () {
- }
-
- // get info for a single log
- var logInfo = function (node) {
- $scope.log = node
- }
-
- var getExpandedList = function () {
- var list = [];
- var tree = $("#overtree").dynatree("getRoot");
- if (tree.length !== 0) {
- tree.visit(function(node){
- if (node.isExpanded()) {
- list.push(node.data.parent)
- }
- });
- }
- return list;
- }
-
- var updateExpanded = function () {
- var tree = $("#overtree").dynatree("getRoot");
- if (tree.length !== 0) {
- tree.visit(function(node){
- if (node.isExpanded() || node.isActive()) {
- node.data.info(node)
- }
- });
- }
- }
-
- // loads the tree node name that was last selected
- var loadActivatedNode = function () {
- return localStorage[OverviewActivatedKey] || 'Routers'
- }
- // saved the tree node name that is currently selected
- var saveActivated = function (key) {
- localStorage[OverviewActivatedKey] = key;
- lastKey = key;
- }
- // loads list that was saved
- var loadExpandedNodeList = function () {
- return angular.fromJson(localStorage[OverviewExpandedKey]) || [];
- }
- // called when a node is expanded
- // here we save the expanded node so it can be restored when the page reloads
- var saveExpanded = function () {
- var list = getExpandedList();
- localStorage[OverviewExpandedKey] = JSON.stringify(list)
- }
-
- // activated is called each time a tree node is clicked
- // based on which node is clicked, load the correct data grid template and start getting the data
- var activated = function (node) {
- //QDR.log.debug("node activated: " + node.data.title)
- var type = node.data.type;
- saveExpanded()
- saveActivated(node.data.key)
-
- var template = $scope.templates.filter( function (tpl) {
- return tpl.name == type;
- })
- $scope.template = template[0];
- // the nodes info function will fetch the grids data
- if (node.data.info) {
- $timeout(function () {node.data.info(node)})
- }
-
- }
- $scope.template = {url: ''};
-
- if (!QDRService.connected) {
- QDRService.redirectWhenConnected("overview")
- return;
- }
-
- // we are currently connected. setup a handler to get notified if we are ever disconnected
- QDRService.addDisconnectAction( function () {
- QDRService.redirectWhenConnected("overview")
- $scope.$apply();
- })
-
- /* --------------------------------------------------
- *
- * setup the tree on the left
- *
- * -------------------------------------------------
- */
- // utility function called by each top level tree node when it needs to populate its child nodes
- var updateLeaves = function (leaves, parentKey, parentFolder, worker) {
- var scrollTree = $('.qdr-overview.pane.left .pane-viewport')
- var scrollTop = scrollTree.scrollTop();
- var tree = $("#overtree").dynatree("getTree")
- var parentNode = tree.count ? tree.getNodeByKey(parentKey) : null;
- // if we were called after the tree is created, replace the existing nodes
- var activeNode;
- if (parentNode) {
- activeNode = tree.getActiveNode();
- parentNode.removeChildren();
- }
- leaves.forEach( function (leaf) {
- var childFolder = worker(leaf)
- if (parentNode)
- parentNode.addChild(childFolder)
- else
- parentFolder.children.push(childFolder)
- })
- scrollTree.scrollTop(scrollTop)
- if (activeNode) {
- var newNode = tree.getNodeByKey(activeNode.data.key)
- newNode.activateSilently()
- }
- }
-
- // get saved tree state
- var lastKey = loadActivatedNode();
- var expandedNodeList = loadExpandedNodeList();
-
- // create a routers tree branch
- var routers = new Folder("Routers")
- routers.type = "Routers"
- routers.info = allRouterInfo
- routers.activate = lastKey === 'Routers'
- routers.expand = (expandedNodeList.indexOf("Routers") > -1)
- routers.clickFolderMode = 1
- routers.key = "Routers"
- routers.parent = "Routers"
- routers.addClass = "routers"
- topLevelChildren.push(routers)
- // called when the list of routers changes
- var updateRouterTree = function (nodes) {
- var worker = function (node) {
- var name = QDRService.nameFromId(node)
- var router = new Folder(name)
- router.type = "Router"
- router.info = routerInfo
- router.nodeId = node
- router.key = node
- router.addClass = "router"
- router.parent = "Routers"
- router.activate = lastKey === node
- return router;
- }
- updateLeaves(nodes, "Routers", routers, worker)
- }
- updateRouterTree(QDRService.nodeIdList());
-
- // create an addresses tree branch
- var addresses = new Folder("Addresses")
- addresses.type = "Addresses"
- addresses.info = allAddressInfo
- addresses.activate = lastKey === 'Addresses'
- addresses.expand = (expandedNodeList.indexOf("Addresses") > -1)
- addresses.clickFolderMode = 1
- addresses.key = "Addresses"
- addresses.parent = "Addresses"
- addresses.addClass = "addresses"
- topLevelChildren.push(addresses)
- var updateAddressTree = function (addressFields) {
- var worker = function (address) {
- var a = new Folder(address.title)
- a.info = addressInfo
- a.key = address.uid
- a.fields = address
- a.type = "Address"
- a.addClass = "address"
- a.activate = lastKey === address.uid
- a.parent = "Addresses"
- return a;
- }
- updateLeaves(addressFields, "Addresses", addresses, worker)
- }
- allAddressInfo();
-
- $scope.setLinkFilter = function (cur) {
- // filter out non-matching links from the tree and the grid
- getAllLinkFields([updateLinkGrid, updateLinkTree])
- }
- $scope.filterClose = function () {
- var filter = $('#linkFilter')
- filter.hide();
- }
- $scope.currentLinkFilter = "endpoint"
- var filterHtml = "<button type='button' class='btn btn-secondary btn-filter'><span class='filter-icon'><i class='icon-filter'> Filter</span></button>";
- var links = new Folder("Links " + filterHtml)
- links.type = "Links"
- links.info = allLinkInfo
- links.activate = lastKey === 'Links'
- links.expand = (expandedNodeList.indexOf("Links") > -1)
- links.clickFolderMode = 1
- links.key = "Links"
- links.parent = "Links"
- links.addClass = "links"
- topLevelChildren.push(links)
-
- // called both before the tree is created and whenever a background update is done
- var updateLinkTree = function (linkFields) {
- var worker = function (link) {
- var l = new Folder(link.title)
- l.info = linkInfo
- l.key = link.uid
- l.fields = link
- l.type = "Link"
- l.parent = "Links"
- l.activate = lastKey === link.uid
- l.addClass = "link"
- return l;
- }
- linkFields.sort ( function (a,b) { return a.link < b.link ? -1 : a.link > b.link ? 1 : 0})
- updateLeaves(linkFields, "Links", links, worker)
- }
- allLinkInfo();
-
- var connections = new Folder("Connections")
- connections.type = "Connections"
- connections.info = allConnectionInfo
- connections.activate = lastKey === 'Connections'
- connections.expand = (expandedNodeList.indexOf("Connections") > -1)
- connections.clickFolderMode = 1
- connections.key = "Connections"
- connections.parent = "Connections"
- connections.addClass = "connections"
- topLevelChildren.push(connections)
-
- updateConnectionTree = function (nodes) {
- var connectionsObj = {}
- var expected = nodes.length;
- var connreceived = 0;
- nodes.forEach( function (nodeId) {
- QDRService.getNodeInfo(nodeId, ".connection", [], function (nodeName, entity, response) {
- response.results.forEach( function (result) {
-
- var auth = "no_auth"
- var sasl = QDRService.valFor(response.attributeNames, result, "sasl")
- if (QDRService.valFor(response.attributeNames, result, "isAuthenticated")) {
- auth = sasl
- if (sasl === "ANONYMOUS")
- auth = "anonymous-user"
- else {
- if (sasl === "GSSAPI")
- sasl = "Kerberos"
- if (sasl === "EXTERNAL")
- sasl = "x.509"
- auth = QDRService.valFor(response.attributeNames, result, "user") + "(" +
- QDRService.valFor(response.attributeNames, result, "sslCipher") + ")"
- }
- }
-
- var sec = "no-security"
- if (QDRService.valFor(response.attributeNames, result, "isEncrypted")) {
- if (sasl === "GSSAPI")
- sec = "Kerberos"
- else
- sec = QDRService.valFor(response.attributeNames, result, "sslProto") + "(" +
- QDRService.valFor(response.attributeNames, result, "sslCipher") + ")"
- }
-
- var host = QDRService.valFor(response.attributeNames, result, "host")
- connectionsObj[host] = {}
- response.attributeNames.forEach( function (attribute, i) {
- connectionsObj[host][attribute] = result[i]
- })
- connectionsObj[host].security = sec
- connectionsObj[host].authentication = auth
- connectionsObj[host].routerId = nodeName
-
- })
- ++connreceived;
- if (connreceived == expected) {
- var worker = function (connection) {
- var c = new Folder(connection)
- c.type = "Connection"
- c.info = connectionInfo
- c.key = connection
- c.fields = connectionsObj[connection]
- c.tooltip = connectionsObj[connection].role === "inter-router" ? "inter-router connection" : "external connection"
- c.addClass = c.tooltip
- c.parent = "Connections"
- c.activate = lastKey === connection
- return c
- }
- var allConnections = Object.keys(connectionsObj).sort()
- updateLeaves(allConnections, "Connections", connections, worker)
- }
- })
- })
- }
- updateConnectionTree(QDRService.nodeIdList())
-
- var logsreceived = 0;
- var logObj = {}
- var logs = new Folder("Logs")
- logs.type = "Logs"
- logs.info = allLogInfo
- logs.activate = lastKey === 'Logs'
- logs.expand = (expandedNodeList.indexOf("Logs") > -1)
- logs.clickFolderMode = 1
- logs.key = "Logs"
- logs.parent = "Logs"
- //topLevelChildren.push(logs)
- var nodeIds = QDRService.nodeIdList()
- var expected = nodeIds.length;
- nodeIds.forEach( function (nodeId) {
- QDRService.getNodeInfo(nodeId, ".log", ["name"], function (nodeName, entity, response) {
- response.results.forEach( function (result) {
- logObj[result[0]] = 1 // use object to collapse duplicates
- })
- ++logsreceived;
- if (logsreceived == expected) {
- var allLogs = Object.keys(logObj).sort()
- allLogs.forEach(function (log) {
- var l = new Folder(log)
- l.type = "Log"
- l.info = logInfo
- l.key = log
- l.parent = "Logs"
- l.activate = lastKey === log
- logs.children.push(l)
- })
- $('#overtree').dynatree({
- onActivate: activated,
- onExpand: saveExpanded,
- onClick: function (n, e) {
- if (e.target.className.indexOf('-filter') > -1) {
- //QDR.log.debug("overtree on click called")
- e.preventDefault();
- e.stopPropagation()
- var filter = $('#linkFilter')
- var treeLink = $('span.links')
- filter.css({
- top: treeLink.offset().top + treeLink.height(),
- left: treeLink.offset().left,
- zIndex:5000
- });
- filter.toggle()
- $("#overtree").dynatree("getTree").getNodeByKey('Links').activate()
- return false;
- }
- },
- selectMode: 1,
- activeVisible: false,
- children: topLevelChildren
- })
- // simulate a click on the previous active node
- var active = $("#overtree").dynatree("getActiveNode");
- if (!active) {
- active = $("#overtree").dynatree("getTree").getNodeByKey("Routers")
- }
- activated(active);
-
- // populate the data for each expanded node
- updateExpanded();
- QDRService.addUpdatedAction( "overview", function () {
- $timeout(updateExpanded);
- })
- // update the node list
- QDRService.startUpdating()
-
- loadColState($scope.allRouters);
- loadColState($scope.routerGrid);
- loadColState($scope.addressesGrid);
- loadColState($scope.addressGrid);
- loadColState($scope.linksGrid);
- loadColState($scope.linkGrid);
- loadColState($scope.allConnectionGrid);
- loadColState($scope.connectionGrid);
-
- }
- })
- })
-
- $scope.$on("$destroy", function( event ) {
- QDRService.stopUpdating()
- QDRService.delUpdatedAction("overview")
- });
-
- }]);
-
- return QDR;
-
-}(QDR || {}));
-
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js b/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js
new file mode 120000
index 0000000..de6a7a1
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrOverview.js
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/js/qdrOverview.js
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/js/qdrSchema.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrSchema.js b/console/hawtio/src/main/webapp/plugin/js/qdrSchema.js
deleted file mode 100644
index 656b159..0000000
--- a/console/hawtio/src/main/webapp/plugin/js/qdrSchema.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
-*/
-/**
- * @module QDR
- */
-var QDR = (function (QDR) {
-
- QDR.module.controller("QDR.SchemaController", ['$scope', '$location', 'QDRService', function($scope, $location, QDRService) {
- if (!QDRService.connected) {
- QDRService.redirectWhenConnected("schema")
- return;
- }
- // we are currently connected. setup a handler to get notified if we are ever disconnected
- QDRService.addDisconnectAction( function () {
- QDRService.redirectWhenConnected("schema")
- $scope.$apply();
- })
-
- var keys2kids = function (tree, obj) {
-
- if (obj === Object(obj)) {
- tree.children = []
- for (var key in obj) {
- var kid = {title: key}
- if (obj[key] === Object(obj[key])) {
- kid.isFolder = true
- keys2kids(kid, obj[key])
- } else {
- kid.title += (': ' + JSON.stringify(obj[key],null,2))
- }
- tree.children.push(kid)
- }
- }
- }
-
- var tree = []
- for (var key in QDRService.schema) {
- var kid = {title: key}
- var val = QDRService.schema[key]
- if (val === Object(val))
- keys2kids(kid, val)
- else
- kid.title += (': ' + JSON.stringify(val,null,2))
-
- tree.push(kid);
- }
- $('#schema').dynatree({
- minExpandLevel: 2,
- children: tree
- })
-
-
- }]);
-
- return QDR;
-}(QDR || {}));
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrSchema.js b/console/hawtio/src/main/webapp/plugin/js/qdrSchema.js
new file mode 120000
index 0000000..5010e61
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrSchema.js
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/js/qdrSchema.js
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/js/qdrService.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrService.js b/console/hawtio/src/main/webapp/plugin/js/qdrService.js
deleted file mode 100644
index 09c3b92..0000000
--- a/console/hawtio/src/main/webapp/plugin/js/qdrService.js
+++ /dev/null
@@ -1,888 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you 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.
-*/
-/**
- * @module QDR
- */
-var QDR = (function(QDR) {
-
- // The QDR service handles the connection to
- // the server in the background
- QDR.module.factory("QDRService", ['$rootScope', '$http', '$timeout', '$resource', '$location', function($rootScope, $http, $timeout, $resource, $location) {
- var self = {
-
- rhea: require("rhea"),
-
- timeout: 10,
- connectActions: [],
- disconnectActions: [],
- updatedActions: {},
- stop: undefined, // update interval handle
-
- addConnectAction: function(action) {
- if (angular.isFunction(action)) {
- self.connectActions.push(action);
- }
- },
- addDisconnectAction: function(action) {
- if (angular.isFunction(action)) {
- self.disconnectActions.push(action);
- }
- },
- addUpdatedAction: function(key, action) {
- if (angular.isFunction(action)) {
- self.updatedActions[key] = action;
- }
- },
- delUpdatedAction: function(key) {
- if (key in self.updatedActions)
- delete self.updatedActions[key];
- },
-
- executeConnectActions: function() {
- self.connectActions.forEach(function(action) {
- //QDR.log.debug("executing connect action " + action);
- try {
- action.apply();
- } catch (e) {
- // in case the page that registered the handler has been unloaded
- }
- });
- self.connectActions = [];
- if ($location.path().startsWith(QDR.pluginRoot)) {
- $timeout( function () {
-
- var searchObject = $location.search();
- var goto = "overview";
- if (searchObject.org) {
- goto = searchObject.org;
- }
- $location.search('org', null)
- $location.path(QDR.pluginRoot +"/" + goto);
- })
- }
-
- },
- executeDisconnectActions: function() {
- self.disconnectActions.forEach(function(action) {
- try {
- action.apply();
- } catch (e) {
- // in case the page that registered the handler has been unloaded
- }
- });
- self.disconnectActions = [];
- },
- executeUpdatedActions: function() {
- for (action in self.updatedActions) {
- try {
- self.updatedActions[action].apply();
- } catch (e) {
- delete self.updatedActions[action]
- }
- }
- },
- redirectWhenConnected: function (org) {
- $location.path("/" + QDR.pluginName + "/connect")
- $location.search('org', org);
- },
-
- notifyTopologyDone: function() {
- //QDR.log.debug("got Toplogy done notice");
-
- if (!angular.isDefined(self.schema))
- return;
- else if (self.topology._gettingTopo)
- return;
- if (!self.gotTopology) {
- QDR.log.debug("topology was just initialized");
- self.gotTopology = true;
- self.executeConnectActions();
- $rootScope.$apply();
- } else {
- QDR.log.debug("topology model was just updated");
- self.executeUpdatedActions();
- }
-
- },
- /**
- * @property options
- * Holds a reference to the connection options when
- * a connection is started
- */
- options: undefined,
-
- /*
- * @property message
- * The proton message that is used to send commands
- * and receive responses
- */
- sender: undefined,
- receiver: undefined,
- sendable: false,
-
- schema: undefined,
-
- toAddress: undefined,
- connected: false,
- gotTopology: false,
- errorText: undefined,
- connectionError: undefined,
-
- isConnected: function() {
- return self.connected;
- },
-
- correlator: {
- _objects: {},
- _corremationID: 0,
-
- corr: function () {
- var id = ++this._corremationID + "";
- this._objects[id] = {resolver: null}
- return id;
- },
- request: function() {
- //QDR.log.debug("correlator:request");
- return this;
- },
- then: function(id, resolver, error) {
- //QDR.log.debug("registered then resolver for correlationID: " + id);
- if (error) {
- delete this._objects[id];
- return;
- }
- this._objects[id].resolver = resolver;
- },
- // called by receiver's on('message') handler when a response arrives
- resolve: function(context) {
- var correlationID = context.message.properties.correlation_id;
- this._objects[correlationID].resolver(context.message.body, context);
- delete this._objects[correlationID];
- }
- },
-
- onSubscription: function() {
- self.getSchema();
- },
-
- startUpdating: function () {
- self.stopUpdating();
- QDR.log.info("startUpdating called")
- self.topology.get();
- self.stop = setInterval(function() {
- self.topology.get();
- }, 2000);
- },
- stopUpdating: function () {
- if (angular.isDefined(self.stop)) {
- QDR.log.info("stopUpdating called")
- clearInterval(self.stop);
- self.stop = undefined;
- }
- },
-
- initProton: function() {
- //QDR.log.debug("*************QDR init proton called ************");
- },
- cleanUp: function() {
- },
- error: function(line) {
- if (line.num) {
- QDR.log.debug("error - num: ", line.num, " message: ", line.message);
- } else {
- QDR.log.debug("error - message: ", line.message);
- }
- },
- disconnected: function(line) {
- QDR.log.debug("Disconnected from QDR server");
- self.executeDisconnectActions();
- },
-
- nameFromId: function (id) {
- return id.split('/')[3];
- },
-
- humanify: function (s) {
- var t = s.charAt(0).toUpperCase() + s.substr(1).replace(/[A-Z]/g, ' $&');
- return t.replace(".", " ");
- },
- pretty: function(v) {
- var formatComma = d3.format(",");
- if (!isNaN(parseFloat(v)) && isFinite(v))
- return formatComma(v);
- return v;
- },
-
- nodeNameList: function() {
- var nl = [];
- // if we are in the middel of updating the topology
- // then use the last known node info
- var ni = self.topology._nodeInfo;
- if (self.topology._gettingTopo)
- ni = self.topology._lastNodeInfo;
- for (var id in ni) {
- nl.push(self.nameFromId(id));
- }
- return nl.sort();
- },
-
- nodeIdList: function() {
- var nl = [];
- // if we are in the middel of updating the topology
- // then use the last known node info
- var ni = self.topology._nodeInfo;
- if (self.topology._gettingTopo)
- ni = self.topology._lastNodeInfo;
- for (var id in ni) {
- nl.push(id);
- }
- return nl.sort();
- },
-
- nodeList: function () {
- var nl = [];
- var ni = self.topology._nodeInfo;
- if (self.topology._gettingTopo)
- ni = self.topology._lastNodeInfo;
- for (var id in ni) {
- nl.push({name: self.nameFromId(id), id: id});
- }
- return nl;
- },
-
- // given an attribute name array, find the value at the same index in the values array
- valFor: function (aAr, vAr, key) {
- var idx = aAr.indexOf(key);
- if ((idx > -1) && (idx < vAr.length)) {
- return vAr[idx];
- }
- return null;
- },
-
- isArtemis: function (d) {
- return d.nodeType ==='on-demand' && !d.properties.product;
- },
-
- isQpid: function (d) {
- return d.nodeType ==='on-demand' && (d.properties && d.properties.product === 'qpid-cpp');
- },
-
- isAConsole: function (properties, connectionId, nodeType, key) {
- return self.isConsole({properties: properties, connectionId: connectionId, nodeType: nodeType, key: key})
- },
- isConsole: function (d) {
- // TODO: use connection properties when available
- if (d.properties.console_identifier == 'Dispatch console')
- return true;
- // until connection properties can difinitively identify consoles:
- var connid = d.connectionId;
- if (connid && d.nodeType === 'normal') {
- // find all the endpoint links for this router that have this connid
- var linkInfo = self.topology.nodeInfo()[d.key]['.router.link']
- var outs = 0, ins = 0;
- var outaddr, inaddr;
- linkInfo.results.forEach( function (link) {
- if (self.valFor(linkInfo.attributeNames, link, 'connectionId') == connid &&
- self.valFor(linkInfo.attributeNames, link, 'linkType') == 'endpoint') {
- if (self.valFor(linkInfo.attributeNames, link, 'linkDir') == 'in') {
- ++ins;
- inaddr = self.valFor(linkInfo.attributeNames, link, 'owningAddr')
- }
- if (self.valFor(linkInfo.attributeNames, link, 'linkDir') == 'out') {
- ++outs;
- outaddr = self.valFor(linkInfo.attributeNames, link, 'owningAddr')
- }
- return true;
- }
- })
- // consoles have 1 out link with an address that starts with Ltemp. and
- // 1 in link with no address
- if (outs == 1 && ins == 1 &&
- inaddr == null && outaddr.startsWith('Ltemp.')) {
- return true;
- }
- }
- return false;
- },
-
- /*
- * send the management messages that build up the topology
- *
- *
- */
- topology: {
- _gettingTopo: false,
- _nodeInfo: {},
- _lastNodeInfo: {},
- _expected: {},
- _timerHandle: null,
-
- nodeInfo: function () {
- return this._gettingTopo ? this._lastNodeInfo : this._nodeInfo;
- },
-
- get: function () {
- if (this._gettingTopo)
- return;
- if (!self.connected) {
- QDR.log.debug("topology get failed because !self.connected")
- return;
- }
- this._lastNodeInfo = angular.copy(this._nodeInfo);
- this._gettingTopo = true;
-
- self.errorText = undefined;
- this.cleanUp(this._nodeInfo);
- this._nodeInfo = {};
- this._expected = {};
-
- // get the list of nodes to query.
- // once this completes, we will get the info for each node returned
- self.getRemoteNodeInfo( function (response, context) {
- //QDR.log.debug("got remote node list of ");
- //console.dump(response);
- if( Object.prototype.toString.call( response ) === '[object Array]' ) {
- if (response.length === 0) {
- // there is only one router, get its node id from the reeciiver
- //"amqp:/_topo/0/Router.A/temp.aSO3+WGaoNUgGVx"
- var address = context.receiver.remote.attach.source.address;
- var addrParts = address.split('/')
- addrParts.splice(addrParts.length-1, 1, '$management')
- response = [addrParts.join('/')]
- }
- // we expect a response for each of these nodes
- self.topology.wait(self.timeout);
- for (var i=0; i<response.length; ++i) {
- self.makeMgmtCalls(response[i]);
- }
- };
- });
- },
-
- cleanUp: function (obj) {
-/*
- for (var o in obj) {
- QDR.log.debug("cleaning up");
- console.dump(obj[o]);
- if (isNaN(parseInt(o)))
- this.cleanUp(obj[o]);
- }
-*/
- if (obj)
- delete obj;
- },
- wait: function (timeout) {
- this.timerHandle = setTimeout(this.timedOut, timeout * 1000);
- },
- timedOut: function () {
- // a node dropped out. this happens when the get-mgmt-nodex
- // results contains more nodes than actually respond within
- // the timeout. However, if the responses we get don't contain
- // the missing node, assume we are done.
- QDR.log.info("timed out waiting for management responses");
- // note: can't use 'this' in a timeout handler
- self.topology.miniDump("state at timeout");
- // check if _nodeInfo is consistent
- if (self.topology.isConsistent()) {
- //TODO: notify controllers which node was dropped
- // so they can keep an event log
- self.topology.ondone();
- return;
- }
- self.topology.onerror(Error("Timed out waiting for management responses"));
- },
- isConsistent: function () {
- // see if the responses we have so far reference any nodes
- // for which we don't have a response
- var gotKeys = {};
- for (var id in this._nodeInfo) {
- var onode = this._nodeInfo[id];
- var conn = onode['.connection'];
- // get list of node names in the connection data
- if (conn) {
- var containerIndex = conn.attributeNames.indexOf('container');
- var connectionResults = conn.results;
- if (containerIndex >= 0)
- for (var j=0; j < connectionResults.length; ++j) {
- // inter-router connection to a valid dispatch connection name
- gotKeys[connectionResults[j][containerIndex]] = ""; // just add the key
- }
- }
- }
- // gotKeys now contains all the container names that we have received
- // Are any of the keys that are still expected in the gotKeys list?
- var keys = Object.keys(gotKeys);
- for (var id in this._expected) {
- var key = self.nameFromId(id);
- if (key in keys)
- return false;
- }
- return true;
- },
-
- addNodeInfo: function (id, entity, values) {
- // save the results in the nodeInfo object
- if (id) {
- if (!(id in self.topology._nodeInfo)) {
- self.topology._nodeInfo[id] = {};
- }
- self.topology._nodeInfo[id][entity] = values;
- }
-
- // remove the id / entity from _expected
- if (id in self.topology._expected) {
- var entities = self.topology._expected[id];
- var idx = entities.indexOf(entity);
- if (idx > -1) {
- entities.splice(idx, 1);
- if (entities.length == 0)
- delete self.topology._expected[id];
- }
- }
- // see if the expected obj is empty
- if (Object.getOwnPropertyNames(self.topology._expected).length == 0)
- self.topology.ondone();
- self.topology.cleanUp(values);
- },
- expect: function (id, key) {
- if (!key || !id)
- return;
- if (!(id in this._expected))
- this._expected[id] = [];
- if (this._expected[id].indexOf(key) == -1)
- this._expected[id].push(key);
- },
- ondone: function () {
- clearTimeout(this.timerHandle);
- this._gettingTopo = false;
- //this.miniDump();
- //this.dump();
- self.notifyTopologyDone();
- },
- dump: function (prefix) {
- if (prefix)
- QDR.log.info(prefix);
- QDR.log.info("---");
- for (var key in this._nodeInfo) {
- QDR.log.info(key);
- console.dump(this._nodeInfo[key]);
- QDR.log.info("---");
- }
- QDR.log.debug("was still expecting:");
- console.dump(this._expected);
- },
- miniDump: function (prefix) {
- if (prefix)
- QDR.log.info(prefix);
- QDR.log.info("---");
- console.dump(Object.keys(this._nodeInfo));
- QDR.log.info("---");
- },
- onerror: function (err) {
- this._gettingTopo = false;
- QDR.log.debug("Err:" + err);
- self.executeDisconnectActions();
-
- }
-
- },
-
- getRemoteNodeInfo: function (callback) {
- //QDR.log.debug("getRemoteNodeInfo called");
- var ret;
- // first get the list of remote node names
- self.correlator.request(
- ret = self.sendMgmtQuery('GET-MGMT-NODES')
- ).then(ret.id, function(response, context) {
- callback(response, context);
- self.topology.cleanUp(response);
- }, ret.error);
- },
-
- makeMgmtCalls: function (id) {
- var keys = [".router", ".connection", ".container", ".router.node", ".listener", ".router.link"];
- $.each(keys, function (i, key) {
- self.topology.expect(id, key);
- self.getNodeInfo(id, key, [], self.topology.addNodeInfo);
- });
- },
-
- getNodeInfo: function (nodeName, entity, attrs, callback) {
- //QDR.log.debug("getNodeInfo called with nodeName: " + nodeName + " and entity " + entity);
- var ret;
- self.correlator.request(
- ret = self.sendQuery(nodeName, entity, attrs)
- ).then(ret.id, function(response) {
- callback(nodeName, entity, response);
- //self.topology.addNodeInfo(nodeName, entity, response);
- //self.topology.cleanUp(response);
- }, ret.error);
- },
-
- getMultipleNodeInfo: function (nodeNames, entity, attrs, callback, selectedNodeId, aggregate) {
- if (!angular.isDefined(aggregate))
- aggregate = true;
- var responses = {};
- var gotNodesResult = function (nodeName, dotentity, response) {
- responses[nodeName] = response;
- if (Object.keys(responses).length == nodeNames.length) {
- if (aggregate)
- self.aggregateNodeInfo(nodeNames, entity, selectedNodeId, responses, callback);
- else {
- callback(nodeNames, entity, responses)
- }
- }
- }
-
- nodeNames.forEach( function (id) {
- self.getNodeInfo(id, '.'+entity, attrs, gotNodesResult);
- })
- //TODO: implement a timeout in case not all requests complete
- },
-
- aggregateNodeInfo: function (nodeNames, entity, selectedNodeId, responses, callback) {
- //QDR.log.debug("got all results for " + entity);
- // aggregate the responses
- var newResponse = {};
- var thisNode = responses[selectedNodeId];
- newResponse['attributeNames'] = thisNode.attributeNames;
- newResponse['results'] = thisNode.results;
- newResponse['aggregates'] = [];
- for (var i=0; i<thisNode.results.length; ++i) {
- var result = thisNode.results[i];
- var vals = [];
- result.forEach( function (val) {
- vals.push({sum: val, detail: []})
- })
- newResponse.aggregates.push(vals);
- }
- var nameIndex = thisNode.attributeNames.indexOf("name");
- var ent = self.schema.entityTypes[entity];
- var ids = Object.keys(responses);
- ids.sort();
- ids.forEach( function (id) {
- var response = responses[id];
- var results = response.results;
- results.forEach( function (result) {
- // find the matching result in the aggregates
- var found = newResponse.aggregates.some( function (aggregate, j) {
- if (aggregate[nameIndex].sum === result[nameIndex]) {
- // result and aggregate are now the same record, add the graphable values
- newResponse.attributeNames.forEach( function (key, i) {
- if (ent.attributes[key] && ent.attributes[key].graph) {
- if (id != selectedNodeId)
- aggregate[i].sum += result[i];
- }
- aggregate[i].detail.push({node: self.nameFromId(id)+':', val: result[i]})
- })
- return true; // stop looping
- }
- return false; // continute looking for the aggregate record
- })
- if (!found) {
- // this attribute was not found in the aggregates yet
- // because it was not in the selectedNodeId's results
- var vals = [];
- result.forEach( function (val) {
- vals.push({sum: val, detail: [{node: self.nameFromId(id), val: val}]})
- })
- newResponse.aggregates.push(vals)
- }
- })
- })
- callback(nodeNames, entity, newResponse);
- },
-
-
- getSchema: function () {
- //QDR.log.debug("getting schema");
- var ret;
- self.correlator.request(
- ret = self.sendMgmtQuery('GET-SCHEMA')
- ).then(ret.id, function(response) {
- //QDR.log.debug("Got schema response");
- // remove deprecated
- for (var entityName in response.entityTypes) {
- var entity = response.entityTypes[entityName]
- if (entity.deprecated) {
- // deprecated entity
- delete response.entityTypes[entityName]
- } else {
- for (var attributeName in entity.attributes) {
- var attribute = entity.attributes[attributeName]
- if (attribute.deprecated) {
- // deprecated attribute
- delete response.entityTypes[entityName].attributes[attributeName]
- }
- }
- }
- }
- self.schema = response;
- self.topology.get();
- }, ret.error);
- },
-
- getNodeInfo: function (nodeName, entity, attrs, callback) {
- //QDR.log.debug("getNodeInfo called with nodeName: " + nodeName + " and entity " + entity);
- var ret;
- self.correlator.request(
- ret = self.sendQuery(nodeName, entity, attrs)
- ).then(ret.id, function(response) {
- callback(nodeName, entity, response);
- //self.topology.addNodeInfo(nodeName, entity, response);
- //self.topology.cleanUp(response);
- }, ret.error);
- },
-
- sendMethod: function (nodeId, entity, attrs, operation, callback) {
- var ret;
- self.correlator.request(
- ret = self._sendMethod(nodeId, entity, attrs, operation)
- ).then(ret.id, function (response, context) {
- callback(nodeId, entity, response, context);
- }, ret.error);
- },
-
- _fullAddr: function (toAddr) {
- var toAddrParts = toAddr.split('/');
- if (toAddrParts.shift() != "amqp:") {
- self.topology.error(Error("unexpected format for router address: " + toAddr));
- return;
- }
- //var fullAddr = self.toAddress + "/" + toAddrParts.join('/');
- var fullAddr = toAddrParts.join('/');
- return fullAddr;
- },
-
- _sendMethod: function (toAddr, entity, attrs, operation) {
- var fullAddr = self._fullAddr(toAddr);
- var ret = {id: self.correlator.corr()};
- if (!self.sender || !self.sendable) {
- ret.error = "no sender"
- return ret;
- }
- try {
- var application_properties = {
- operation: operation
- }
- var ent = self.schema.entityTypes[entity];
- var fullyQualifiedType = ent.fullyQualifiedType;
- if (fullyQualifiedType) {
- application_properties.type = fullyQualifiedType
- }
- else
- application_properties.type = entity;
- if (attrs.name)
- application_properties.name = attrs.name;
- var msg = {
- body: attrs,
- properties: {
- to: fullAddr,
- reply_to: self.receiver.remote.attach.source.address,
- correlation_id: ret.id
- },
- application_properties: application_properties
- }
- self.sender.send( msg );
- console.dump("------- method called -------")
- console.dump (msg)
- }
- catch (e) {
- error = "error sending: " + e;
- QDR.log.error(error)
- ret.error = error;
- }
- return ret;
- },
-
- sendQuery: function(toAddr, entity, attrs, operation) {
- operation = operation || "QUERY"
- var fullAddr = self._fullAddr(toAddr);
-
- var body;
- if (attrs)
- body = {
- "attributeNames": attrs,
- }
- else
- body = {
- "attributeNames": [],
- }
- if (entity[0] === '.')
- entity = entity.substr(1, entity.length-1)
- var prefix = "org.apache.qpid.dispatch."
- var configs = ["address", "autoLink", "linkRoute"]
- if (configs.indexOf(entity) > -1)
- prefix += "router.config."
- return self._send(body, fullAddr, operation, prefix + entity);
- },
-
- sendMgmtQuery: function (operation) {
- return self._send([], "/$management", operation);
- },
-
- _send: function (body, to, operation, entityType) {
- var ret = {id: self.correlator.corr()};
- if (!self.sender || !self.sendable) {
- ret.error = "no sender"
- return ret;
- }
- try {
- var application_properties = {
- operation: operation,
- type: "org.amqp.management",
- name: "self"
- };
- if (entityType)
- application_properties.entityType = entityType;
-
- self.sender.send({
- body: body,
- properties: {
- to: to,
- reply_to: self.receiver.remote.attach.source.address,
- correlation_id: ret.id
- },
- application_properties: application_properties
- })
- }
- catch (e) {
- error = "error sending: " + e;
- QDR.log.error(error)
- ret.error = error;
- }
- return ret;
- },
-
- disconnect: function() {
- self.connection.close();
- self.errorText = "Disconnected."
- },
-
- connect: function(options) {
- self.options = options;
- self.topologyInitialized = false;
- if (!self.connected) {
- var okay = {connection: false, sender: false, receiver: false}
- var port = options.port || 5673;
- var baseAddress = options.address + ':' + port;
- var ws = self.rhea.websocket_connect(WebSocket);
- self.toAddress = "amqp://" + baseAddress;
- self.connectionError = undefined;
-
- var stop = function (context) {
- //self.stopUpdating();
- okay.sender = false;
- okay.receiver = false;
- okay.connected = false;
- self.connected = false;
- self.sender = null;
- self.receiver = null;
- self.sendable = false;
- self.gotTopology = false;
- }
- var maybeStart = function () {
- if (okay.connection && okay.sender && okay.receiver && self.sendable && !self.connected) {
- QDR.log.info("okay to start")
- self.connected = true;
- self.connection = connection;
- self.sender = sender;
- self.receiver = receiver;
- self.onSubscription();
- self.gotTopology = false;
- }
- }
- var onDisconnect = function () {
- //QDR.log.warn("Disconnected");
- self.connectionError = true;
- stop();
- self.executeDisconnectActions();
- }
-
- QDR.log.debug("****** calling rhea.connect ********")
- var connection;
- try {
- connection = self.rhea.connect({
- connection_details:ws('ws://' + baseAddress, ["binary", "AMQWSB10"]),
- reconnect:true,
- properties: {console_identifier: 'Dispatch console'}
- });
- }
- catch (e) {
- QDR.log.debug("exception caught on connect")
- self.errorText = "Connection failed"
- onDisconnect();
- }
- if (!self.connectionError) {
- connection.on('connection_open', function (context) {
- QDR.log.debug("connection_opened")
- okay.connection = true;
- okay.receiver = false;
- okay.sender = false;
- })
- connection.on('disconnected', function (context) {
- QDR.log.debug("connection disconnected")
- self.errorText = "Unable to connect"
- onDisconnect();
- })
- connection.on('connection_close', function (context) {
- QDR.log.debug("connection closed")
- self.errorText = "Disconnected"
- onDisconnect();
- })
-
- var sender = connection.open_sender();
- sender.on('sender_open', function (context) {
- QDR.log.debug("sender_opened")
- okay.sender = true
- maybeStart()
- })
- sender.on('sendable', function (context) {
- //QDR.log.debug("sendable")
- self.sendable = true;
- maybeStart();
- })
-
- var receiver = connection.open_receiver({source: {dynamic: true}});
- receiver.on('receiver_open', function (context) {
- QDR.log.debug("receiver_opened")
- okay.receiver = true;
- maybeStart()
- })
- receiver.on("message", function (context) {
- self.correlator.resolve(context);
- });
- }
- }
- }
- }
- return self;
- }]);
-
- return QDR;
-}(QDR || {}));
-
-(function() {
- console.dump = function(object) {
- if (window.JSON && window.JSON.stringify)
- QDR.log.info(JSON.stringify(object,undefined,2));
- else
- console.log(object);
- };
-})();
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrService.js b/console/hawtio/src/main/webapp/plugin/js/qdrService.js
new file mode 120000
index 0000000..2d2a672
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrService.js
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/js/qdrService.js
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[05/11] qpid-dispatch git commit: DISPATCH-316 Hawtio and stand-alone
consoles now use common code
Posted by ea...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/html/tmplListChart.html
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/html/tmplListChart.html b/console/stand-alone/plugin/html/tmplListChart.html
new file mode 100644
index 0000000..e52a39a
--- /dev/null
+++ b/console/stand-alone/plugin/html/tmplListChart.html
@@ -0,0 +1,18 @@
+<!--
+ This is the template for the graph dialog that is displayed.
+-->
+<div class="modal-header">
+ <h3 class="modal-title">Chart {{chart.attr() | humanify}}</h3>
+</div>
+<div class="modal-body">
+ <div id="{{svgDivId}}" class="d3Chart"></div>
+</div>
+<div class="modal-footer">
+ <span ng-hide="isOnChartsPage()">
+ <button class="btn btn-success" type="button" ng-click="addChartsPage()"><i class="icon-bar-chart"></i> Add</button> this chart to the Charts page.
+ </span>
+ <span ng-show="isOnChartsPage()">
+ <button class="btn btn-danger" type="button" ng-click="delChartsPage()">Remove</button> this chart from the <button class="btn btn-success" type="button" ng-click="showChartsPage()"><i class="icon-bar-chart"></i> Charts</button> page.
+ </span>
+ <button class="btn btn-primary" type="button" ng-click="ok()">Close</button>
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/html/tmplListTree.html
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/html/tmplListTree.html b/console/stand-alone/plugin/html/tmplListTree.html
new file mode 100644
index 0000000..9aa8be5
--- /dev/null
+++ b/console/stand-alone/plugin/html/tmplListTree.html
@@ -0,0 +1,17 @@
+<div class="qdr-attributes pane left" position="left" width="300">
+ <div class="pane-wrapper">
+ <div class="pane-header-wrapper">
+ </div>
+ <div class="pane-viewport">
+ <div class="pane-content">
+ <div class="treeContainer">
+ <div class="tree-header"><select ng-options="node as node.name for node in nodes" ng-model="currentNode" ng-change="selectNode(currentNode)"></select></div>
+ <div id="entityTree" onSelect="onTreeSelected" onRoot="onRootReady" hideRoot="true"></div>
+ <div ng-init="treeReady()"></div>
+ </div>
+ </div>
+ </div>
+ <div class="pane-bar"></div>
+ </div>
+</div>
+<ng-include src="'listGrid.html'"></ng-include>
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/html/tmplOverviewTree.html
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/html/tmplOverviewTree.html b/console/stand-alone/plugin/html/tmplOverviewTree.html
new file mode 100644
index 0000000..4346b9c
--- /dev/null
+++ b/console/stand-alone/plugin/html/tmplOverviewTree.html
@@ -0,0 +1,15 @@
+<div class="qdr-overview pane left" position="left" width="300">
+ <div class="pane-wrapper">
+ <div class="pane-header-wrapper">
+ </div>
+ <div class="pane-viewport">
+ <div class="pane-content">
+ <div class="treeContainer ng-scope">
+ <div id="overtree"></div>
+ </div>
+ </div>
+ </div>
+ <div class="pane-bar" ng-mousedown="startMoving($event)" ng-click="toggle()"></div>
+ </div>
+</div>
+<ng-include src="'overviewGrid.html'"></ng-include>
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/js/dispatchPlugin.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/dispatchPlugin.js b/console/stand-alone/plugin/js/dispatchPlugin.js
new file mode 100644
index 0000000..e8078e9
--- /dev/null
+++ b/console/stand-alone/plugin/js/dispatchPlugin.js
@@ -0,0 +1,254 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you 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.
+*/
+/**
+ * @module QDR
+ * @main QDR
+ *
+ * The main entry point for the QDR module
+ *
+ */
+var QDR = (function(QDR) {
+
+ /**
+ * @property pluginName
+ * @type {string}
+ *
+ * The name of this plugin
+ */
+ QDR.pluginName = "QDR";
+ QDR.pluginRoot = "";
+ QDR.isStandalone = true;
+
+ /**
+ * @property log
+ * @type {Logging.Logger}
+ *
+ * This plugin's logger instance
+ */
+ //HIO QDR.log = Logger.get(QDR.pluginName);
+ /**
+ * @property templatePath
+ * @type {string}
+ *
+ * The top level path to this plugin's partials
+ */
+ QDR.srcBase = "plugin/";
+ QDR.templatePath = QDR.srcBase + "html/";
+ QDR.cssPath = QDR.srcBase + "css/";
+ /**
+ * @property SETTINGS_KEY
+ * @type {string}
+ *
+ * The key used to fetch our settings from local storage
+ */
+ QDR.SETTINGS_KEY = 'QDRSettings';
+ QDR.LAST_LOCATION = "QDRLastLocation";
+
+ /**
+ * @property module
+ * @type {object}
+ *
+ * This plugin's angularjs module instance
+ */
+ QDR.module = angular.module(QDR.pluginName, ['ngResource', 'ngGrid', 'ui.bootstrap', 'ui.slider'/*, 'minicolors' */]);
+
+ // set up the routing for this plugin
+ QDR.module.config(function($routeProvider) {
+ $routeProvider
+ .when('/', {
+ templateUrl: QDR.templatePath + 'qdrConnect.html'
+ })
+ .when('/overview', {
+ templateUrl: QDR.templatePath + 'qdrOverview.html'
+ })
+ .when('/topology', {
+ templateUrl: QDR.templatePath + 'qdrTopology.html'
+ })
+ .when('/list', {
+ templateUrl: QDR.templatePath + 'qdrList.html'
+ })
+ .when('/schema', {
+ templateUrl: QDR.templatePath + 'qdrSchema.html'
+ })
+ .when('/charts', {
+ templateUrl: QDR.templatePath + 'qdrCharts.html'
+ })
+ .when('/connect', {
+ templateUrl: QDR.templatePath + 'qdrConnect.html'
+ })
+ .otherwise({
+ templateUrl: QDR.templatePath + 'qdrConnect.html'
+ })
+ });
+
+ QDR.module.config(function ($compileProvider) {
+ var cur = $compileProvider.urlSanitizationWhitelist();
+ $compileProvider.urlSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|blob):/);
+ cur = $compileProvider.urlSanitizationWhitelist();
+ })
+
+ QDR.module.filter('to_trusted', ['$sce', function($sce){
+ return function(text) {
+ return $sce.trustAsHtml(text);
+ };
+ }]);
+
+ QDR.module.filter('humanify', function (QDRService) {
+ return function (input) {
+ return QDRService.humanify(input);
+ };
+ });
+
+ QDR.module.filter('Pascalcase', function () {
+ return function (str) {
+ if (!str)
+ return "";
+ return str.replace(/(\w)(\w*)/g,
+ function(g0,g1,g2){return g1.toUpperCase() + g2.toLowerCase();});
+ }
+ })
+
+ QDR.module.filter('safePlural', function () {
+ return function (str) {
+ var es = ['x', 'ch', 'ss', 'sh']
+ for (var i=0; i<es.length; ++i) {
+ if (str.endsWith(es[i]))
+ return str + 'es'
+ }
+ if (str.endsWith('y'))
+ return str.substr(0, str.length-2) + 'ies'
+ if (str.endsWith('s'))
+ return str;
+ return str + 's'
+ }
+ })
+
+ QDR.logger = function ($log) {
+ var log = $log;
+
+ this.debug = function (msg) { msg = "QDR: " + msg; log.debug(msg)};
+ this.error = function (msg) {msg = "QDR: " + msg; log.error(msg)}
+ this.info = function (msg) {msg = "QDR: " + msg; log.info(msg)}
+ this.warn = function (msg) {msg = "QDR: " + msg; log.warn(msg)}
+
+ return this;
+ }
+ // one-time initialization happens in the run function
+ // of our module
+ QDR.module.run( ["$rootScope", '$route', '$timeout', "$location", "$log", "QDRService", "QDRChartService", function ($rootScope, $route, $timeout, $location, $log, QDRService, QDRChartService) {
+ QDR.log = new QDR.logger($log);
+ QDR.log.info("*************creating Dispatch Console************");
+ var curPath = $location.path()
+ var org = curPath.substr(1)
+ if (org && org.length > 0 && org !== "connect") {
+ $location.search('org', org)
+ } else {
+ $location.search('org', null)
+ }
+
+ QDRService.initProton();
+ var settings = angular.fromJson(localStorage[QDR.SETTINGS_KEY]);
+ QDRService.addConnectAction(function() {
+ QDRChartService.init(); // initialize charting service after we are connected
+ });
+ if (settings && settings.autostart) {
+ QDRService.addDisconnectAction( function () {
+ $timeout(function () {
+ var lastLocation = localStorage[QDR.LAST_LOCATION] || "/overview";
+ org = lastLocation.substr(1)
+ $location.path("/connect");
+ $location.search('org', org)
+ })
+ })
+ QDRService.addConnectAction(function() {
+ var searchObject = $location.search();
+ // the redirect will be handled by QDRService when connected
+ if (searchObject.org) {
+ return;
+ }
+ // there was no org= parameter, so redirect to last known location
+ $timeout(function () {
+ var lastLocation = localStorage[QDR.LAST_LOCATION] || "/overview";
+ $location.path(lastLocation);
+ })
+ });
+ QDRService.connect(settings);
+ } else {
+ $timeout(function () {
+ $location.path('/connect')
+ $location.search('org', org)
+ })
+ }
+
+ $rootScope.$on('$routeChangeSuccess', function() {
+ var path = $location.path();
+ if (path !== "/connect") {
+ localStorage[QDR.LAST_LOCATION] = path;
+ }
+ });
+
+ }]);
+
+ QDR.module.controller ("QDR.MainController", ['$scope', '$location', function ($scope, $location) {
+ QDR.log.debug("started QDR.MainController with location.url: " + $location.url());
+ QDR.log.debug("started QDR.MainController with window.location.pathname : " + window.location.pathname);
+ $scope.topLevelTabs = [];
+ $scope.topLevelTabs.push({
+ id: "qdr",
+ content: "Qpid Dispatch Router Console",
+ title: "Dispatch Router Console",
+ isValid: function() { return true; },
+ href: function() { return "#connect"; },
+ isActive: function() { return true; }
+ });
+ }])
+
+ QDR.module.controller ("QDR.Core", function ($scope, $rootScope) {
+ $scope.alerts = [];
+ $scope.closeAlert = function(index) {
+ $scope.alerts.splice(index, 1);
+ };
+ $scope.$on('newAlert', function(event, data) {
+ $scope.alerts.push(data);
+ $scope.$apply();
+ });
+ $scope.$on("clearAlerts", function () {
+ $scope.alerts = [];
+ $scope.$apply();
+ })
+
+ })
+
+ return QDR;
+}(QDR || {}));
+
+var Folder = (function () {
+ function Folder(title) {
+ this.title = title;
+ this.children = [];
+ this.folder = true;
+ }
+ return Folder;
+})();
+var Leaf = (function () {
+ function Leaf(title) {
+ this.title = title;
+ }
+ return Leaf;
+})();
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/js/navbar.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/navbar.js b/console/stand-alone/plugin/js/navbar.js
index ebda4d4..337be52 100644
--- a/console/stand-alone/plugin/js/navbar.js
+++ b/console/stand-alone/plugin/js/navbar.js
@@ -34,39 +34,38 @@ var QDR = (function (QDR) {
content: '<i class="icon-cogs"></i> Connect',
title: "Connect to a router",
isValid: function () { return true; },
- href: "#connect"
+ href: "#" + QDR.pluginRoot + "/connect"
},
{
- content: '<i class="fa fa-home"></i> Overview',
+ content: '<i class="icon-home"></i> Overview',
title: "View router overview",
isValid: function (QDRService) { return QDRService.isConnected(); },
- href: "#/overview"
+ href: "#" + QDR.pluginRoot + "/overview"
},
{
- content: '<i class="icon-star-empty"></i> Topology',
- title: "View router network topology",
+ content: '<i class="icon-list "></i> Entities',
+ title: "View the attributes of the router entities",
isValid: function (QDRService) { return QDRService.isConnected(); },
- href: "#/topology"
+ href: "#" + QDR.pluginRoot + "/list"
},
{
- content: '<i class="icon-list "></i> List',
- title: "View router nodes as a list",
+ content: '<i class="icon-star-empty"></i> Topology',
+ title: "View router network topology",
isValid: function (QDRService) { return QDRService.isConnected(); },
- href: "#/list"
+ href: "#" + QDR.pluginRoot + "/topology"
},
{
content: '<i class="icon-bar-chart"></i> Charts',
title: "View charts",
- isValid: function (QDRService, $location) { return QDRService.isConnected(); },
+ isValid: function (QDRService, $location) { return QDRService.isConnected() && QDR.isStandalone; },
href: "#/charts"
},
{
content: '<i class="icon-align-left"></i> Schema',
title: "View dispatch schema",
isValid: function (QDRService) { return QDRService.isConnected(); },
- href: "#/schema",
+ href: "#" + QDR.pluginRoot + "/schema",
right: true
-
}
];
/**
@@ -78,28 +77,16 @@ var QDR = (function (QDR) {
* The controller for this plugin's navigation bar
*
*/
- QDR.module.controller("QDR.NavBarController", ['$scope', '$sce', 'QDRService', 'QDRChartService', '$location', function($scope, $sce, QDRService, QDRChartService, $location) {
-
- QDR.log.debug("navbar started with location.url: " + $location.url());
- QDR.log.debug("navbar started with window.location.pathname : " + window.location.pathname);
-
- if ($location.path().startsWith("/topology")
- && !QDRService.isConnected()) {
- $location.path("/connect");
- }
-
- if ($location.path().startsWith("/connect")
- && QDRService.isConnected()) {
- $location.path("/topology");
- }
-
+ QDR.module.controller("QDR.NavBarController", ['$scope', 'QDRService', 'QDRChartService', '$routeParams', '$location', function($scope, QDRService, QDRChartService, $routeParams, $location) {
$scope.breadcrumbs = QDR.breadcrumbs;
-
$scope.isValid = function(link) {
return link.isValid(QDRService, $location);
};
$scope.isActive = function(href) {
+ // highlight the connect tab if we are on the root page
+ if (($location.path() === QDR.pluginRoot) && (href.split("#")[1] === QDR.pluginRoot + "/connect"))
+ return true
return href.split("#")[1] == $location.path();
};
@@ -112,8 +99,30 @@ var QDR = (function (QDR) {
return QDRChartService.charts.some(function (c) { return c.dashboard });
}
}
+
+ $scope.isDashboardable = function () {
+ return ($location.path().indexOf("schema") < 0 && $location.path().indexOf("connect") < 0);
+ }
+
+ $scope.addToDashboardLink = function () {
+ var href = "#" + $location.path();
+ var size = angular.toJson({
+ size_x: 2,
+ size_y: 2
+ });
+
+ var routeParams = angular.toJson($routeParams);
+ var title = "Dispatch Router";
+ return "/hawtio/#/dashboard/add?tab=dashboard" +
+ "&href=" + encodeURIComponent(href) +
+ "&routeParams=" + encodeURIComponent(routeParams) +
+ "&title=" + encodeURIComponent(title) +
+ "&size=" + encodeURIComponent(size);
+ };
+
}]);
+
return QDR;
} (QDR || {}));
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/js/qdrChartService.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrChartService.js b/console/stand-alone/plugin/js/qdrChartService.js
index efc607d..47cb47d 100644
--- a/console/stand-alone/plugin/js/qdrChartService.js
+++ b/console/stand-alone/plugin/js/qdrChartService.js
@@ -22,8 +22,8 @@ under the License.
var QDR = (function(QDR) {
// The QDR chart service handles periodic gathering data for charts and displaying the charts
- QDR.module.factory("QDRChartService", ['$rootScope', 'QDRService', '$http', '$resource',
- function($rootScope, QDRService, $http, $resource) {
+ QDR.module.factory("QDRChartService", ['$rootScope', 'QDRService', '$http', '$resource', '$location',
+ function($rootScope, QDRService, $http, $resource, $location) {
var instance = 0; // counter for chart instances
var bases = [];
@@ -56,26 +56,32 @@ var QDR = (function(QDR) {
// Object that represents a visible chart
// There can be multiple of these per ChartBase (eg. one rate and one value chart)
- function Chart(name, attr, request) {
+ function Chart(opts, request) { //name, attr, cinstance, request) {
- var base = findBase(name, attr, request);
+ var base = findBase(opts.name, opts.attr, request);
if (!base) {
- base = new ChartBase(name, attr, request);
+ base = new ChartBase(opts.name, opts.attr, request);
bases.push(base);
}
this.base = base;
- this.instance = instance++;
+ this.instance = angular.isDefined(opts.instance) ? opts.instance : ++instance;
this.dashboard = false; // is this chart on the dashboard page
- this.type = "value"; // value or rate
- this.rateWindow = 1000; // calculate the rate of change over this time interval. higher == smother graph
- this.areaColor = "#c0e0ff"; // the chart's area color when not an empty string
- this.lineColor = "#4682b4"; // the chart's line color when not an empty string
- this.visibleDuration = 10; // number of minutes of data to show (<= base.duration)
+ this.hdash = false; // is this chart on the hawtio dashboard page
+ this.hreq = false; // has this hdash chart been requested
+ this.type = opts.type ? opts.type: "value"; // value or rate
+ this.rateWindow = opts.rateWindow ? opts.rateWindow : 1000; // calculate the rate of change over this time interval. higher == smother graph
+ this.areaColor = "#cbe7f3"; // the chart's area color when not an empty string
+ this.lineColor = "#058dc7"; // the chart's line color when not an empty string
+ this.visibleDuration = opts.visibleDuration ? opts.visibleDuration : 10; // number of minutes of data to show (<= base.duration)
this.userTitle = null; // user title overrides title()
// generate a unique id for this chart
this.id = function () {
- var key = this.request().nodeId + this.request().entity + this.name() + this.attr() + "_" + this.instance;
+ var name = this.name()
+ var nameparts = name.split('/');
+ if (nameparts.length == 2)
+ name = nameparts[1];
+ var key = QDRService.nameFromId(this.request().nodeId) + this.request().entity + name + this.attr() + "_" + this.instance + "_" + (this.request().aggregate ? "1" : "0");
// remove all characters except letters,numbers, and _
return key.replace(/[^\w]/gi, '')
}
@@ -87,6 +93,9 @@ var QDR = (function(QDR) {
o.lineColor = this.lineColor;
o.visibleDuration = this.visibleDuration;
o.userTitle = this.userTitle;
+ o.dashboard = this.dashboard;
+ o.hdash = this.hdash;
+ o.instance = this.instance;
this.base.copyProps(o);
}
this.name = function (_) {
@@ -109,6 +118,11 @@ var QDR = (function(QDR) {
this.base.request.entity = _;
return this;
}
+ this.aggregate = function (_) {
+ if (!arguments.length) return this.base.request.aggregate;
+ this.base.request.aggregate = _;
+ return this;
+ }
this.request = function (_) {
if (!arguments.length) return this.base.request;
this.base.request = _;
@@ -145,8 +159,16 @@ var QDR = (function(QDR) {
return this;
}
this.copy = function () {
- var chart = self.registerChart(this.nodeId(), this.entity(),
- this.name(), this.attr(), this.interval(), true, this.base.request.aggregate);
+ var chart = self.registerChart({
+ nodeId: this.nodeId(),
+ entity: this.entity(),
+ name: this.name(),
+ attr: this.attr(),
+ interval: this.interval(),
+ forceCreate: true,
+ aggregate: this.aggregate(),
+ hdash: this.hdash
+ })
chart.type = this.type;
chart.areaColor = this.areaColor;
chart.lineColor = this.lineColor;
@@ -167,17 +189,17 @@ var QDR = (function(QDR) {
}
// Object that represents the management request to fetch and store data for multiple charts
- function ChartRequest(nodeId, entity, name, attr, interval, aggregate) {
- this.duration = 10; // number of minutes to keep the data
- this.nodeId = nodeId; // eg amqp:/_topo/0/QDR.A/$management
- this.entity = entity; // eg .router.address
+ function ChartRequest(opts) { //nodeId, entity, name, attr, interval, aggregate) {
+ this.duration = opts.duration || 10; // number of minutes to keep the data
+ this.nodeId = opts.nodeId; // eg amqp:/_topo/0/QDR.A/$management
+ this.entity = opts.entity; // eg .router.address
// sorted since the responses will always be sorted
- this.aggregate = aggregate; // list of nodeIds for aggregate charts
- this.datum = {}; // object containing array of arrays for each attr
- // like {attr1: [[date,value],[date,value]...], attr2: [[date,value]...]}
+ this.aggregate = opts.aggregate; // list of nodeIds for aggregate charts
+ this.datum = {}; // object containing array of arrays for each attr
+ // like {attr1: [[date,value],[date,value]...], attr2: [[date,value]...]}
- this.interval = interval; // number of milliseconds between updates to data
- this.setTimeoutHandle = null; // used to cancel the next request
+ this.interval = opts.interval || 1000; // number of milliseconds between updates to data
+ this.setTimeoutHandle = null; // used to cancel the next request
// copy the savable properties to an object
this.data = function (name, attr) {
@@ -193,7 +215,7 @@ var QDR = (function(QDR) {
this.datum[name][attr] = [];
}
}
- this.addAttrName(name, attr)
+ this.addAttrName(opts.name, opts.attr)
this.copyProps = function (o) {
o.nodeId = this.nodeId;
@@ -232,6 +254,8 @@ var QDR = (function(QDR) {
return Object.keys(attrs);
}
};
+
+ // Below here are the properties and methods available on QDRChartService
var self = {
charts: [], // list of charts to gather data for
chartRequests: [], // the management request info (multiple charts can be driven off of a single request
@@ -251,12 +275,15 @@ var QDR = (function(QDR) {
return ret;
},
- findCharts: function (name, attr, nodeId, entity) {
+ findCharts: function (opts) { //name, attr, nodeId, entity, hdash) {
+ if (!opts.hdash)
+ opts.hdash = false; // rather than undefined
return self.charts.filter( function (chart) {
- return (chart.name() == name &&
- chart.attr() == attr &&
- chart.nodeId() == nodeId &&
- chart.entity() == entity)
+ return (chart.name() == opts.name &&
+ chart.attr() == opts.attr &&
+ chart.nodeId() == opts.nodeId &&
+ chart.entity() == opts.entity &&
+ chart.hdash == opts.hdash)
});
},
@@ -290,22 +317,24 @@ var QDR = (function(QDR) {
}
},
- registerChart: function (nodeId, entity, name, attr, interval, forceCreate, aggregate) {
- var request = self.findChartRequest(nodeId, entity, aggregate);
+ registerChart: function (opts) { //nodeId, entity, name, attr, interval, instance, forceCreate, aggregate, hdash) {
+ var request = self.findChartRequest(opts.nodeId, opts.entity, opts.aggregate);
if (request) {
// add any new attr or name to the list
- request.addAttrName(name, attr)
+ request.addAttrName(opts.name, opts.attr)
} else {
// the nodeId/entity did not already exist, so add a new request and chart
- QDR.log.debug("added new request: " + nodeId + " " + entity);
- request = new ChartRequest(nodeId, entity, name, attr, interval, aggregate);
+ QDR.log.debug("added new request: " + opts.nodeId + " " + opts.entity);
+ request = new ChartRequest(opts); //nodeId, entity, name, attr, interval, aggregate);
self.chartRequests.push(request);
self.startCollecting(request);
}
- var charts = self.findCharts(name, attr, nodeId, entity);
+ var charts = self.findCharts(opts); //name, attr, nodeId, entity, hdash);
var chart;
- if (charts.length == 0 || forceCreate) {
- chart = new Chart(name, attr, request);
+ if (charts.length == 0 || opts.forceCreate) {
+ if (!opts.use_instance && opts.instance)
+ delete opts.instance;
+ chart = new Chart(opts, request) //opts.name, opts.attr, opts.instance, request);
self.charts.push(chart);
} else {
chart = charts[0];
@@ -317,6 +346,16 @@ var QDR = (function(QDR) {
// if all attrs are gone for this request, remove the request
unRegisterChart: function (chart) {
// remove the chart
+
+ // TODO: how do we remove charts that were added to the hawtio dashboard but then removed?
+ // We don't get a notification that they were removed. Instead, we could just stop sending
+ // the request in the background and only send the request when the chart's tick() event is triggered
+ //if (chart.hdash) {
+ // chart.dashboard = false;
+ // self.saveCharts();
+ // return;
+ //}
+
for (var i=0; i<self.charts.length; ++i) {
var c = self.charts[i];
if (chart.equals(c)) {
@@ -337,6 +376,8 @@ var QDR = (function(QDR) {
}
}
}
+ self.saveCharts();
+
},
stopCollecting: function (request) {
@@ -350,16 +391,29 @@ var QDR = (function(QDR) {
// Using setTimeout instead of setInterval because the response may take longer than interval
request.setTimeoutHandle = setTimeout(self.sendChartRequest, request.interval, request);
},
+ shouldRequest: function (request) {
+ // see if any of the charts associated with this request have either dialog, dashboard, or hreq
+ return self.charts.some( function (chart) {
+ return (chart.dashboard || chart.hreq) || (!chart.dashboard && !chart.hdash);
+ });
+ },
// send the request
- sendChartRequest: function (request) {
+ sendChartRequest: function (request, once) {
+ if (!once && !self.shouldRequest(request)) {
+ request.setTimeoutHandle = setTimeout(self.sendChartRequest, request.interval, request)
+ return;
+ }
+
// ensure the response has the name field so we can associate the response values with the correct chart
var attrs = request.attrs();
attrs.push("name");
// this is called when the response is received
var saveResponse = function (nodeId, entity, response) {
- QDR.log.debug("got chart results for " + nodeId + " " + entity);
- // records an array that has data for all names
+ if (!response || !response.attributeNames)
+ return;
+ //QDR.log.debug("got chart results for " + nodeId + " " + entity);
+ // records is an array that has data for all names
var records = response.results;
if (!records)
return;
@@ -397,27 +451,52 @@ var QDR = (function(QDR) {
}
if (request.aggregate) {
var nodeList = QDRService.nodeIdList()
- QDR.log.debug("sent multiple chart request for " + nodeList + " " + request.entity, + " " + attrs + " " + request.nodeId);
QDRService.getMultipleNodeInfo(nodeList, request.entity, attrs, saveResponse, request.nodeId);
} else {
- QDR.log.debug("sent chart request for " + request.nodeId + " " + request.entity + " " + attrs);
QDRService.getNodeInfo(request.nodeId, request.entity, attrs, saveResponse);
}
- // it is now safe to send another request
+ // it is now safe to schedule another request
+ if (once)
+ return;
request.setTimeoutHandle = setTimeout(self.sendChartRequest, request.interval, request)
},
numCharts: function () {
- return self.charts.length;
+ return self.charts.filter( function (chart) { return chart.dashboard }).length;
+ //return self.charts.length;
},
isAttrCharted: function (nodeId, entity, name, attr) {
- var charts = self.findCharts(name, attr, nodeId, entity);
+ var charts = self.findCharts({
+ name: name,
+ attr: attr,
+ nodeId: nodeId,
+ entity: entity
+ })
// if any of the matching charts are on the dashboard page, return true
return charts.some(function (chart) {
return (chart.dashboard) });
},
+ addHDash: function (chart) {
+ chart.hdash = true;
+ self.saveCharts();
+ /*
+ if (!chart.hdash) {
+ var dashChart = self.registerChart(chart.nodeId(), chart.entity(),
+ chart.name(), chart.attr(), chart.interval(), true, chart.aggregate(), true);
+ dashChart.dashboard = true;
+ dashChart.hdash = false;
+ chart.dashboard = false;
+ chart.hdash = true;
+ self.saveCharts();
+ }
+ */
+ },
+ delHDash: function (chart) {
+ chart.hdash = false;
+ self.saveCharts();
+ },
addDashboard: function (chart) {
chart.dashboard = true;
self.saveCharts();
@@ -434,7 +513,7 @@ var QDR = (function(QDR) {
self.charts.forEach(function (chart) {
var minChart = {};
// don't save chart unless it is on the dashboard
- if (chart.dashboard) {
+ if (chart.dashboard || chart.hdash) {
chart.copyProps(minChart);
minCharts.push(minChart);
}
@@ -469,8 +548,53 @@ var QDR = (function(QDR) {
})
}
},
+ loadCharts: function () {
+ var charts = angular.fromJson(localStorage["QDRCharts"]);
+ if (charts) {
+ // get array of known ids
+ var nodeList = QDRService.nodeList().map( function (node) {
+ return node.id;
+ })
+ charts.forEach(function (chart) {
+ // if this chart is not in the current list of nodes, skip
+ if (nodeList.indexOf(chart.nodeId) >= 0) {
+ if (!angular.isDefined(chart.instance)) {
+ chart.instance = ++instance;
+ }
+ if (chart.instance >= instance)
+ instance = chart.instance + 1;
+ if (!chart.duration)
+ chart.duration = 10;
+ if (chart.nodeList)
+ chart.aggregate = true;
+ if (!chart.hdash)
+ chart.hdash = false;
+ if (!chart.dashboard)
+ chart.dashboard = false;
+ if (!chart.hdash && !chart.dashboard)
+ chart.dashboard = true;
+ if (chart.hdash && chart.dashboard)
+ chart.dashboard = false;
+ chart.forceCreate = true;
+ chart.use_instance = true;
+ var newChart = self.registerChart(chart); //chart.nodeId, chart.entity, chart.name, chart.attr, chart.interval, true, chart.aggregate);
+ newChart.dashboard = chart.dashboard;
+ newChart.hdash = chart.hdash;
+ newChart.hreq = false;
+ newChart.type = chart.type;
+ newChart.rateWindow = chart.rateWindow;
+ newChart.areaColor = chart.areaColor ? chart.areaColor : "#cbe7f3";
+ newChart.lineColor = chart.lineColor ? chart.lineColor : "#058dc7";
+ newChart.duration(chart.duration);
+ newChart.visibleDuration = chart.visibleDuration ? chart.visibleDuration : 10;
+ if (chart.userTitle)
+ newChart.title(chart.userTitle);
+ }
+ })
+ }
+ },
- AreaChart: function (chart, url) {
+ AreaChart: function (chart) {
if (!chart)
return;
@@ -478,11 +602,7 @@ var QDR = (function(QDR) {
var stacked = chart.request().aggregate;
this.chart = chart; // reference to underlying chart
this.svgchart = null;
- if (url)
- url = "/dispatch" + url;
- else
- url = "";
- this.url = url;
+ this.url = $location.absUrl();
// callback function. called by svgchart when binding data
// the variable 'this' refers to the svg and not the AreaChart,
@@ -600,7 +720,8 @@ var QDR = (function(QDR) {
this.chart.name(),
QDRService.nameFromId(this.chart.nodeId()),
this.chart.entity(),
- stacked)
+ stacked,
+ this.chart.visibleDuration)
.tooltipGenerator(tooltipGenerator);
}
@@ -619,7 +740,7 @@ var QDR = (function(QDR) {
}
},
- timeSeriesStackedChart: function (id, width, height, attrName, name, node, entity, stacked) {
+ timeSeriesStackedChart: function (id, width, height, attrName, name, node, entity, stacked, visibleDuration) {
var margin = {top: 20, right: 18, bottom: 10, left: 15}
// attrs that can be changed after the chart is created by using
// chart.attr(<attrname>, <attrvalue>);
@@ -633,18 +754,19 @@ var QDR = (function(QDR) {
type: "value", // value or rate
areaColor: "", // can be set for non-stacked charts
lineColor: "", // can be set for non-stacked charts
- zoom: false // should the y-axis range start at 0 or the min data value
+ zoom: false, // should the y-axis range start at 0 or the min data value
+ visibleDuration: visibleDuration
}
var width = width - margin.left - margin.right,
- height = height - margin.top - margin.bottom
+ height = height - margin.top - margin.bottom,
yAxisTransitionDuration = 0
var x = d3.time.scale()
var y = d3.scale.linear()
.rangeRound([height, 0]);
- // The x-accessor for the path generator; xScale \u2218 xValue.
+ // The x-accessor for the path generator; xScale * xValue.
var X = function (d) { return x(d[0]) }
- // The x-accessor for the path generator; yScale \u2218 yValue.
+ // The x-accessor for the path generator; yScale * yValue.
var Y = function Y(d) { return y(d[1]) }
var xAxis = d3.svg.axis().scale(x).orient("bottom")
@@ -672,7 +794,6 @@ var QDR = (function(QDR) {
.y(function (d) { return d.value; });
var area = d3.svg.area()
-
if (stacked) {
area.interpolate("cardinal")
.x(function (d) { return x(d.date); })
@@ -691,7 +812,22 @@ var QDR = (function(QDR) {
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
- var clip = svg.append("defs").append("svg:clipPath")
+ sv.append("linearGradient")
+ .attr("id", id) //"temperature-gradient")
+ .attr("gradientUnits", "userSpaceOnUse")
+ .attr("x1", 0).attr("y1", height *.5 )
+ .attr("x2", 0).attr("y2", height * 1.2)
+ .selectAll("stop")
+ .data([
+ {offset: "0%", opacity: 1},
+ {offset: "100%", opacity: 0}
+ ])
+ .enter().append("stop")
+ .attr("offset", function(d) { return d.offset; })
+ .attr("stop-opacity", function(d) { return d.opacity; })
+ .attr("stop-color", function(d) { return "#cbe7f3" });
+/*
+ var clip = svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("id", "clip-rect")
@@ -699,7 +835,7 @@ var QDR = (function(QDR) {
.attr("y", "0")
.attr("width", width)
.attr("height", height);
-
+*/
// we want all our areas to appear before the axiis
svg.append("g")
.attr("class", "section-container")
@@ -741,8 +877,11 @@ var QDR = (function(QDR) {
focus.append("foreignObject")
.attr('class', 'svg-tooltip')
.append("xhtml:span");
-
-
+/*
+ var transition = d3.select({}).transition()
+ .duration(2000)
+ .ease("linear");
+*/
function chart(selection) {
selection.each(function(data) {
@@ -769,12 +908,15 @@ var QDR = (function(QDR) {
}
var extent = d3.extent(data, function(d) {return d[0];});
+ //var points = data.length;
+ //var futureDate = new Date(data[points-1][0].getTime() - attrs.visibleDuration * 60 * 1000);
+ //extent = [futureDate, data[points-1][0]]
x.domain(extent)
.range([0, width - margin.left - margin.right]);
// Update the y-scale.
- var min = attrs.zoom ? 0 : d3.min(data, function(d) {return d[1]});
- var max = d3.max(data, function(d) {return d[1]});
+ var min = attrs.zoom ? 0 : d3.min(data, function(d) {return d[1]}) *.99;
+ var max = d3.max(data, function(d) {return d[1]}) * 1.01;
var mean = d3.mean(data, function(d) {return d[1]});
//max = max * 1.01;
var diff = (max - min);
@@ -839,7 +981,6 @@ var QDR = (function(QDR) {
series.exit().remove()
- //series.exit().remove()
// each time the data is updated, update each section
container.selectAll(".series .streamPath").data(seriesArr)
.attr("d", function (d) { return area(d.values); })
@@ -847,23 +988,30 @@ var QDR = (function(QDR) {
var series = container.selectAll(".series")
.data([data], function(d) { return d; })
- series.enter().append("g")
- .append("path")
+ var g = series.enter().append("g")
+ .attr("class", "series")
+
+ g.append("path")
.attr("class", "area")
- series.enter().append("path")
- .attr("class", "line")
+ .style("fill", "url(" + attrs.url + "#" + id + ") " + attrs.areaColor) //temperature-gradient)")
+ .attr("d", area.y0(y.range()[0]))
+ .attr("transform", null);
+ g.append("path")
+ .attr("class", "line")
+ .style("stroke", attrs.lineColor)
+ .attr("d", line)
+/*
+debugger;
+ g.transition()
+ .duration(2000)
+ .attr("transform", "translate(-4)");
+*/
series.exit().remove()
- // Update the area path.
- container.select(".area").data([data])
- .attr("d", area.y0(y.range()[0]))
- .style("fill", attrs.areaColor);
+ sv.selectAll("stop")
+ .attr("stop-color", attrs.areaColor)
- //Update the line path.
- container.select(".line").data([data])
- .attr("d", line)
- .style("stroke", attrs.lineColor)
}
// Update the x-axis.
svg.select(".x.axis")
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/js/qdrCharts.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrCharts.js b/console/stand-alone/plugin/js/qdrCharts.js
index e484b07..8bddca5 100644
--- a/console/stand-alone/plugin/js/qdrCharts.js
+++ b/console/stand-alone/plugin/js/qdrCharts.js
@@ -19,44 +19,58 @@ under the License.
/**
* @module QDR
*/
-/**
- * @module QDR
- */
var QDR = (function (QDR) {
/**
* @method ChartsController
- * @param $scope
- * @param QDRServer
- * @param QDRChartServer
*
* Controller that handles the QDR charts page
*/
- QDR.module.controller("QDR.ChartsController", ['$scope', 'QDRService', 'QDRChartService', '$uibModal', '$location',
- function($scope, QDRService, QDRChartService, $uibModal, $location) {
- var updateTimer = null;
+ QDR.module.controller("QDR.ChartsController", function($scope, QDRService, QDRChartService, $dialog, $location, $routeParams) {
+
+ var updateTimer = null;
+
+ if (!QDRService.connected) {
+ // we are not connected. we probably got here from a bookmark or manual page reload
+ QDRService.redirectWhenConnected("charts");
+ return;
+ }
+ // we are currently connected. setup a handler to get notified if we are ever disconnected
+ QDRService.addDisconnectAction( function () {
+ QDRService.redirectWhenConnected("charts")
+ $scope.$apply();
+ })
- QDR.log.debug("started Charts controller");
- if (!angular.isDefined(QDRService.schema))
- return;
$scope.svgCharts = [];
// create an svg object for each chart
QDRChartService.charts.filter(function (chart) {return chart.dashboard}).forEach(function (chart) {
- var svgChart = new QDRChartService.AreaChart(chart, $location.$$path)
+ var svgChart = new QDRChartService.AreaChart(chart)
svgChart.zoomed = false;
$scope.svgCharts.push(svgChart);
})
- // redraw the charts every second
+ // redraw the chart every update period
+ // this is a $scope function because it is called from the dialog
var updateCharts = function () {
$scope.svgCharts.forEach(function (svgChart) {
svgChart.tick(svgChart.chart.id()); // on this page we are using the chart.id() as the div id in which to render the chart
})
- updateHandle = setTimeout(updateCharts, 1100);
+ var updateRate = localStorage['updateRate'] ? localStorage['updateRate'] : 5000;
+ if (updateTimer) {
+ clearTimeout(updateTimer)
+ }
+ updateTimer = setTimeout(updateCharts, updateRate);
}
+
+ // called by ng-init in the html when the page is loaded
$scope.chartsLoaded = function () {
- setTimeout(updateCharts, 0);
+ $scope.svgCharts.forEach(function (svgChart) {
+ QDRChartService.sendChartRequest(svgChart.chart.request(), true);
+ })
+ if (updateTimer)
+ clearTimeout(updateTimer)
+ setTimeout(updateCharts, 0);
}
$scope.zoomChart = function (chart) {
@@ -88,12 +102,12 @@ var QDR = (function (QDR) {
// called from dialog when we want to clone the dialog chart
// the chart argument here is a QDRChartService chart
$scope.addChart = function (chart) {
- $scope.svgCharts.push(new QDRChartService.AreaChart(chart, $location.$$path));
+ $scope.svgCharts.push(new QDRChartService.AreaChart(chart));
};
$scope.$on("$destroy", function( event ) {
if (updateTimer) {
- cancelTimer(updateTimer);
+ clearTimeout(updateTimer);
updateTimer = null;
}
for (var i=$scope.svgCharts.length-1; i>=0; --i) {
@@ -103,28 +117,33 @@ var QDR = (function (QDR) {
function doDialog(template, chart) {
- var modalInstance = $uibModal.open({
- animation: true,
- templateUrl: template,
- controller: 'QDR.ChartDialogController',
- resolve: {
- chart: function () {
- return chart;
- },
- dashboard: function () {
- return $scope;
- }
- }
- });
+ $dialog.dialog({
+ backdrop: true,
+ keyboard: true,
+ backdropClick: true,
+ templateUrl: template,
+ controller: "QDR.ChartDialogController",
+ resolve: {
+ chart: function() {
+ return chart;
+ },
+ updateTick: function () {
+ return updateCharts;
+ },
+ dashboard: function () {
+ return $scope;
+ }
+ }
+ }).open();
};
- }]);
+ });
- QDR.module.controller("QDR.ChartDialogController", function($scope, QDRChartService, $location, $uibModalInstance, $rootScope, chart, dashboard) {
+ QDR.module.controller("QDR.ChartDialogController", function($scope, QDRChartService, $location, dialog, $rootScope, chart, updateTick, dashboard) {
var dialogSvgChart = null;
$scope.svgDivId = "dialogChart"; // the div id for the svg chart
- $scope.updateTimer = null;
+ var updateTimer = null;
$scope.chart = chart; // the underlying chart object from the dashboard
$scope.dialogChart = $scope.chart.copy(); // the chart object for this dialog
$scope.userTitle = $scope.chart.title();
@@ -132,51 +151,85 @@ var QDR = (function (QDR) {
$scope.$watch('userTitle', function(newValue, oldValue) {
if (newValue !== oldValue) {
$scope.dialogChart.title(newValue);
+ dialogSvgChart.tick($scope.svgDivId);
}
})
+ $scope.$watch("dialogChart.areaColor", function (newValue, oldValue) {
+ if (newValue !== oldValue) {
+ if (dialogSvgChart)
+ dialogSvgChart.tick($scope.svgDivId);
+ }
+ })
+ $scope.$watch("dialogChart.lineColor", function (newValue, oldValue) {
+ if (newValue !== oldValue) {
+ if (dialogSvgChart)
+ dialogSvgChart.tick($scope.svgDivId);
+ }
+ })
+ $scope.$watch("dialogChart.type", function (newValue, oldValue) {
+ if (newValue !== oldValue) {
+ if (dialogSvgChart)
+ dialogSvgChart.tick($scope.svgDivId);
+ }
+ })
+
// the stored rateWindow is in milliseconds, but the slider is in seconds
$scope.rateWindow = $scope.chart.rateWindow / 1000;
var cleanup = function () {
- if ($scope.updateTimer) {
- clearTimeout($scope.updateTimer);
- $scope.updateTimer = null;
+ if (updateTimer) {
+ clearTimeout(updateTimer);
+ updateTimer = null;
}
QDRChartService.unRegisterChart($scope.dialogChart); // remove the chart
}
$scope.okClick = function () {
- cleanup();
- $uibModalInstance.close();
+ cleanup();
+ dialog.close();
};
- // initialize the rateWindow slider
- $scope.slider = {
- 'options': {
- min: 1,
- max: 10,
- step: 1,
- tick: true,
- stop: function (event, ui) {
- $scope.dialogChart.rateWindow = ui.value * 1000;
- if (dialogSvgChart)
- dialogSvgChart.tick($scope.svgDivId);
- }
- }
- };
-
- $scope.visibleDuration =
- $scope.duration = {
- 'options': {
- min: 1,
- max: 10,
- step: 1,
- tick: true,
- stop: function (event, ui) {
- if (dialogSvgChart)
- dialogSvgChart.tick($scope.svgDivId);
- }
- }
- };
+ var initRateSlider = function () {
+ if (document.getElementById('rateSlider')) {
+ $( "#rateSlider" ).slider({
+ value: $scope.rateWindow,
+ min: 1,
+ max: 10,
+ step: 1,
+ slide: function( event, ui ) {
+ $scope.rateWindow = ui.value;
+ $scope.dialogChart.rateWindow = ui.value * 1000;
+ $scope.$apply();
+ if (dialogSvgChart)
+ dialogSvgChart.tick($scope.svgDivId);
+ }
+ });
+
+ } else {
+ setTimeout(initRateSlider, 100)
+ }
+ }
+ initRateSlider();
+
+ var initDurationSlider = function () {
+ if (document.getElementById('durationSlider')) {
+ $( "#durationSlider" ).slider({
+ value: $scope.dialogChart.visibleDuration,
+ min: 1,
+ max: 10,
+ step: 1,
+ slide: function( event, ui ) {
+ $scope.visibleDuration = $scope.dialogChart.visibleDuration = ui.value;
+ $scope.$apply();
+ if (dialogSvgChart)
+ dialogSvgChart.tick($scope.svgDivId);
+ }
+ });
+
+ } else {
+ setTimeout(initDurationSlider, 100)
+ }
+ }
+ initDurationSlider();
// handle the Apply button click
// update the dashboard chart's properties
@@ -184,10 +237,14 @@ var QDR = (function (QDR) {
$scope.chart.areaColor = $scope.dialogChart.areaColor;
$scope.chart.lineColor = $scope.dialogChart.lineColor;
$scope.chart.type = $scope.dialogChart.type;
- $scope.chart.rateWindow = $scope.dialogChart.rateWindow;
+ $scope.chart.rateWindow = $scope.rateWindow * 1000;
$scope.chart.title($scope.dialogChart.title());
$scope.chart.visibleDuration = $scope.dialogChart.visibleDuration;
QDRChartService.saveCharts();
+ if (typeof updateTick === "function")
+ updateTick();
+ if (typeof updateTick === "function")
+ updateTick();
}
// add a new chart to the dashboard based on the current dialog settings
@@ -206,7 +263,10 @@ var QDR = (function (QDR) {
dialogSvgChart.tick($scope.svgDivId);
// draw the chart again in 1 second
- $scope.updateTimer = setTimeout(updateDialogChart, 1000);
+ var updateRate = localStorage['updateRate'] ? localStorage['updateRate'] : 5000;
+ if (updateTimer)
+ clearTimeout(updateTimer);
+ updateTimer = setTimeout(updateDialogChart, updateRate);
}
var showChart = function () {
@@ -216,7 +276,19 @@ var QDR = (function (QDR) {
setTimeout(showChart, 100);
return;
}
- dialogSvgChart = new QDRChartService.AreaChart($scope.dialogChart, $location.$$path);
+ dialogSvgChart = new QDRChartService.AreaChart($scope.dialogChart);
+ $('input[name=lineColor]').val($scope.dialogChart.lineColor);
+ $('input[name=areaColor]').val($scope.dialogChart.areaColor);
+ $('input[name=areaColor]').on('input', function (e) {
+ $scope.dialogChart.areaColor = $(this).val();
+ updateDialogChart()
+ })
+ $('input[name=lineColor]').on('input', function (e) {
+ $scope.dialogChart.lineColor = $(this).val();
+ updateDialogChart()
+ })
+ if (updateTimer)
+ clearTimeout(updateTimer);
updateDialogChart();
}
showChart();
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[10/11] qpid-dispatch git commit: DISPATCH-316 Hawtio and stand-alone
consoles now use common code
Posted by ea...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/js/qdrChartService.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrChartService.js b/console/hawtio/src/main/webapp/plugin/js/qdrChartService.js
deleted file mode 100644
index 47cb47d..0000000
--- a/console/hawtio/src/main/webapp/plugin/js/qdrChartService.js
+++ /dev/null
@@ -1,1111 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
-*/
-/**
- * @module QDR
- */
-var QDR = (function(QDR) {
-
- // The QDR chart service handles periodic gathering data for charts and displaying the charts
- QDR.module.factory("QDRChartService", ['$rootScope', 'QDRService', '$http', '$resource', '$location',
- function($rootScope, QDRService, $http, $resource, $location) {
-
- var instance = 0; // counter for chart instances
- var bases = [];
- var findBase = function (name, attr, request) {
- for (var i=0; i<bases.length; ++i) {
- var base = bases[i];
- if (base.equals(name, attr, request))
- return base;
- }
- return null;
- }
-
- function ChartBase(name, attr, request) {
- // the base chart attributes
- this.name = name; // the record's "name" field
- this.attr = attr; // the record's attr field to chart
- this.request = request; // the associated request that fetches the data
-
- // copy the savable properties to an object
- this.copyProps = function (o) {
- o.name = this.name;
- o.attr = this.attr;
- this.request.copyProps(o);
- }
-
- this.equals = function (name, attr, request) {
- return (this.name == name && this.attr == attr && this.request.equals(request));
- }
- };
-
- // Object that represents a visible chart
- // There can be multiple of these per ChartBase (eg. one rate and one value chart)
- function Chart(opts, request) { //name, attr, cinstance, request) {
-
- var base = findBase(opts.name, opts.attr, request);
- if (!base) {
- base = new ChartBase(opts.name, opts.attr, request);
- bases.push(base);
- }
- this.base = base;
- this.instance = angular.isDefined(opts.instance) ? opts.instance : ++instance;
- this.dashboard = false; // is this chart on the dashboard page
- this.hdash = false; // is this chart on the hawtio dashboard page
- this.hreq = false; // has this hdash chart been requested
- this.type = opts.type ? opts.type: "value"; // value or rate
- this.rateWindow = opts.rateWindow ? opts.rateWindow : 1000; // calculate the rate of change over this time interval. higher == smother graph
- this.areaColor = "#cbe7f3"; // the chart's area color when not an empty string
- this.lineColor = "#058dc7"; // the chart's line color when not an empty string
- this.visibleDuration = opts.visibleDuration ? opts.visibleDuration : 10; // number of minutes of data to show (<= base.duration)
- this.userTitle = null; // user title overrides title()
-
- // generate a unique id for this chart
- this.id = function () {
- var name = this.name()
- var nameparts = name.split('/');
- if (nameparts.length == 2)
- name = nameparts[1];
- var key = QDRService.nameFromId(this.request().nodeId) + this.request().entity + name + this.attr() + "_" + this.instance + "_" + (this.request().aggregate ? "1" : "0");
- // remove all characters except letters,numbers, and _
- return key.replace(/[^\w]/gi, '')
- }
- // copy the savable properties to an object
- this.copyProps = function (o) {
- o.type = this.type;
- o.rateWindow = this.rateWindow;
- o.areaColor = this.areaColor;
- o.lineColor = this.lineColor;
- o.visibleDuration = this.visibleDuration;
- o.userTitle = this.userTitle;
- o.dashboard = this.dashboard;
- o.hdash = this.hdash;
- o.instance = this.instance;
- this.base.copyProps(o);
- }
- this.name = function (_) {
- if (!arguments.length) return this.base.name;
- this.base.name = _;
- return this;
- }
- this.attr = function (_) {
- if (!arguments.length) return this.base.attr;
- this.base.attr = _;
- return this;
- }
- this.nodeId = function (_) {
- if (!arguments.length) return this.base.request.nodeId;
- this.base.request.nodeId = _;
- return this;
- }
- this.entity = function (_) {
- if (!arguments.length) return this.base.request.entity;
- this.base.request.entity = _;
- return this;
- }
- this.aggregate = function (_) {
- if (!arguments.length) return this.base.request.aggregate;
- this.base.request.aggregate = _;
- return this;
- }
- this.request = function (_) {
- if (!arguments.length) return this.base.request;
- this.base.request = _;
- return this;
- }
- this.data = function () {
- return this.base.request.data(this.base.name, this.base.attr); // refernce to chart's data array
- }
- this.interval = function (_) {
- if (!arguments.length) return this.base.request.interval;
- this.base.request.interval = _;
- return this;
- }
- this.duration = function (_) {
- if (!arguments.length) return this.base.request.duration;
- this.base.request.duration = _;
- return this;
- }
- this.title = function (_) {
- var name = this.request().aggregate ? 'Aggregate' : QDRService.nameFromId(this.nodeId());
- var computed = name +
- " " + QDRService.humanify(this.attr()) +
- " - " + this.name()
- if (!arguments.length) return this.userTitle || computed;
-
- // don't store computed title in userTitle
- if (_ === computed)
- _ = null;
- this.userTitle = _;
- return this;
- }
- this.title_short = function (_) {
- if (!arguments.length) return this.userTitle || this.name();
- return this;
- }
- this.copy = function () {
- var chart = self.registerChart({
- nodeId: this.nodeId(),
- entity: this.entity(),
- name: this.name(),
- attr: this.attr(),
- interval: this.interval(),
- forceCreate: true,
- aggregate: this.aggregate(),
- hdash: this.hdash
- })
- chart.type = this.type;
- chart.areaColor = this.areaColor;
- chart.lineColor = this.lineColor;
- chart.rateWindow = this.rateWindow;
- chart.visibleDuration = this.visibleDuration;
- chart.userTitle = this.userTitle;
- return chart;
- }
- // compare to a chart
- this.equals = function (c) {
- return (c.instance == this.instance &&
- c.base.equals(this.base.name, this.base.attr, this.base.request) &&
- c.type == this.type &&
- c.rateWindow == this.rateWindow &&
- c.areaColor == this.areaColor &&
- c.lineColor == this.lineColor)
- }
- }
-
- // Object that represents the management request to fetch and store data for multiple charts
- function ChartRequest(opts) { //nodeId, entity, name, attr, interval, aggregate) {
- this.duration = opts.duration || 10; // number of minutes to keep the data
- this.nodeId = opts.nodeId; // eg amqp:/_topo/0/QDR.A/$management
- this.entity = opts.entity; // eg .router.address
- // sorted since the responses will always be sorted
- this.aggregate = opts.aggregate; // list of nodeIds for aggregate charts
- this.datum = {}; // object containing array of arrays for each attr
- // like {attr1: [[date,value],[date,value]...], attr2: [[date,value]...]}
-
- this.interval = opts.interval || 1000; // number of milliseconds between updates to data
- this.setTimeoutHandle = null; // used to cancel the next request
- // copy the savable properties to an object
-
- this.data = function (name, attr) {
- if (this.datum[name] && this.datum[name][attr])
- return this.datum[name][attr]
- return null;
- }
- this.addAttrName = function (name, attr) {
- if (Object.keys(this.datum).indexOf(name) == -1) {
- this.datum[name] = {}
- }
- if (Object.keys(this.datum[name]).indexOf(attr) == -1) {
- this.datum[name][attr] = [];
- }
- }
- this.addAttrName(opts.name, opts.attr)
-
- this.copyProps = function (o) {
- o.nodeId = this.nodeId;
- o.entity = this.entity;
- o.interval = this.interval;
- o.aggregate = this.aggregate;
- o.duration = this.duration;
- }
-
- this.removeAttr = function (name, attr) {
- if (this.datum[name]) {
- if (this.datum[name][attr]) {
- delete this.datum[name][attr]
- }
- }
- return this.attrs().length;
- }
-
- this.equals = function (r, entity, aggregate) {
- if (arguments.length == 3) {
- var o = {nodeId: r, entity: entity, aggregate: aggregate}
- r = o;
- }
- return (this.nodeId === r.nodeId && this.entity === r.entity && this.aggregate == r.aggregate)
- }
- this.names = function () {
- return Object.keys(this.datum)
- }
- this.attrs = function () {
- var attrs = {}
- Object.keys(this.datum).forEach( function (name) {
- Object.keys(this.datum[name]).forEach( function (attr) {
- attrs[attr] = 1;
- })
- }, this)
- return Object.keys(attrs);
- }
- };
-
- // Below here are the properties and methods available on QDRChartService
- var self = {
- charts: [], // list of charts to gather data for
- chartRequests: [], // the management request info (multiple charts can be driven off of a single request
-
- init: function () {
- self.loadCharts();
- },
-
- findChartRequest: function (nodeId, entity, aggregate) {
- var ret = null;
- self.chartRequests.some( function (request) {
- if (request.equals(nodeId, entity, aggregate)) {
- ret = request;
- return true;
- }
- })
- return ret;
- },
-
- findCharts: function (opts) { //name, attr, nodeId, entity, hdash) {
- if (!opts.hdash)
- opts.hdash = false; // rather than undefined
- return self.charts.filter( function (chart) {
- return (chart.name() == opts.name &&
- chart.attr() == opts.attr &&
- chart.nodeId() == opts.nodeId &&
- chart.entity() == opts.entity &&
- chart.hdash == opts.hdash)
- });
- },
-
- delChartRequest: function (request) {
- for (var i=0; i<self.chartRequests.length; ++i) {
- var r = self.chartRequests[i];
- if (request.equals(r)) {
- QDR.log.debug("removed request: " + request.nodeId + " " + request.entity);
- self.chartRequests.splice(i, 1);
- self.stopCollecting(request);
- return;
- }
- }
- },
-
- delChart: function (chart) {
- var foundBases = 0;
- for (var i=0; i<self.charts.length; ++i) {
- var c = self.charts[i];
- if (c.base === chart.base)
- ++foundBases;
- if (c.equals(chart)) {
- self.charts.splice(i, 1);
- if (chart.dashboard)
- self.saveCharts();
- }
- }
- if (foundBases == 1) {
- var baseIndex = bases.indexOf(chart.base)
- bases.splice(baseIndex, 1);
- }
- },
-
- registerChart: function (opts) { //nodeId, entity, name, attr, interval, instance, forceCreate, aggregate, hdash) {
- var request = self.findChartRequest(opts.nodeId, opts.entity, opts.aggregate);
- if (request) {
- // add any new attr or name to the list
- request.addAttrName(opts.name, opts.attr)
- } else {
- // the nodeId/entity did not already exist, so add a new request and chart
- QDR.log.debug("added new request: " + opts.nodeId + " " + opts.entity);
- request = new ChartRequest(opts); //nodeId, entity, name, attr, interval, aggregate);
- self.chartRequests.push(request);
- self.startCollecting(request);
- }
- var charts = self.findCharts(opts); //name, attr, nodeId, entity, hdash);
- var chart;
- if (charts.length == 0 || opts.forceCreate) {
- if (!opts.use_instance && opts.instance)
- delete opts.instance;
- chart = new Chart(opts, request) //opts.name, opts.attr, opts.instance, request);
- self.charts.push(chart);
- } else {
- chart = charts[0];
- }
- return chart;
- },
-
- // remove the chart for name/attr
- // if all attrs are gone for this request, remove the request
- unRegisterChart: function (chart) {
- // remove the chart
-
- // TODO: how do we remove charts that were added to the hawtio dashboard but then removed?
- // We don't get a notification that they were removed. Instead, we could just stop sending
- // the request in the background and only send the request when the chart's tick() event is triggered
- //if (chart.hdash) {
- // chart.dashboard = false;
- // self.saveCharts();
- // return;
- //}
-
- for (var i=0; i<self.charts.length; ++i) {
- var c = self.charts[i];
- if (chart.equals(c)) {
- var request = chart.request();
- self.delChart(chart);
- if (request) {
- // see if any other charts use this attr
- for (var i=0; i<self.charts.length; ++i) {
- var c = self.charts[i];
- if (c.attr() == chart.attr() && c.request().equals(chart.request()))
- return;
- }
- // no other charts use this attr, so remove it
- if (request.removeAttr(chart.name(), chart.attr()) == 0) {
- self.stopCollecting(request);
- self.delChartRequest(request);
- }
- }
- }
- }
- self.saveCharts();
-
- },
-
- stopCollecting: function (request) {
- if (request.setTimeoutHandle) {
- clearTimeout(request.setTimeoutHandle);
- request.setTimeoutHandle = null;
- }
- },
-
- startCollecting: function (request) {
- // Using setTimeout instead of setInterval because the response may take longer than interval
- request.setTimeoutHandle = setTimeout(self.sendChartRequest, request.interval, request);
- },
- shouldRequest: function (request) {
- // see if any of the charts associated with this request have either dialog, dashboard, or hreq
- return self.charts.some( function (chart) {
- return (chart.dashboard || chart.hreq) || (!chart.dashboard && !chart.hdash);
- });
- },
- // send the request
- sendChartRequest: function (request, once) {
- if (!once && !self.shouldRequest(request)) {
- request.setTimeoutHandle = setTimeout(self.sendChartRequest, request.interval, request)
- return;
- }
-
- // ensure the response has the name field so we can associate the response values with the correct chart
- var attrs = request.attrs();
- attrs.push("name");
-
- // this is called when the response is received
- var saveResponse = function (nodeId, entity, response) {
- if (!response || !response.attributeNames)
- return;
- //QDR.log.debug("got chart results for " + nodeId + " " + entity);
- // records is an array that has data for all names
- var records = response.results;
- if (!records)
- return;
-
- var now = new Date();
- var cutOff = new Date(now.getTime() - request.duration * 60 * 1000);
- // index of the "name" attr in the response
- var nameIndex = response.attributeNames.indexOf("name");
- if (nameIndex < 0)
- return;
-
- var names = request.names();
- // for each record returned, find the name/attr for this request and save the data with this timestamp
- for (var i=0; i<records.length; ++i) {
- var name = records[i][nameIndex];
- // if we want to store the values for some attrs for this name
- if (names.indexOf(name) > -1) {
- attrs.forEach( function (attr) {
- var data = request.data(name, attr) // get a reference to the data array
- if (data) {
- var attrIndex = response.attributeNames.indexOf(attr)
- if (request.aggregate) {
- data.push([now, response.aggregates[i][attrIndex].sum, response.aggregates[i][attrIndex].detail])
- } else {
- data.push([now, records[i][attrIndex]])
- }
- // expire the old data
- while (data[0][0] < cutOff) {
- data.shift();
- }
- }
- })
- }
- }
- }
- if (request.aggregate) {
- var nodeList = QDRService.nodeIdList()
- QDRService.getMultipleNodeInfo(nodeList, request.entity, attrs, saveResponse, request.nodeId);
- } else {
- QDRService.getNodeInfo(request.nodeId, request.entity, attrs, saveResponse);
- }
- // it is now safe to schedule another request
- if (once)
- return;
- request.setTimeoutHandle = setTimeout(self.sendChartRequest, request.interval, request)
- },
-
- numCharts: function () {
- return self.charts.filter( function (chart) { return chart.dashboard }).length;
- //return self.charts.length;
- },
-
- isAttrCharted: function (nodeId, entity, name, attr) {
- var charts = self.findCharts({
- name: name,
- attr: attr,
- nodeId: nodeId,
- entity: entity
- })
- // if any of the matching charts are on the dashboard page, return true
- return charts.some(function (chart) {
- return (chart.dashboard) });
- },
-
- addHDash: function (chart) {
- chart.hdash = true;
- self.saveCharts();
- /*
- if (!chart.hdash) {
- var dashChart = self.registerChart(chart.nodeId(), chart.entity(),
- chart.name(), chart.attr(), chart.interval(), true, chart.aggregate(), true);
- dashChart.dashboard = true;
- dashChart.hdash = false;
- chart.dashboard = false;
- chart.hdash = true;
- self.saveCharts();
- }
- */
- },
- delHDash: function (chart) {
- chart.hdash = false;
- self.saveCharts();
- },
- addDashboard: function (chart) {
- chart.dashboard = true;
- self.saveCharts();
- },
- delDashboard: function (chart) {
- chart.dashboard = false;
- self.saveCharts();
- },
- // save the charts to local storage
- saveCharts: function () {
- var charts = [];
- var minCharts = [];
-
- self.charts.forEach(function (chart) {
- var minChart = {};
- // don't save chart unless it is on the dashboard
- if (chart.dashboard || chart.hdash) {
- chart.copyProps(minChart);
- minCharts.push(minChart);
- }
- })
- localStorage["QDRCharts"] = angular.toJson(minCharts);
- },
- loadCharts: function () {
- var charts = angular.fromJson(localStorage["QDRCharts"]);
- if (charts) {
- var nodeList = QDRService.nodeList().map( function (node) {
- return node.id;
- })
- charts.forEach(function (chart) {
- if (nodeList.indexOf(chart.nodeId) >= 0) {
- if (!chart.interval)
- chart.interval = 1000;
- if (!chart.duration)
- chart.duration = 10;
- if (chart.nodeList)
- chart.aggregate = true;
- var newChart = self.registerChart(chart.nodeId, chart.entity, chart.name, chart.attr, chart.interval, true, chart.aggregate);
- newChart.dashboard = true; // we only save the dashboard charts
- newChart.type = chart.type;
- newChart.rateWindow = chart.rateWindow;
- newChart.areaColor = chart.areaColor ? chart.areaColor : "#c0e0ff";
- newChart.lineColor = chart.lineColor ? chart.lineColor : "#4682b4";
- newChart.duration(chart.duration);
- newChart.visibleDuration = chart.visibleDuration ? chart.visibleDuration : 10;
- if (chart.userTitle)
- newChart.title(chart.userTitle);
- }
- })
- }
- },
- loadCharts: function () {
- var charts = angular.fromJson(localStorage["QDRCharts"]);
- if (charts) {
- // get array of known ids
- var nodeList = QDRService.nodeList().map( function (node) {
- return node.id;
- })
- charts.forEach(function (chart) {
- // if this chart is not in the current list of nodes, skip
- if (nodeList.indexOf(chart.nodeId) >= 0) {
- if (!angular.isDefined(chart.instance)) {
- chart.instance = ++instance;
- }
- if (chart.instance >= instance)
- instance = chart.instance + 1;
- if (!chart.duration)
- chart.duration = 10;
- if (chart.nodeList)
- chart.aggregate = true;
- if (!chart.hdash)
- chart.hdash = false;
- if (!chart.dashboard)
- chart.dashboard = false;
- if (!chart.hdash && !chart.dashboard)
- chart.dashboard = true;
- if (chart.hdash && chart.dashboard)
- chart.dashboard = false;
- chart.forceCreate = true;
- chart.use_instance = true;
- var newChart = self.registerChart(chart); //chart.nodeId, chart.entity, chart.name, chart.attr, chart.interval, true, chart.aggregate);
- newChart.dashboard = chart.dashboard;
- newChart.hdash = chart.hdash;
- newChart.hreq = false;
- newChart.type = chart.type;
- newChart.rateWindow = chart.rateWindow;
- newChart.areaColor = chart.areaColor ? chart.areaColor : "#cbe7f3";
- newChart.lineColor = chart.lineColor ? chart.lineColor : "#058dc7";
- newChart.duration(chart.duration);
- newChart.visibleDuration = chart.visibleDuration ? chart.visibleDuration : 10;
- if (chart.userTitle)
- newChart.title(chart.userTitle);
- }
- })
- }
- },
-
- AreaChart: function (chart) {
- if (!chart)
- return;
-
- // if this is an aggregate chart, show it stacked
- var stacked = chart.request().aggregate;
- this.chart = chart; // reference to underlying chart
- this.svgchart = null;
- this.url = $location.absUrl();
-
- // callback function. called by svgchart when binding data
- // the variable 'this' refers to the svg and not the AreaChart,
- // but since we are still in the scope of the AreaChart we have access to the passed in chart argument
- this.chartData = function () {
-
- var now = new Date();
- var visibleDate = new Date(now.getTime() - chart.visibleDuration * 60 * 1000);
- var data = chart.data();
- var nodeList = QDRService.nodeIdList();
-
- if (chart.type == "rate") {
- var rateData = [];
- var datalen = data.length;
- k = 0; // inner loop optimization
- for (var i=0; i<datalen; ++i) {
- var d = data[i];
- if (d[0] >= visibleDate) {
- for (var j=k+1; j<datalen; ++j) {
- var d1 = data[j];
- if (d1[0] - d[0] >= chart.rateWindow) { // rateWindow is the timespan to calculate rates
- var elapsed = Math.max((d1[0] - d[0]) / 1000, 1); // number of seconds that elapsed
- var rd = [d1[0],(d1[1] - d[1])/elapsed]
- k = j; // start here next time
- // this is a stacked (aggregate) chart
- if (stacked) {
- var detail = [];
- nodeList.forEach( function (node, nodeIndex) {
- if (d1[2][nodeIndex] && d[2][nodeIndex])
- detail.push({node: QDRService.nameFromId(node), val: (d1[2][nodeIndex].val- d[2][nodeIndex].val)/elapsed})
- })
- rd.push(detail)
- }
- rateData.push(rd);
- break;
- }
- }
- }
- }
- // we need at least a point to chart
- if (rateData.length == 0) {
- rateData[0] = [chart.data()[0][0],0,[{node:'',val:0}]];
- }
- return rateData;
- }
- if (chart.visibleDuration != chart.duration()) {
- return data.filter(function (d) { return d[0]>=visibleDate});
- } else
- return data;
- }
-
- this.zoom = function (id, zoom) {
- if (this.svgchart) {
- this.svgchart.attr("zoom", zoom)
- d3.select('#' + id)
- .data([this.chartData()])
- .call(this.svgchart)
- }
- }
-
- // called by the controller on the page that displays the chart
- // called whenever the controller wants to redraw the chart
- // note: the data is collected independently of how often the chart is redrawn
- this.tick = function (id) {
-
- // can't draw charts that don't have data yet
- if (this.chart.data().length == 0) {
- return;
- }
-
- // if we haven't created the svg yet
- if (!this.svgchart) {
-
- // make sure the dom element exists on the page
- var div = angular.element('#' + id);
- if (!div)
- return;
-
- var width = div.width();
- var height = div.height();
-
- // make sure the dom element has a size. otherwise we wouldn't see anything anyway
- if (!width)
- return;
-
- var tooltipGenerator;
- // stacked charts have a different tooltip
- if (stacked) {
- tooltipGenerator = function (d, color, format) {
- var html = "<table class='fo-table'><tbody><tr class='fo-title'>"+
- "<td align='center' colspan='2' nowrap>Time: "+d[0].toTimeString().substring(0, 8)+"</td></tr>"
- d[2].forEach( function (detail) {
- html += "<tr class='detail'><td align='right' nowrap>"
- + detail.node
- + "<div class='fo-table-legend' style='background-color: "+color(detail.node)+"'></div>"
- + "</td><td>"+format(detail.val)+"</td></tr>"
- })
- html += "</tbody></table>"
- return html;
- }
- } else {
- tooltipGenerator = function (d, color, format) {
- var html = "<table class='fo-table'><tbody><tr class='fo-title'>"+
- "<td align='center'>Time</td><td align='center'>Value</td></tr><tr><td>" +
- d[0].toTimeString().substring(0, 8) +
- "</td><td>" +
- format(d[1]) +
- "</td></tr></tbody></table>"
- return html;
- }
- }
- // create and initialize the chart
- this.svgchart = self.timeSeriesStackedChart(id, width, height,
- QDRService.humanify(this.chart.attr()),
- this.chart.name(),
- QDRService.nameFromId(this.chart.nodeId()),
- this.chart.entity(),
- stacked,
- this.chart.visibleDuration)
- .tooltipGenerator(tooltipGenerator);
-
- }
- // in case the chart properties have changed, set the new props
- this.svgchart
- .attr("type", this.chart.type)
- .attr("areaColor", this.chart.areaColor)
- .attr("lineColor", this.chart.lineColor)
- .attr("url", this.url)
- .attr("title", this.chart.userTitle);
-
- // bind the new data and update the chart
- d3.select('#' + id) // the div id on the page/dialog
- .data([this.chartData()])
- .call(this.svgchart); // the charting function
- }
- },
-
- timeSeriesStackedChart: function (id, width, height, attrName, name, node, entity, stacked, visibleDuration) {
- var margin = {top: 20, right: 18, bottom: 10, left: 15}
- // attrs that can be changed after the chart is created by using
- // chart.attr(<attrname>, <attrvalue>);
- var attrs = {
- attrName: attrName, // like Deliveries to Container. Put at top of chart
- name: name, // like router.address/qdrhello Put at bottom of chart with node
- node: node, // put at bottom of chart with name
- entity: entity, // like .router.address Not used atm
- title: "", // user title overrides the node and name at the bottom of the chart
- url: "", // needed to reference filters and clip because of angular's location service
- type: "value", // value or rate
- areaColor: "", // can be set for non-stacked charts
- lineColor: "", // can be set for non-stacked charts
- zoom: false, // should the y-axis range start at 0 or the min data value
- visibleDuration: visibleDuration
- }
- var width = width - margin.left - margin.right,
- height = height - margin.top - margin.bottom,
- yAxisTransitionDuration = 0
-
- var x = d3.time.scale()
- var y = d3.scale.linear()
- .rangeRound([height, 0]);
- // The x-accessor for the path generator; xScale * xValue.
- var X = function (d) { return x(d[0]) }
- // The x-accessor for the path generator; yScale * yValue.
- var Y = function Y(d) { return y(d[1]) }
-
- var xAxis = d3.svg.axis().scale(x).orient("bottom")
- .outerTickSize(6)
- .innerTickSize(-(height-margin.top-margin.bottom))
- .tickPadding(2)
- .ticks(d3.time.minutes, 2)
- var yAxis = d3.svg.axis().scale(y).orient("right")
- .outerTickSize(8)
- .innerTickSize(-(width-margin.left-margin.right))
- .tickPadding(10)
- .ticks(3)
- .tickFormat(function(d) { return formatValue(d)})
-
- var tooltipGenerator = function (d, color, format) {return ""}; // should be overridden to set an appropriate tooltip
- var formatValue = d3.format(".2s");
- var formatPrecise = d3.format(",");
- var bisectDate = d3.bisector(function(d) { return d[0]; }).left;
- var line = d3.svg.line();
-
- var stack = d3.layout.stack()
- .offset("zero")
- .values(function (d) { return d.values; })
- .x(function (d) { return x(d.date); })
- .y(function (d) { return d.value; });
-
- var area = d3.svg.area()
- if (stacked) {
- area.interpolate("cardinal")
- .x(function (d) { return x(d.date); })
- .y0(function (d) { return y(d.y0); })
- .y1(function (d) { return y(d.y0 + d.y); });
- } else {
- area.interpolate("basis").x(X).y1(Y)
- line.x(X).y(Y)
- }
- var color = d3.scale.category20();
-
- var sv = d3.select("#"+id).append("svg")
- .attr("width", width + margin.left + margin.right)
- .attr("height", height + margin.top + margin.bottom)
- var svg = sv
- .append("g")
- .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
-
- sv.append("linearGradient")
- .attr("id", id) //"temperature-gradient")
- .attr("gradientUnits", "userSpaceOnUse")
- .attr("x1", 0).attr("y1", height *.5 )
- .attr("x2", 0).attr("y2", height * 1.2)
- .selectAll("stop")
- .data([
- {offset: "0%", opacity: 1},
- {offset: "100%", opacity: 0}
- ])
- .enter().append("stop")
- .attr("offset", function(d) { return d.offset; })
- .attr("stop-opacity", function(d) { return d.opacity; })
- .attr("stop-color", function(d) { return "#cbe7f3" });
-/*
- var clip = svg.append("defs").append("svg:clipPath")
- .attr("id", "clip")
- .append("svg:rect")
- .attr("id", "clip-rect")
- .attr("x", "0")
- .attr("y", "0")
- .attr("width", width)
- .attr("height", height);
-*/
- // we want all our areas to appear before the axiis
- svg.append("g")
- .attr("class", "section-container")
-
- svg.append("g")
- .attr("class", "x axis")
-
- svg.append("g")
- .attr("class", "y axis")
-
- svg.append("text").attr("class", "title")
- .attr("x", (width / 2) - (margin.left + margin.right) / 2)
- .attr("y", 0 - (margin.top / 2))
- .attr("text-anchor", "middle")
- .text(attrs.attrName);
-
- svg.append("text").attr("class", "legend")
- .attr("x", (width / 2) - (margin.left + margin.right) / 2)
- .attr("y", height + (margin.bottom / 2) )
- .attr("text-anchor", "middle")
- .text(!stacked ? attrs.node + " " + attrs.name : attrs.name);
-
- var focus = sv.append("g")
- .attr("class", "focus")
- .style("display", "none");
-
- focus.append("circle")
- .attr("r", 4.5);
-
- var focusg = focus.append("g");
- focusg.append("rect")
- .attr("class", "mo-guide y")
- .attr("width", 1)
- .attr("height", height - (margin.top + margin.bottom));
- focusg.append("rect")
- .attr("class", "mo-guide x")
- .attr("width", width - (margin.left + margin.right))
- .attr("height", 1);
- focus.append("foreignObject")
- .attr('class', 'svg-tooltip')
- .append("xhtml:span");
-/*
- var transition = d3.select({}).transition()
- .duration(2000)
- .ease("linear");
-*/
- function chart(selection) {
- selection.each(function(data) {
-
- var seriesArr = []
- if (stacked) {
- var detailNames = data[0][2].map(function (detail){ return detail.node })
- var revNames = angular.copy(detailNames).reverse();
- color.domain(revNames);
-
- var series = {};
- detailNames.forEach(function (name) {
- series[name] = {name: name, values:[]};
- seriesArr.unshift(series[name]); // insert at beginning
- });
-
- data.forEach(function (d) {
- detailNames.map(function (name, i) {
- series[name].values.push({date: d[0], value: d[2][i] ? d[2][i].val : 0});
- });
- });
-
- // this decorates seriesArr with x,y,and y0 properties
- stack(seriesArr);
- }
-
- var extent = d3.extent(data, function(d) {return d[0];});
- //var points = data.length;
- //var futureDate = new Date(data[points-1][0].getTime() - attrs.visibleDuration * 60 * 1000);
- //extent = [futureDate, data[points-1][0]]
- x.domain(extent)
- .range([0, width - margin.left - margin.right]);
-
- // Update the y-scale.
- var min = attrs.zoom ? 0 : d3.min(data, function(d) {return d[1]}) *.99;
- var max = d3.max(data, function(d) {return d[1]}) * 1.01;
- var mean = d3.mean(data, function(d) {return d[1]});
- //max = max * 1.01;
- var diff = (max - min);
- if (diff == 0) {
- max = max + 1;
- diff = 1;
- }
- var ratio = mean != 0 ? diff / mean : 1;
- if (ratio < .05)
- formatValue = d3.format(".3s")
-
- if (stacked) {
- y.domain([min, max])
- .range([height - margin.top - margin.bottom, 0]);
- } else {
- y
- .domain([min, max])
- .range([height - margin.top - margin.bottom, 0]);
- }
- if (attrs.type == "rate") {
- area.interpolate("basis"); // rate charts look better smoothed
- line.interpolate("basis");
- }
- else {
- area.interpolate("linear"); // don't smooth value charts
- line.interpolate("linear");
- }
-
- // adjust the xaxis based on the range of x values (domain)
- var timeSpan = (extent[1] - extent[0]) / (1000 * 60); // number of minutes
- if (timeSpan < 1.5)
- xAxis.ticks(d3.time.seconds, 10);
- else if (timeSpan < 3)
- xAxis.ticks(d3.time.seconds, 30);
- else if (timeSpan < 8)
- xAxis.ticks(d3.time.minutes, 1);
- else
- xAxis.ticks(d3.time.minutes, 2);
-
- // adjust the number of yaxis ticks based on the range of y values
- if (formatValue(min) === formatValue(max))
- yAxis.ticks(2);
-
- var container = svg.select('.section-container');
- container.selectAll('.series').remove();
- if (stacked) {
- y.domain([Math.min(min, 0), d3.max(seriesArr, function (c) {
- return d3.max(c.values, function (d) { return d.y0 + d.y; });
- })]);
-
- // creates a .series g path for each section in the detail
- // since we don't get more sections this selection is only run once
- var series = container.selectAll(".series")
- .data(seriesArr)
-
- series.enter().append("g")
- .attr("class", "series")
- .append("path")
- .attr("class", "streamPath")
- .style("fill", function (d) { return color(d.name); })
- .style("stroke", "grey");
-
- series.exit().remove()
-
- // each time the data is updated, update each section
- container.selectAll(".series .streamPath").data(seriesArr)
- .attr("d", function (d) { return area(d.values); })
- } else {
- var series = container.selectAll(".series")
- .data([data], function(d) { return d; })
-
- var g = series.enter().append("g")
- .attr("class", "series")
-
- g.append("path")
- .attr("class", "area")
- .style("fill", "url(" + attrs.url + "#" + id + ") " + attrs.areaColor) //temperature-gradient)")
- .attr("d", area.y0(y.range()[0]))
- .attr("transform", null);
-
- g.append("path")
- .attr("class", "line")
- .style("stroke", attrs.lineColor)
- .attr("d", line)
-/*
-debugger;
- g.transition()
- .duration(2000)
- .attr("transform", "translate(-4)");
-*/
- series.exit().remove()
-
- sv.selectAll("stop")
- .attr("stop-color", attrs.areaColor)
-
- }
- // Update the x-axis.
- svg.select(".x.axis")
- .attr("transform", "translate(0," + (height - margin.top - margin.bottom + 1) + ")")
- .call(xAxis);
-
- svg.select(".y.axis")
- .transition().duration(yAxisTransitionDuration) // animate the y axis
- .attr("transform", "translate(" + (width - margin.right - margin.left) + ",0)")
- .call(yAxis);
- yAxisTransitionDuration = 1000 // only do a transition after the chart is 1st drawn
-
- // TODO: fix this
- // need to recreate this every update... not sure why
- var overlay = sv.select(".overlay");
- if (!overlay.empty())
- overlay.remove();
- sv.append("rect")
- .attr("class", "overlay")
- .attr("width", width)
- .attr("height", height)
- .on("mouseover", function () {focus.style("display", null)})
- .on("mouseout", function () {focus.style("display", "none")})
- .on("mousemove", mousemove)
-
- function mousemove() {
- var x0 = x.invert(d3.mouse(this)[0] - margin.left);
- var i = bisectDate(data, x0, 1);
- if (i < data.length && i > 0) {
- var d0 = data[i - 1];
- var d1 = data[i];
- // set d to the data that is closest to the mouse position
- var d = x0 - d0[0] > d1[0] - x0 ? d1 : d0;
- focus.attr("transform", "translate(" + (x(d[0]) + margin.left) + "," + (y(d[1]) + margin.top) + ")");
-
- var tipFormat = formatPrecise;
- if (attrs.type === "rate")
- tipFormat = d3.format(".2n")
- // set the tooltip html and position it
- focus.select('.svg-tooltip span')
- .html(tooltipGenerator(d, color, tipFormat))
-
- var foBounds = focus.select('table')[0][0].getBoundingClientRect();
- var mx = x(d[0]); // mouse x
- var my = y(d[1]); // mouse y
-
- // perfer to put the tooltip in the nw corner relative to the focus circle
- var foy = -foBounds.height;
- var fox = -foBounds.width;
- // off the left side
- if (mx - foBounds.width - margin.left < 0)
- fox = 0;
- // above the top
- if (my - foBounds.height - margin.top < 0)
- foy = 0;
- // won't fit above or below, just put it at bottom
- if (my + foBounds.height > height)
- foy = -(foBounds.height - (height - my));
-
- focus.select('.svg-tooltip')
- .attr('x', fox).attr('y', foy);
-
- // position the guide lines
- focus.select(".mo-guide.y")
- .attr("y", -my);
- focus.select(".mo-guide.x")
- .attr("x", -mx);
-
- } else {
- focus.attr("transform", "translate(-10,-10)");
- }
- }
-
- })
-
-
- }
- chart.attr = function (attrName, value) {
- if (arguments.length < 2)
- return arguments.length == 1 ? attrs[attrName] : chart;
- if (angular.isDefined(attrs[attrName]))
- attrs[attrName] = value;
- return chart;
- }
- chart.tooltipGenerator = function (_) {
- tooltipGenerator = _;
- return chart;
- }
-
- return chart;
- }
- }
- return self;
- }]);
-
- return QDR;
-}(QDR || {}));
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrChartService.js b/console/hawtio/src/main/webapp/plugin/js/qdrChartService.js
new file mode 120000
index 0000000..dc5df4c
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrChartService.js
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/js/qdrChartService.js
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/js/qdrCharts.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrCharts.js b/console/hawtio/src/main/webapp/plugin/js/qdrCharts.js
index f37018f..30a9b99 100644
--- a/console/hawtio/src/main/webapp/plugin/js/qdrCharts.js
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrCharts.js
@@ -27,16 +27,21 @@ var QDR = (function (QDR) {
* Controller that handles displaying a chart on the hawtio dashboard page. Only one chart is displayed per instance of this
* page
*/
- QDR.module.controller("QDR.ChartsController", function($scope, QDRService, QDRChartService, $dialog, $location, localStorage, $routeParams) {
+ QDR.module.controller("QDR.ChartsController", function($scope, QDRService, QDRChartService, $dialog, $location, $routeParams) {
var updateTimer = null;
if (!QDRService.connected && !$routeParams.chid) {
// we are not connected. we probably got here from a bookmark or manual page reload
- $location.path("/" + QDR.pluginName + "/connect")
- $location.search('org', "charts");
+ QDRService.redirectWhenConnected("charts");
return;
}
+ // we are currently connected. setup a handler to get notified if we are ever disconnected
+ QDRService.addDisconnectAction( function () {
+ QDRService.redirectWhenConnected("charts")
+ $scope.$apply();
+ })
+
$scope.svgCharts = [];
// create an svg object for each chart
@@ -74,7 +79,7 @@ var QDR = (function (QDR) {
// the link that the above login prompt will display
$scope.loginHref = QDR.pluginName + "/connect";
- // call by ng-init in the html when the page is loaded
+ // called by ng-init in the html when the page is loaded
$scope.chartsLoaded = function () {
$scope.svgCharts.forEach(function (svgChart) {
QDRChartService.sendChartRequest(svgChart.chart.request(), true);
@@ -169,7 +174,7 @@ var QDR = (function (QDR) {
});
// the edit chart properties dialog
- QDR.module.controller("QDR.ChartDialogController", function($scope, QDRChartService, $location, dialog, $rootScope, localStorage, chart, updateTick) {
+ QDR.module.controller("QDR.ChartDialogController", function($scope, QDRChartService, $location, dialog, $rootScope, chart, updateTick) {
UI.colors[0] = "#cbe7f3"
UI.colors[1] = "#058dc7"
@@ -178,7 +183,7 @@ var QDR = (function (QDR) {
var dialogSvgChart = null;
$scope.svgDivId = "dialogChart"; // the div id for the svg chart
- var updateTimer = null;
+ var updateTimer = null;
$scope.chart = chart; // the underlying chart object from the dashboard
$scope.dialogChart = $scope.chart.copy(); // the chart object for this dialog
$scope.userTitle = $scope.chart.title();
@@ -191,8 +196,9 @@ var QDR = (function (QDR) {
})
$scope.$watch("dialogChart.areaColor", function (newValue, oldValue) {
if (newValue !== oldValue) {
- if (dialogSvgChart)
+ if (dialogSvgChart) {
dialogSvgChart.tick($scope.svgDivId);
+ }
}
})
$scope.$watch("dialogChart.lineColor", function (newValue, oldValue) {
@@ -219,8 +225,8 @@ var QDR = (function (QDR) {
QDRChartService.unRegisterChart($scope.dialogChart); // remove the chart
}
$scope.okClick = function () {
- cleanup();
- dialog.close();
+ cleanup();
+ dialog.close();
};
var initRateSlider = function () {
@@ -283,9 +289,9 @@ var QDR = (function (QDR) {
// update the chart on the popup dialog
var updateDialogChart = function () {
// draw the chart using the current data
- if (dialogSvgChart)
+ if (dialogSvgChart) {
dialogSvgChart.tick($scope.svgDivId);
-
+ }
// draw the chart again in 1 second
var updateRate = localStorage['updateRate'] ? localStorage['updateRate'] : 5000;
if (updateTimer)
@@ -301,6 +307,16 @@ var QDR = (function (QDR) {
return;
}
dialogSvgChart = new QDRChartService.AreaChart($scope.dialogChart);
+ $('input[name=lineColor]').val($scope.dialogChart.lineColor);
+ $('input[name=areaColor]').val($scope.dialogChart.areaColor);
+ $('input[name=areaColor]').on('input', function (e) {
+ $scope.dialogChart.areaColor = $(this).val();
+ updateDialogChart()
+ })
+ $('input[name=lineColor]').on('input', function (e) {
+ $scope.dialogChart.lineColor = $(this).val();
+ updateDialogChart()
+ })
if (updateTimer)
clearTimeout(updateTimer);
updateDialogChart();
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/js/qdrList.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrList.js b/console/hawtio/src/main/webapp/plugin/js/qdrList.js
deleted file mode 100644
index 7aa808e..0000000
--- a/console/hawtio/src/main/webapp/plugin/js/qdrList.js
+++ /dev/null
@@ -1,811 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements. See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership. The ASF licenses this file
-to you 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.
-*/
-/**
- * @module QDR
- */
-var QDR = (function(QDR) {
-
- /**
- * @method ListController
- * @param $scope
- * @param QDRService
- *
- * Controller for the main interface
- */
- QDR.module.controller("QDR.ListController", ['$scope', '$location', '$dialog', '$filter', 'localStorage', 'QDRService', 'QDRChartService',
- function ($scope, $location, $dialog, $filter, localStorage, QDRService, QDRChartService) {
-
- var updateIntervalHandle = undefined;
- var updateInterval = 5000;
- var ListExpandedKey = "QDRListExpanded";
- $scope.details = {};
-
- $scope.selectedEntity = localStorage['QDRSelectedEntity'] || "address";
- $scope.selectedNode = localStorage['QDRSelectedNode'];
- $scope.selectedNodeId = localStorage['QDRSelectedNodeId'];
- $scope.selectedRecordName = localStorage['QDRSelectedRecordName'];
- $scope.nodes = []
- $scope.currentNode = undefined;
- $scope.modes = [{
- content: '<a><i class="icon-list"></i> Attributes</a>',
- id: 'attributes',
- op: 'READ',
- title: "View router attributes",
- isValid: function () { return true; }
- },
- {
- content: '<a><i class="icon-edit"></i> Update</a>',
- id: 'operations',
- op: 'UPDATE',
- title: "Update this attribute",
- isValid: function () { return $scope.operations.indexOf(this.op) > -1 }
- },
- {
- content: '<a><i class="icon-plus"></i> Create</a>',
- id: 'operations',
- op: 'CREATE',
- title: "Create a new attribute",
- isValid: function () { return $scope.operations.indexOf(this.op) > -1 }
- },
- {
- content: '<a><i class="icon-remove"></i> Delete</a>',
- id: 'delete',
- op: 'DELETE',
- title: "Delete",
- isValid: function () { return $scope.operations.indexOf(this.op) > -1 }
- },
- {
- content: '<a><i class="icon-chart"></i> Chart</a>',
- id: 'charts',
- op: 'graph',
- title: "Graph attributes",
- isValid: function () { return false; return $scope.detailFields.some( function (field ) {
- return field.graph;
- })}
- },
- {
- content: '<a><i class="icon-eye-open"></i> Fetch</a>',
- id: 'log',
- op: 'GET-LOG',
- title: "Fetch recent log entries",
- isValid: function () { return ($scope.selectedEntity === 'log') }
- }
- ];
- $scope.operations = []
- $scope.currentMode = $scope.modes[0];
- $scope.isModeSelected = function (mode) {
- return mode === $scope.currentMode;
- }
- $scope.selectMode = function (mode) {
- $scope.currentMode = mode;
- if (mode.id === 'log') {
- $scope.logResults = "getting recent log entries...";
- QDRService.sendMethod($scope.currentNode.id, $scope.selectedEntity, {}, $scope.currentMode.op, function (nodeName, entity, response, context) {
- $scope.logResults = response.filter( function (entry) {
- return entry[0] === $scope.detailsObject.module
- }).sort( function (a, b) {
- return b[5] - a[5]
- }).map( function (entry) {
- return {
- type: entry[1],
- message: entry[2],
- source: entry[3],
- line: entry[4],
- time: Date(entry[5]).toString()
- }
- })
- $scope.$apply();
- })
- }
- }
- $scope.isValid = function (mode) {
- return mode.isValid()
- }
-
- if (!QDRService.connected) {
- // we are not connected. we probably got here from a bookmark or manual page reload
- QDRService.redirectWhenConnected("list");
- return;
- }
- // we are currently connected. setup a handler to get notified if we are ever disconnected
- QDRService.addDisconnectAction( function () {
- QDRService.redirectWhenConnected("list")
- $scope.$apply();
- })
-
- $scope.nodes = QDRService.nodeList().sort(function (a, b) { return a.name.toLowerCase() > b.name.toLowerCase()});
- // unable to get node list? Bail.
- if ($scope.nodes.length == 0) {
- $location.path("/" + QDR.pluginName + "/connect")
- $location.search('org', "list");
- }
- if (!angular.isDefined($scope.selectedNode)) {
- //QDR.log.debug("selectedNode was " + $scope.selectedNode);
- if ($scope.nodes.length > 0) {
- $scope.selectedNode = $scope.nodes[0].name;
- $scope.selectedNodeId = $scope.nodes[0].id;
- //QDR.log.debug("forcing selectedNode to " + $scope.selectedNode);
- }
- }
- var setCurrentNode = function () {
- $scope.nodes.some( function (node, i) {
- if (node.name === $scope.selectedNode) {
- $scope.currentNode = $scope.nodes[i]
- return true;
- }
- })
- }
- setCurrentNode();
- if ($scope.currentNode == undefined) {
- if ($scope.nodes.length > 0) {
- $scope.selectedNode = $scope.nodes[0].name;
- $scope.selectedNodeId = $scope.nodes[0].id;
- $scope.currentNode = $scope.nodes[0];
- }
- }
-
- var excludedEntities = ["management", "org.amqp.management", "operationalEntity", "entity", "configurationEntity", "dummy", "console"];
- var aggregateEntities = ["router.address"];
- var classOverrides = {
- "connection": function (row) {
- return row.role.value;
- },
- "router.link": function (row) {
- return row.linkType.value;
- }
- }
-
- var lookupOperations = function () {
- var ops = QDRService.schema.entityTypes[$scope.selectedEntity].operations.filter( function (op) { return op !== 'READ'});
- $scope.operation = ops.length ? ops[0] : "";
- return ops;
- }
-
- var entityTreeChildren = [];
- var expandedList = angular.fromJson(localStorage[ListExpandedKey]) || [];
- var sortedEntities = Object.keys(QDRService.schema.entityTypes).sort();
- sortedEntities.forEach( function (entity) {
- if (excludedEntities.indexOf(entity) == -1) {
- if (!angular.isDefined($scope.selectedEntity)) {
- $scope.selectedEntity = entity;
- $scope.operations = lookupOperations()
- }
- var e = new Folder(entity)
- e.typeName = "entity"
- e.key = entity
- e.expand = (expandedList.indexOf(entity) > -1)
- var placeHolder = new Folder("loading...")
- placeHolder.addClass = "loading"
- e.children = [placeHolder]
- entityTreeChildren.push(e)
- }
- })
- $scope.treeReady = function () {
- $('#entityTree').dynatree({
- onActivate: onTreeSelected,
- onExpand: onTreeNodeExpanded,
- selectMode: 1,
- activeVisible: false,
- children: entityTreeChildren
- })
- restartUpdate(); // start getting the data now that the tree is created
- updateExpandedEntities();
- };
- var onTreeNodeExpanded = function (expanded, node) {
- // save the list of entities that are expanded
- var tree = $("#entityTree").dynatree("getTree");
- var list = [];
- tree.visit( function (tnode) {
- if (tnode.isExpanded()) {
- list.push(tnode.data.key)
- }
- })
- localStorage[ListExpandedKey] = JSON.stringify(list)
-
- if (expanded)
- onTreeSelected(node);
- }
- // a tree node was selected
- var onTreeSelected = function (selectedNode) {
- if ($scope.currentMode.id === 'operations')
- $scope.currentMode = $scope.modes[0];
- else if ($scope.currentMode.id === 'log')
- $scope.selectMode($scope.currentMode)
- else if ($scope.currentMode.id === 'delete') {
- // clicked on a tree node while on the delete screen -> switch to attribute screen
- $scope.currentMode = $scope.modes[0];
- }
- if (selectedNode.data.typeName === "entity") {
- $scope.selectedEntity = selectedNode.data.key;
- $scope.operations = lookupOperations()
- } else if (selectedNode.data.typeName === 'attribute') {
- $scope.selectedEntity = selectedNode.parent.data.key;
- $scope.operations = lookupOperations()
- $scope.selectedRecordName = selectedNode.data.key;
- updateDetails(selectedNode.data.details); // update the table on the right
- $("#entityTree").dynatree("getRoot").visit(function(node){
- node.select(false);
- });
- selectedNode.select();
- }
- $scope.$apply();
- }
- // fill in an empty results recoord based on the entities schema
- var fromSchema = function (entityName) {
- var row = {}
- var schemaEntity = QDRService.schema.entityTypes[entityName]
- for (attr in schemaEntity.attributes) {
- var entity = schemaEntity.attributes[attr]
- var value = ""
- if (angular.isDefined(entity['default']))
- value = entity['default']
- row[attr] = {
- value: value,
- type: entity.type,
- graph: false,
- title: entity.description,
- aggregate: false,
- aggregateTip: '',
- 'default': entity['default']
- }
- }
- return row;
- }
- $scope.hasCreate = function () {
- var schemaEntity = QDRService.schema.entityTypes[$scope.selectedEntity]
- return (schemaEntity.operations.indexOf("CREATE") > -1)
- }
-
- var stopUpdating = function () {
- if (angular.isDefined(updateIntervalHandle)) {
- clearInterval(updateIntervalHandle);
- }
- updateIntervalHandle = undefined;
- }
-
- // the data for the selected entity is available, populate the tree
- var updateEntityChildren = function (entity, tableRows, expand) {
- var tree = $("#entityTree").dynatree("getTree");
- if (!tree.getNodeByKey) {
- return stopUpdating()
- }
- var node = tree.getNodeByKey(entity)
- var updatedDetails = false;
- var scrollTreeDiv = $('.qdr-attributes.pane.left .pane-viewport')
- var scrollTop = scrollTreeDiv.scrollTop();
- node.removeChildren();
- if (tableRows.length == 0) {
- node.addChild({
- addClass: "no-data",
- typeName: "none",
- title: "no data",
- key: node.data.key + ".1"
- })
- if (expand) {
- updateDetails(fromSchema(entity));
- $scope.selectedRecordName = entity;
- }
- } else {
- tableRows.forEach( function (row) {
- var addClass = entity;
- if (classOverrides[entity]) {
- addClass += " " + classOverrides[entity](row);
- }
- var child = {
- typeName: "attribute",
- addClass: addClass,
- key: row.name.value,
- title: row.name.value,
- details: row
- }
- if (row.name.value === $scope.selectedRecordName) {
- if (expand)
- updateDetails(row); // update the table on the right
- child.select = true;
- updatedDetails = true;
- }
- node.addChild(child)
- })
- }
- // if the selectedRecordName was not found, select the 1st one
- if (expand && !updatedDetails && tableRows.length > 0) {
- var row = tableRows[0];
- $scope.selectedRecordName = row.name.value;
- var node = tree.getNodeByKey($scope.selectedRecordName);
- node.select(true);
- updateDetails(row) // update the table on the right
- }
- scrollTreeDiv.scrollTop(scrollTop)
- }
-
- var schemaProps = function (entityName, key, currentNode) {
- var typeMap = {integer: 'number', string: 'text', path: 'text', boolean: 'boolean', map: 'textarea'};
-
- var entity = QDRService.schema.entityTypes[entityName]
- var value = entity.attributes[key]
- // skip identity and depricated fields
- if (!value)
- return {input: 'input', type: 'disabled', required: false, selected: "", rawtype: 'string', disabled: true, 'default': ''}
- var description = value.description || ""
- var val = value['default'];
- var disabled = (key == 'identity' || description.startsWith('Deprecated'))
- // special cases
- if (entityName == 'log' && key == 'module') {
- return {input: 'input', type: 'disabled', required: false, selected: "", rawtype: 'string', disabled: true, 'default': ''}
- }
- if (entityName === 'linkRoutePattern' && key === 'connector') {
- // turn input into a select. the values will be populated later
- value.type = []
- // find all the connector names and populate the select
- QDRService.getNodeInfo(currentNode.id, '.connector', ['name'], function (nodeName, dotentity, response) {
- $scope.detailFields.some( function (field) {
- if (field.name === 'connector') {
- field.rawtype = response.results.map (function (result) {return result[0]})
- return true;
- }
- })
- });
- }
- return { name: key,
- humanName: QDRService.humanify(key),
- description:value.description,
- type: disabled ? 'disabled' : typeMap[value.type],
- rawtype: value.type,
- input: typeof value.type == 'string' ? value.type == 'boolean' ? 'boolean' : 'input'
- : 'select',
- selected: val ? val : undefined,
- 'default': value['default'],
- value: val,
- required: value.required,
- unique: value.unique,
- disabled: disabled
- };
- }
- $scope.getAttributeValue = function (attribute) {
- var value = attribute.attributeValue;
- if ($scope.currentMode.op === "CREATE" && attribute.name === 'identity')
- value = "<assigned by system>"
- return value;
- }
-
- // update the table on the right
- var updateDetails = function (row) {
- var details = [];
- $scope.detailsObject = {};
- var attrs = Object.keys(row).sort();
- attrs.forEach( function (attr) {
- var changed = $scope.detailFields.filter(function (old) {
- return (old.name === attr) ? old.graph && old.rawValue != row[attr].value : false;
- })
- var schemaEntity = schemaProps($scope.selectedEntity, attr, $scope.currentNode)
- details.push( {
- attributeName: QDRService.humanify(attr),
- attributeValue: attr === 'port' ? row[attr].value : QDRService.pretty(row[attr].value),
- name: attr,
- changed: changed.length,
- rawValue: row[attr].value,
- graph: row[attr].graph,
- title: row[attr].title,
- aggregateValue: QDRService.pretty(row[attr].aggregate),
- aggregateTip: row[attr].aggregateTip,
-
- input: schemaEntity.input,
- type: schemaEntity.type,
- required: schemaEntity.required,
- selected: schemaEntity.selected,
- rawtype: schemaEntity.rawtype,
- disabled: schemaEntity.disabled,
- 'default': schemaEntity['default']
- })
- $scope.detailsObject[attr] = row[attr].value;
- })
- setTimeout(applyDetails, 1, details)
- }
-
- var applyDetails = function (details) {
- $scope.detailFields = details;
- aggregateColumn();
- $scope.$apply();
- // ng-grid bug? the entire table doesn't always draw unless a reflow is triggered;
- $(window).trigger('resize');
- }
-
- var restartUpdate = function () {
- stopUpdating();
- updateTableData($scope.selectedEntity, true);
- updateIntervalHandle = setInterval(updateExpandedEntities, updateInterval);
- }
- var updateExpandedEntities = function () {
- var tree = $("#entityTree").dynatree("getTree");
- if (tree.visit) {
- tree.visit( function (node) {
- if (node.isExpanded()) {
- updateTableData(node.data.key, node.data.key === $scope.selectedEntity)
- }
- })
- } else {
- stopUpdating();
- }
- }
-
- $scope.selectNode = function(node) {
- $scope.selectedNode = node.name;
- $scope.selectedNodeId = node.id;
- setCurrentNode();
- restartUpdate();
- };
- $scope.$watch('selectedEntity', function(newValue, oldValue) {
- if (newValue !== oldValue) {
- localStorage['QDRSelectedEntity'] = $scope.selectedEntity;
- restartUpdate();
- $scope.operations = lookupOperations()
- }
- })
- $scope.$watch('selectedNode', function(newValue, oldValue) {
- if (newValue !== oldValue) {
- localStorage['QDRSelectedNode'] = $scope.selectedNode;
- localStorage['QDRSelectedNodeId'] = $scope.selectedNodeId;
- }
- })
- $scope.$watch('selectedRecordName', function(newValue, oldValue) {
- if (newValue != oldValue) {
- localStorage['QDRSelectedRecordName'] = $scope.selectedRecordName;
- }
- })
-
- /* Called periodically to refresh the data on the page */
- var updateTableData = function (entity, expand) {
- if (!QDRService.connected) {
- // we are no longer connected. bail back to the connect page
- $location.path("/" + QDR.pluginName + "/connect")
- $location.search('org', "list");
- return;
- }
- // don't update the data when on the operations tab
- if ($scope.currentMode.id === 'operations') {
- return;
- }
-
- var gotNodeInfo = function (nodeName, dotentity, response) {
- var tableRows = [];
- var records = response.results;
- var aggregates = response.aggregates;
- var attributeNames = response.attributeNames;
- // If !attributeNmes then there was an error getting the records for this entity
- if (attributeNames) {
- var nameIndex = attributeNames.indexOf("name");
- var identityIndex = attributeNames.indexOf("identity");
- var ent = QDRService.schema.entityTypes[entity];
- for (var i=0; i<records.length; ++i) {
- var record = records[i];
- var aggregate = aggregates ? aggregates[i] : undefined;
- var row = {};
- var rowName;
- if (nameIndex > -1) {
- rowName = record[nameIndex];
- if (!rowName && identityIndex > -1) {
- rowName = record[nameIndex] = (dotentity + '/' + record[identityIndex])
- }
- }
- if (!rowName) {
- QDR.log.error("response attributeNames did not contain a name field");
- console.dump(response.attributeNames);
- return;
- }
- for (var j=0; j<attributeNames.length; ++j) {
- var col = attributeNames[j];
- row[col] = {value: record[j], type: undefined, graph: false, title: '', aggregate: '', aggregateTip: ''};
- if (ent) {
- var att = ent.attributes[col];
- if (att) {
- row[col].type = att.type;
- row[col].graph = att.graph;
- row[col].title = att.description;
-
- if (aggregate) {
- if (att.graph) {
- row[col].aggregate = att.graph ? aggregate[j].sum : '';
- var tip = [];
- aggregate[j].detail.forEach( function (line) {
- tip.push(line);
- })
- row[col].aggregateTip = angular.toJson(tip);
- }
- }
- }
- }
- }
- tableRows.push(row);
- }
- }
-
- tableRows.sort( function (a, b) { return a.name.value.localeCompare(b.name.value) })
- setTimeout(selectRow, 0, {entity: dotentity, rows: tableRows, expand: expand});
- }
- // if this entity should show an aggregate column, send the request to get the info for this entity from all the nedes
- if (aggregateEntities.indexOf(entity) > -1) {
- var nodeInfo = QDRService.topology.nodeInfo();
- QDRService.getMultipleNodeInfo(Object.keys(nodeInfo), entity, [], gotNodeInfo, $scope.selectedNodeId);
- } else {
- QDRService.getNodeInfo($scope.selectedNodeId, entity, [], gotNodeInfo);
- }
- };
-
- // tableRows are the records that were returned, this populates the left hand table on the page
- var selectRow = function (info) {
- updateEntityChildren(info.entity, info.rows, info.expand);
- fixTooltips();
- }
-
- var titleFromAlt = function (alt) {
- if (alt && alt.length) {
- var data = angular.fromJson(alt);
- var table = "<table class='tiptable'><tbody>";
- data.forEach (function (row) {
- table += "<tr>";
- table += "<td>" + row.node + "</td><td align='right'>" + QDRService.pretty(row.val) + "</td>";
- table += "</tr>"
- })
- table += "</tbody></table>"
- return table;
- }
- return '';
- }
- var fixTooltips = function () {
- if ($('.hastip').length == 0) {
- setTimeout(fixTooltips, 100);
- return;
- }
- $('.hastip').each( function (i, tip) {
- var tipset = tip.getAttribute('tipset')
- if (!tipset) {
- $(tip).tipsy({html: true, className: 'subTip', opacity: 1, title: function () {
- return titleFromAlt(this.getAttribute('alt'))
- } });
- tip.setAttribute('tipset', true)
- } else {
- var title = titleFromAlt(tip.getAttribute('alt'))
- tip.setAttribute('original-title', title)
- }
- })
- }
-
- $scope.detailFields = [];
-
- $scope.addToGraph = function(rowEntity) {
- var chart = QDRChartService.registerChart(
- {nodeId: $scope.selectedNodeId,
- entity: "." + $scope.selectedEntity,
- name: $scope.selectedRecordName,
- attr: rowEntity.name,
- forceCreate: true});
- doDialog("template-from-script.html", chart);
- }
-
- $scope.addAllToGraph = function(rowEntity) {
- var chart = QDRChartService.registerChart({
- nodeId: $scope.selectedNodeId,
- entity: $scope.selectedEntity,
- name: $scope.selectedRecordName,
- attr: rowEntity.name,
- type: "rate",
- rateWindow: udateInterval,
- visibleDuration: 1,
- forceCreate: true,
- aggregate: true});
- doDialog("template-from-script.html", chart);
- }
-
- $scope.detailCols = [];
- var aggregateColumn = function () {
- if ((aggregateEntities.indexOf($scope.selectedEntity) > -1 && $scope.detailCols.length != 3) ||
- (aggregateEntities.indexOf($scope.selectedEntity) == -1 && $scope.detailCols.length != 2)) {
- // column defs have to be reassigned and not spliced, so no push/pop
- $scope.detailCols = [
- {
- field: 'attributeName',
- displayName: 'Attribute',
- cellTemplate: '<div title="{{row.entity.title}}" class="listAttrName">{{row.entity[col.field]}}<i ng-if="row.entity.graph" ng-click="addToGraph(row.entity)" ng-class="{\'icon-bar-chart\': row.entity.graph == true }"></i></div>'
- },
- {
- field: 'attributeValue',
- displayName: 'Value',
- cellTemplate: '<div class="ngCellText" ng-class="{\'changed\': row.entity.changed == 1}"><span>{{row.getProperty(col.field)}}</span></div>'
- }
- ]
- if (aggregateEntities.indexOf($scope.selectedEntity) > -1) {
- $scope.detailCols.push(
- {
- width: '10%',
- field: 'aggregateValue',
- displayName: 'Aggregate',
- cellTemplate: '<div class="hastip" alt="{{row.entity.aggregateTip}}"><span ng-class="{\'changed\': row.entity.changed == 1}">{{row.entity[col.field]}}</span><i ng-if="row.entity.graph" ng-click="addAllToGraph(row.entity)" ng-class="{\'icon-bar-chart\': row.entity.graph == true }"></i></div>',
- cellClass: 'aggregate'
- }
- )
- }
- }
- if ($scope.selectedRecordName === "")
- $scope.detailCols = [];
- }
-
- // the table on the right of the page contains a row for each field in the selected record in the table on the left
- $scope.details = {
- data: 'detailFields',
- columnDefs: "detailCols",
- enableColumnResize: true,
- multiSelect: false,
- beforeSelectionChange: function() {
- return false;
- }
- };
- $scope.$on("$destroy", function( event ) {
- //QDR.log.debug("scope destroyed for qdrList");
- stopUpdating();
- });
-
- function gotMethodResponse (nodeName, entity, response, context) {
- var statusCode = context.message.application_properties.statusCode;
- if (statusCode < 200 || statusCode >= 300) {
- Core.notification('error', context.message.application_properties.statusDescription);
- //QDR.log.debug(context.message.application_properties.statusDescription)
- } else {
- var note = entity + " " + $filter('Pascalcase')($scope.currentMode.op) + "d"
- Core.notification('success', note);
- $scope.selectMode($scope.modes[0]);
- restartUpdate();
- }
- }
- $scope.ok = function () {
- var attributes = {}
- $scope.detailFields.forEach( function (field) {
- var value = field.rawValue;
- if (field.input === 'input') {
- if (field.type === 'text' || field.type === 'disabled')
- value = field.attributeValue;
- } else if (field.input === 'select') {
- value = field.selected;
- } else if (field.input === 'boolean') {
- value = field.rawValue
- }
- if (value === "")
- value = undefined;
-
- if ((value && value != field['default']) || field.required || (field.name === 'role')) {
- if (field.name !== 'identity')
- attributes[field.name] = value
- }
- })
- QDRService.sendMethod($scope.currentNode.id, $scope.selectedEntity, attributes, $scope.currentMode.op, gotMethodResponse)
- }
- $scope.remove = function () {
- var attributes = {type: $scope.selectedEntity, name: $scope.selectedRecordName}
- QDRService.sendMethod($scope.currentNode.id, $scope.selectedEntity, attributes, $scope.currentMode.op, gotMethodResponse)
- }
-
- function doDialog(template, chart) {
- var d = $dialog.dialog({
- backdrop: true,
- keyboard: true,
- backdropClick: true,
- templateUrl: template,
- controller: "QDR.ListChartController",
- resolve: {
- chart: function() {
- return chart
- },
- nodeName: function () {
- return $scope.selectedNode
- }
- }
- });
-
- d.open().then(function(result) { console.log("d.open().then"); });
-
- };
- }]);
-
- QDR.module.controller('QDR.ListChartController', function ($scope, dialog, $dialog, $location, localStorage, QDRChartService, chart, nodeName) {
- $scope.chart = chart;
- $scope.dialogSvgChart = null;
- var updateTimer = null;
- $scope.svgDivId = "dialogChart"; // the div id for the svg chart
-
- $scope.showChartsPage = function () {
- cleanup();
- dialog.close(true);
- $location.path("/" + QDR.pluginName + "/charts");
- };
-
- $scope.addHChart = function () {
- QDRChartService.addHDash($scope.chart);
- cleanup();
- dialog.close(true);
- }
-
- $scope.addToDashboardLink = function () {
- var href = "#/" + QDR.pluginName + "/charts";
- var size = angular.toJson({
- size_x: 2,
- size_y: 2
- });
-
- var params = angular.toJson({chid: $scope.chart.id()});
- var title = "Dispatch - " + nodeName;
- return "/hawtio/#/dashboard/add?tab=dashboard" +
- "&href=" + encodeURIComponent(href) +
- "&routeParams=" + encodeURIComponent(params) +
- "&title=" + encodeURIComponent(title) +
- "&size=" + encodeURIComponent(size);
- };
-
-
- $scope.addChartsPage = function () {
- QDRChartService.addDashboard($scope.chart);
- };
-
- $scope.delChartsPage = function () {
- QDRChartService.delDashboard($scope.chart);
- };
-
- $scope.isOnChartsPage = function () {
- return $scope.chart.dashboard;
- }
-
- var showChart = function () {
- // the chart divs are generated by angular and aren't available immediately
- var div = angular.element("#" + $scope.svgDivId);
- if (!div.width()) {
- setTimeout(showChart, 100);
- return;
- }
- dialogSvgChart = new QDRChartService.AreaChart($scope.chart);
- $scope.dialogSvgChart = dialogSvgChart;
- updateDialogChart();
- }
- showChart();
-
- var updateDialogChart = function () {
- if ($scope.dialogSvgChart)
- $scope.dialogSvgChart.tick($scope.svgDivId);
- if (updateTimer)
- clearTimeout(updateTimer)
- updateTimer = setTimeout(updateDialogChart, 1000);
- }
-
- var cleanup = function () {
- if (updateTimer) {
- clearTimeout(updateTimer);
- updateTimer = null;
- }
- if (!$scope.chart.hdash)
- QDRChartService.unRegisterChart($scope.chart); // remove the chart
-
- }
- $scope.ok = function () {
- cleanup();
- dialog.close(true);
- //dialogService.cancel("myDialog");
- };
-
- });
- return QDR;
-
-} (QDR || {}));
-// messaging-ci-01.mw.lab.eng.bos.redhat.com
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrList.js b/console/hawtio/src/main/webapp/plugin/js/qdrList.js
new file mode 120000
index 0000000..3955db5
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrList.js
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/js/qdrList.js
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/js/qdrListChart.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/js/qdrListChart.js b/console/hawtio/src/main/webapp/plugin/js/qdrListChart.js
new file mode 120000
index 0000000..d1fcf4a
--- /dev/null
+++ b/console/hawtio/src/main/webapp/plugin/js/qdrListChart.js
@@ -0,0 +1 @@
+../../../../../../stand-alone/plugin/js/qdrListChart.js
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[02/11] qpid-dispatch git commit: DISPATCH-316 Hawtio and stand-alone
consoles now use common code
Posted by ea...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/js/qdrSettings.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrSettings.js b/console/stand-alone/plugin/js/qdrSettings.js
index 950e1c5..e81463a 100644
--- a/console/stand-alone/plugin/js/qdrSettings.js
+++ b/console/stand-alone/plugin/js/qdrSettings.js
@@ -28,7 +28,8 @@ var QDR = (function (QDR) {
*
* Controller that handles the QDR settings page
*/
- QDR.module.controller("QDR.SettingsController", ['$scope', 'QDRService', '$location', function($scope, QDRService, $location) {
+
+ QDR.module.controller("QDR.SettingsController", ['$scope', 'QDRService', '$timeout', '$location', function($scope, QDRService, $timeout, $location) {
$scope.connecting = false;
$scope.connectionError = false;
@@ -36,38 +37,6 @@ var QDR = (function (QDR) {
$scope.forms = {};
$scope.formEntity = angular.fromJson(localStorage[QDR.SETTINGS_KEY]) || {address: '', port: '', username: '', password: '', autostart: false};
- $scope.formConfig = {
- properties: {
- address: {
- description: "Router address",
- 'type': 'java.lang.String',
- required: true
- },
- port: {
- description: 'Router port',
- 'type': 'Integer',
- tooltip: 'Ports to connect to, by default 5672'
- },
- username: {
- description: 'User Name',
- 'type': 'java.lang.String'
- },
- password: {
- description: 'Password',
- 'type': 'password'
- },
- /*
- useSSL: {
- description: 'SSL',
- 'type': 'boolean'
- },*/
- autostart: {
- description: 'Connect at startup',
- 'type': 'boolean',
- tooltip: 'Whether or not the connection should be started as soon as you log into hawtio'
- }
- }
- };
$scope.$watch('formEntity', function(newValue, oldValue) {
if (newValue !== oldValue) {
@@ -77,39 +46,106 @@ var QDR = (function (QDR) {
$scope.buttonText = function() {
if (QDRService.isConnected()) {
- return "Reconnect";
+ return "Disconnect";
} else {
return "Connect";
}
};
-
$scope.connect = function() {
- if ($scope.settings.$valid) {
- $scope.connectionError = false;
- $scope.connecting = true;
- console.log("attempting to connect");
- QDRService.addDisconnectAction(function() {
- //QDR.log.debug("disconnect action called");
- $scope.connecting = false;
- $scope.connectionErrorText = QDRService.errorText;
- $scope.connectionError = true;
- $scope.$apply();
- });
+ if (QDRService.connected) {
+ QDRService.disconnect();
+ return;
+ }
+
+ if ($scope.settings.$valid) {
+ $scope.connectionError = false;
+ $scope.connecting = true;
+ $timeout( doConnect ) // timeout so connecting animation can display
+ }
+ }
+
+ var doConnect = function () {
+ if (!$scope.formEntity.address)
+ $scope.formEntity.address = "localhost"
+
+ console.log("attempting to connect to " + $scope.formEntity.address + ':' + $scope.formEntity.port);
+ QDRService.addDisconnectAction(function () {
+ $timeout( function () {
+ QDR.log.debug("disconnect action called");
+ $scope.connecting = false;
+ $scope.connectionErrorText = QDRService.errorText;
+ $scope.connectionError = true;
+ })
+ });
QDRService.addConnectAction(function() {
//QDR.log.debug("got connection notification");
- $scope.connecting = false;
- //console.log("we were on connect page. let's switch to topo now that we are connected");
- //QDR.log.debug("location before the connect " + $location.path());
- $location.path("/overview");
- //QDR.log.debug("location after the connect " + $location.path());
- $scope.$apply();
+ $timeout( function () {
+ $scope.connecting = false;
+ })
});
QDRService.connect($scope.formEntity);
}
- };
}]);
+
+QDR.module.directive('posint', function (){
+ return {
+ require: 'ngModel',
+
+ link: function(scope, elem, attr, ctrl) {
+ // input type number allows + and - but we don't want them so filter them out
+ elem.bind('keypress', function (event) {
+ var nkey = !event.charCode ? event.which : event.charCode;
+ var skey = String.fromCharCode(nkey);
+ var nono = "-+.,"
+ if (nono.indexOf(skey) >= 0) {
+ event.preventDefault();
+ return false;
+ }
+ // firefox doesn't filter out non-numeric input. it just sets the ctrl to invalid
+ if (/[\!\@\#\$\%^&*\(\)]/.test(skey) && event.shiftKey || // prevent shift numbers
+ !( // prevent all but the following
+ nkey <= 0 || // arrows
+ nkey == 8 || // delete|backspace
+ nkey == 13 || // enter
+ (nkey >= 37 && nkey <=40) || // arrows
+ event.ctrlKey || event.altKey || // ctrl-v, etc.
+ /[0-9]/.test(skey)) // numbers
+ ) {
+ event.preventDefault();
+ return false;
+ }
+ })
+ // check the current value of input
+ var _isPortInvalid = function (value) {
+ var port = value + ''
+ var isErrRange = false;
+ // empty string is valid
+ if (port.length !== 0) {
+ var n = ~~Number(port);
+ if (n < 1 || n > 65535) {
+ isErrRange = true;
+ }
+ }
+ ctrl.$setValidity('range', !isErrRange)
+ return isErrRange;
+ }
+
+ //For DOM -> model validation
+ ctrl.$parsers.unshift(function(value) {
+ return _isPortInvalid(value) ? undefined : value;
+ });
+
+ //For model -> DOM validation
+ ctrl.$formatters.unshift(function(value) {
+ _isPortInvalid(value);
+ return value;
+ });
+ }
+ };
+});
+
return QDR;
}(QDR || {}));
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/stand-alone/plugin/js/qdrTopology.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrTopology.js b/console/stand-alone/plugin/js/qdrTopology.js
index 75b8b6e..9ab3689 100644
--- a/console/stand-alone/plugin/js/qdrTopology.js
+++ b/console/stand-alone/plugin/js/qdrTopology.js
@@ -21,20 +21,12 @@ under the License.
*/
var QDR = (function (QDR) {
- /**
- * @function TopologyFormController
- *
- * @param $scope
- * @param QDRService
- *
- * The controller for the topology page's connection/router info form on the left
- *
- */
- QDR.module.controller('QDR.TopologyFormController', ['$scope', 'QDRService',
- function ($scope, QDRService) {
+
+ QDR.module.controller('QDR.TopologyFormController', function ($scope, QDRService) {
$scope.attributes = []
- var generalCellTemplate = '<div class="ngCellText"><span title="{{row.entity.description}}">{{row.entity.attributeName}}</span></div>';
+ var nameTemplate = '<div title="{{row.entity.description}}" class="ngCellText"><span>{{row.entity.attributeName}}</span></div>';
+ var valueTemplate = '<div title="{{row.entity.attributeValue}}" class="ngCellText"><span>{{row.entity.attributeValue}}</span></div>';
$scope.topoGridOptions = {
data: 'attributes',
enableColumnResize: true,
@@ -43,11 +35,12 @@ var QDR = (function (QDR) {
{
field: 'attributeName',
displayName: 'Attribute',
- cellTemplate: generalCellTemplate
+ cellTemplate: nameTemplate
},
{
field: 'attributeValue',
- displayName: 'Value'
+ displayName: 'Value',
+ cellTemplate: valueTemplate
}
]
};
@@ -55,9 +48,9 @@ var QDR = (function (QDR) {
$scope.$on('showEntityForm', function (event, args) {
var attributes = args.attributes;
var entityTypes = QDRService.schema.entityTypes[args.entity].attributes;
- Object.keys(attributes).forEach( function (attr) {
- if (entityTypes[attr])
- attributes[attr].description = entityTypes[attr]
+ attributes.forEach( function (attr) {
+ if (entityTypes[attr.attributeName] && entityTypes[attr.attributeName].description)
+ attr.description = entityTypes[attr.attributeName].description
})
$scope.attributes = attributes;
$scope.form = args.entity;
@@ -65,53 +58,225 @@ var QDR = (function (QDR) {
$scope.$on('showAddForm', function (event) {
$scope.form = 'add';
})
- $scope.getTableHeight = function (rows) {
- return {height: ((rows.length+2) * 30) + "px"};
- }
+ })
- }])
/**
* @method TopologyController
*
* Controller that handles the QDR topology page
*/
- QDR.module.controller("QDR.TopologyController", ['$scope', '$rootScope', 'uiGridConstants', 'QDRService', '$uibModal', '$location', '$timeout',
- function($scope, $rootScope, uiGridConstants, QDRService, $uibModal, $location, $timeout) {
-
- $scope.multiData = [{name: ''}, {name: ''}, {name: ''}]
+ QDR.module.controller("QDR.TopologyController", ['$scope', '$rootScope', 'QDRService', '$location', '$timeout', '$dialog',
+ function($scope, $rootScope, QDRService, $location, $timeout, $dialog) {
+
+ $scope.multiData = []
+ $scope.selectedClient = [];
+ $scope.quiesceState = {}
+ var dontHide = false;
+ $scope.quiesceConnection = function (row) {
+ var entity = row.entity;
+ var state = $scope.quiesceState[entity.connectionId].state;
+ if (state === 'enabled') {
+ // start quiescing all links
+ $scope.quiesceState[entity.connectionId].state = 'quiescing';
+ } else if (state === 'quiesced') {
+ // start reviving all links
+ $scope.quiesceState[entity.connectionId].state = 'reviving';
+ }
+ $scope.multiDetails.updateState(entity);
+ dontHide = true;
+ $scope.multiDetails.selectRow(row.rowIndex, true);
+ $scope.multiDetails.showLinksList(row)
+ }
+ $scope.quiesceDisabled = function (row) {
+ return $scope.quiesceState[row.entity.connectionId].buttonDisabled;
+ }
+ $scope.quiesceText = function (row) {
+ return $scope.quiesceState[row.entity.connectionId].buttonText;
+ }
+ $scope.quiesceClass = function (row) {
+ var stateClassMap = {
+ enabled: 'btn-primary',
+ quiescing: 'btn-warning',
+ reviving: 'btn-warning',
+ quiesced: 'btn-danger'
+ }
+ return stateClassMap[$scope.quiesceState[row.entity.connectionId].state];
+ }
$scope.multiDetails = {
data: 'multiData',
+ selectedItems: $scope.selectedClient,
+ multiSelect: false,
+ afterSelectionChange: function (obj) {
+ if (obj.selected && obj.orig) {
+ var detailsDiv = d3.select('#link_details')
+ var isVis = detailsDiv.style('display') === 'block';
+ if (!dontHide && isVis && $scope.connectionId === obj.entity.connectionId) {
+ hideLinkDetails();
+ return;
+ }
+ dontHide = false;
+ $scope.multiDetails.showLinksList(obj)
+ }
+ },
+ showLinksList: function (obj) {
+ $scope.linkData = obj.entity.linkData;
+ $scope.connectionId = obj.entity.connectionId;
+ var visibleLen = Math.min(obj.entity.linkData.length, 10)
+ var left = parseInt(d3.select('#multiple_details').style("left"))
+ var detailsDiv = d3.select('#link_details')
+ detailsDiv
+ .style({
+ display: 'block',
+ opacity: 1,
+ left: (left + 20) + "px",
+ top: (mouseY + 20 + $(document).scrollTop()) + "px",
+ height: (visibleLen + 1) * 30 + "px", // +1 for the header row
+ 'overflow-y': obj.entity.linkData > 10 ? 'scroll' : 'hidden'})
+ },
+ updateState: function (entity) {
+ var state = $scope.quiesceState[entity.connectionId].state
+
+ // count enabled and disabled links for this connection
+ var enabled = 0, disabled = 0;
+ entity.linkData.forEach ( function (link) {
+ if (link.adminStatus === 'enabled')
+ ++enabled;
+ if (link.adminStatus === 'disabled')
+ ++disabled;
+ })
+
+ var linkCount = entity.linkData.length;
+ // if state is quiescing and any links are enabled, button should say 'Quiescing' and be disabled
+ if (state === 'quiescing' && (enabled > 0)) {
+ $scope.quiesceState[entity.connectionId].buttonText = 'Quiescing';
+ $scope.quiesceState[entity.connectionId].buttonDisabled = true;
+ } else
+ // if state is enabled and all links are disabled, button should say Revive and be enabled. set state to quisced
+ // if state is quiescing and all links are disabled, button should say 'Revive' and be enabled. set state to quiesced
+ if ((state === 'quiescing' || state === 'enabled') && (disabled === linkCount)) {
+ $scope.quiesceState[entity.connectionId].buttonText = 'Revive';
+ $scope.quiesceState[entity.connectionId].buttonDisabled = false;
+ $scope.quiesceState[entity.connectionId].state = 'quiesced'
+ } else
+ // if state is reviving and any links are disabled, button should say 'Reviving' and be disabled
+ if (state === 'reviving' && (disabled > 0)) {
+ $scope.quiesceState[entity.connectionId].buttonText = 'Reviving';
+ $scope.quiesceState[entity.connectionId].buttonDisabled = true;
+ } else
+ // if state is reviving or quiesced and all links are enabled, button should say 'Quiesce' and be enabled. set state to enabled
+ if ((state === 'reviving' || state === 'quiesced') && (enabled === linkCount)) {
+ $scope.quiesceState[entity.connectionId].buttonText = 'Quiesce';
+ $scope.quiesceState[entity.connectionId].buttonDisabled = false;
+ $scope.quiesceState[entity.connectionId].state = 'enabled'
+ }
+ },
columnDefs: [
{
field: 'host',
- displayName: 'Host'
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ displayName: 'Connection host'
},
{
field: 'user',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
displayName: 'User'
},
{
field: 'properties',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
displayName: 'Properties'
- },
+ }/*,
{
- field: 'isEncrypted',
- displayName: 'Encrypted'
- }
+ cellClass: 'gridCellButton',
+ cellTemplate: '<button title="{{quiesceText(row)}} the links" type="button" ng-class="quiesceClass(row)" class="btn" ng-click="$event.stopPropagation();quiesceConnection(row)" ng-disabled="quiesceDisabled(row)">{{quiesceText(row)}}</button>'
+ }*/
]
};
+ $scope.linkData = [];
+ $scope.quiesceLinkClass = function (row) {
+ var stateClassMap = {
+ enabled: 'btn-primary',
+ disabled: 'btn-danger'
+ }
+ return stateClassMap[row.entity.adminStatus]
+ //return stateClassMap[$scope.quiesceState[row.entity.connectionId].linkStates[row.entity.identity]];
+ }
+ $scope.quiesceLink = function (row) {
+ var state = row.entity.adminStatus === 'enabled' ? 'disabled' : 'enabled';
+ $scope.quiesceState[row.entity.connectionId].linkStates[row.entity.identity] = state;
+ }
+ $scope.quiesceLinkDisabled = function (row) {
+ return false;
+ }
+ $scope.quiesceLinkText = function (row) {
+ return row.entity.adminStatus === 'disabled' ? "Revive" : "Quiesce";
+ }
+ $scope.linkDetails = {
+ data: 'linkData',
+ columnDefs: [
+ {
+ field: 'adminStatus',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ displayName: 'Admin stat'
+ },
+ {
+ field: 'dir',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ displayName: 'dir'
+ },
+ {
+ field: 'owningAddr',
+ cellTemplate: "titleCellTemplate.html",
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ displayName: 'Address'
+ },
+ {
+ field: 'deliveryCount',
+ displayName: 'Delivered',
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ cellClass: 'grid-values'
+
+ },
+ {
+ field: 'undeliveredCount',
+ displayName: 'Undelivered',
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ cellClass: 'grid-values'
+ },
+ {
+ field: 'unsettledCount',
+ displayName: 'Unsettled',
+ headerCellTemplate: 'titleHeaderCellTemplate.html',
+ cellClass: 'grid-values'
+ }/*,
+
+ {
+ cellClass: 'gridCellButton',
+ cellTemplate: '<button title="{{quiesceLinkText(row)}} this link" type="button" ng-class="quiesceLinkClass(row)" class="btn" ng-click="quiesceLink(row)" ng-disabled="quiesceLinkDisabled(row)">{{quiesceLinkText(row)}}</button>'
+ }*/
+ ]
+ }
if (!QDRService.connected) {
// we are not connected. we probably got here from a bookmark or manual page reload
- $location.path("/dispatch_plugin/connect")
- $location.search('org', "topology");
+ QDRService.redirectWhenConnected("topology");
return;
}
+ // we are currently connected. setup a handler to get notified if we are ever disconnected
+ QDRService.addDisconnectAction( function () {
+ QDRService.redirectWhenConnected("topology");
+ $scope.$apply();
+ })
- QDR.log.debug("started QDR.TopologyController with urlPrefix: " + $location.absUrl());
- //var urlPrefix = $location.absUrl();
- var urlPrefix = window.location.pathname;
+ var urlPrefix = $location.absUrl();
+ urlPrefix = urlPrefix.split("#")[0]
+ QDR.log.debug("started QDR.TopologyController with urlPrefix: " + urlPrefix);
$scope.addingNode = {
step: 0,
@@ -139,7 +304,6 @@ var QDR = (function (QDR) {
$scope.modes = [
{title: 'Topology view', name: 'Diagram', right: false},
- /* {title: '3D Globe view', name: 'Globe', right: false}, */
/* {title: 'Add a new router node', name: 'Add Router', right: true} */
];
$scope.mode = "Diagram";
@@ -300,7 +464,6 @@ var QDR = (function (QDR) {
$(".contextMenu").fadeOut(200);
});
-
// set up SVG for D3
var width, height;
var tpdiv = $('#topology');
@@ -310,7 +473,14 @@ var QDR = (function (QDR) {
var radius = 25;
var radiusNormal = 15;
width = tpdiv.width() - gap;
- height = $(document).height() - gap;
+ var top = tpdiv.offset().top
+ var tpform = $('#topologyForm')
+ var tpformHeight = tpform.height()
+ height = Math.max(window.innerHeight, tpformHeight + top) - top - gap;
+ if (width < 10) {
+ QDR.log.info("page width and height are abynormal: returning before very bad things happen")
+ return;
+ }
var svg, lsvg;
var force;
@@ -372,13 +542,8 @@ var QDR = (function (QDR) {
}
}
- var cities = ["Raleigh"];
- var possibleCities = ["Boston","Tel Aviv-Yafo", "Brno", "Toronto", "Beijing", , "Ashburn", "Raleigh"]
- //var drag;
- // create an bare svg element and
// initialize the nodes and links array from the QDRService.topology._nodeInfo object
var initForceGraph = function () {
- //QDR.log.debug("initForceGraph called");
nodes = [];
links = [];
@@ -449,7 +614,6 @@ var QDR = (function (QDR) {
// initialize the list of links
var source = 0;
var client = 1;
- cities = ["Raleigh"];
for (var id in nodeInfo) {
var onode = nodeInfo[id];
var conns = onode['.connection'].results;
@@ -484,11 +648,13 @@ var QDR = (function (QDR) {
if (position.y > height)
position.y = nodes[parent].y + 40 + Math.cos(Math.PI/2 * client)
var node = aNode(id, name, role, nodeInfo, nodes.length, position.x, position.y, j, position.fixed, properties)
- var nodeType = role === 'normal' ? (properties.console_identifier == 'Dispatch console' ? 'console' : 'client') : 'broker';
+ var nodeType = QDRService.isAConsole(properties, QDRService.valFor(attrs, conns[j], "identity"), role, node.key)
+
if (role === 'normal') {
node.user = QDRService.valFor(attrs, conns[j], "user")
node.isEncrypted = QDRService.valFor(attrs, conns[j], "isEncrypted")
node.host = QDRService.valFor(attrs, conns[j], "host")
+ node.connectionId = QDRService.valFor(attrs, conns[j], "identity")
if (!normalsParent[nodeType]) {
normalsParent[nodeType] = node;
@@ -498,7 +664,6 @@ var QDR = (function (QDR) {
getLink(parent, nodes.length-1, dir);
client++;
} else {
-
normalsParent[nodeType].normals.push(node)
}
} else {
@@ -525,9 +690,6 @@ var QDR = (function (QDR) {
.on('tick', tick)
.start()
- //drag = force.drag()
- // .on("dragstart", dragstart);
-
svg.append("svg:defs").selectAll('marker')
.data(["end-arrow", "end-arrow-selected"]) // Different link/path types can be defined here
.enter().append("svg:marker") // This section adds in the arrows
@@ -573,217 +735,6 @@ var QDR = (function (QDR) {
}
- var initGlobe = function (clients) {
- d3.select(window)
- .on("mousemove", mousemove)
- .on("mouseup", mouseup);
-
- var width = 960,
- height = 500;
-
- var proj = d3.geo.orthographic()
- .scale(220)
- .translate([width / 2, height / 2])
- .clipAngle(90);
-
- var path = d3.geo.path().projection(proj).pointRadius(1.5);
-
- var links = [],
- arcLines = [];
-
- var graticule = d3.geo.graticule();
- d3.select("#geology svg").remove();
- var svg = d3.select("#geology").append("svg")
- .attr("width", width)
- .attr("height", height)
- .on("mousedown", mousedown);
-
- queue()
- .defer(d3.json, "plugin/data/world-110m.json")
- .defer(d3.json, "plugin/data/places1.json")
- .await(ready);
-
- function ready(error, world, places) {
- var ocean_fill = svg.append("defs").append("radialGradient")
- .attr("id", "ocean_fill")
- .attr("cx", "75%")
- .attr("cy", "25%");
- ocean_fill.append("stop").attr("offset", "5%").attr("stop-color", "#fff");
- ocean_fill.append("stop").attr("offset", "100%").attr("stop-color", "#eef");
-
- var globe_highlight = svg.append("defs").append("radialGradient")
- .attr("id", "globe_highlight")
- .attr("cx", "75%")
- .attr("cy", "25%");
- globe_highlight.append("stop")
- .attr("offset", "5%").attr("stop-color", "#ffd")
- .attr("stop-opacity","0.6");
- globe_highlight.append("stop")
- .attr("offset", "100%").attr("stop-color", "#ba9")
- .attr("stop-opacity","0.1");
-
- var globe_shading = svg.append("defs").append("radialGradient")
- .attr("id", "globe_shading")
- .attr("cx", "55%")
- .attr("cy", "45%");
- globe_shading.append("stop")
- .attr("offset","30%").attr("stop-color", "#fff")
- .attr("stop-opacity","0")
- globe_shading.append("stop")
- .attr("offset","100%").attr("stop-color", "#505962")
- .attr("stop-opacity","0.2")
-
- var drop_shadow = svg.append("defs").append("radialGradient")
- .attr("id", "drop_shadow")
- .attr("cx", "50%")
- .attr("cy", "50%");
- drop_shadow.append("stop")
- .attr("offset","20%").attr("stop-color", "#000")
- .attr("stop-opacity",".5")
- drop_shadow.append("stop")
- .attr("offset","100%").attr("stop-color", "#000")
- .attr("stop-opacity","0")
-
- svg.append("ellipse")
- .attr("cx", 440).attr("cy", 450)
- .attr("rx", proj.scale()*.90)
- .attr("ry", proj.scale()*.25)
- .attr("class", "noclicks")
- .style("fill", "url("+urlPrefix+"#drop_shadow)");
-
- svg.append("circle")
- .attr("cx", width / 2).attr("cy", height / 2)
- .attr("r", proj.scale())
- .attr("class", "noclicks")
- .style("fill", "url("+urlPrefix+"#ocean_fill)");
-
- svg.append("path")
- .datum(topojson.object(world, world.objects.land))
- .attr("class", "land noclicks")
- .attr("d", path);
-
- svg.append("path")
- .datum(graticule)
- .attr("class", "graticule noclicks")
- .attr("d", path);
-
- svg.append("circle")
- .attr("cx", width / 2).attr("cy", height / 2)
- .attr("r", proj.scale())
- .attr("class","noclicks")
- .style("fill", "url("+urlPrefix+"#globe_highlight)");
-
- svg.append("circle")
- .attr("cx", width / 2).attr("cy", height / 2)
- .attr("r", proj.scale())
- .attr("class","noclicks")
- .style("fill", "url("+urlPrefix+"#globe_shading)");
-
- var filtered = places.features.filter( function (feature) {
- return clients.indexOf(feature.properties.NAME) > -1
- })
- svg.append("g").attr("class","points")
- .selectAll("text").data(filtered)
- .enter().append("path")
- .attr("class", "point")
- .attr("d", path);
-
- svg.append("g").attr("class","labels")
- .selectAll("text").data(filtered)
- .enter().append("text")
- .attr("class", "label")
- .text(function(d) { return d.properties.NAME })
-
- position_labels();
-
- // spawn links between cities as source/target coord pairs
- places.features.forEach(function(a, i) {
- if (clients.indexOf(a.properties.NAME) > -1) {
- places.features.forEach(function(b, j) {
- if (b.properties.NAME === 'Raleigh') {
- if (j > i) { // avoid duplicates
- links.push({
- source: a.geometry.coordinates,
- target: b.geometry.coordinates
- });
- }
- }
- });
- }
- });
-
- // build geoJSON features from links array
- links.forEach(function(e,i,a) {
- var feature = { "type": "Feature", "geometry": { "type": "LineString", "coordinates": [e.source,e.target] }}
- arcLines.push(feature)
- })
-
- svg.append("g").attr("class","arcs")
- .selectAll("path").data(arcLines)
- .enter().append("path")
- .attr("class","arc")
- .attr("d",path)
- refresh();
- }
-
- function position_labels() {
- var centerPos = proj.invert([width/2,height/2]);
-
- var arc = d3.geo.greatArc();
-
- svg.selectAll(".label")
- .attr("transform", function(d) {
- var loc = proj(d.geometry.coordinates),
- x = loc[0],
- y = loc[1];
- var offset = x < width/2 ? -5 : 5;
- return "translate(" + (x+offset) + "," + (y-2) + ")"
- })
- .style("display",function(d) {
- var d = arc.distance({source: d.geometry.coordinates, target: centerPos});
- return (d > 1.57) ? 'none' : 'inline';
- })
- }
-
- function refresh() {
- svg.selectAll(".land").attr("d", path);
- svg.selectAll(".point").attr("d", path);
- svg.selectAll(".graticule").attr("d", path);
- svg.selectAll(".arc").attr("d", path);
- position_labels();
- }
-
- // modified from http://bl.ocks.org/1392560
- var m0, o0;
- o0 = angular.fromJson(localStorage["QDR.rotate"]);
- if (o0)
- proj.rotate(o0);
-
- function mousedown() {
- m0 = [d3.event.pageX, d3.event.pageY];
- o0 = proj.rotate();
- d3.event.preventDefault();
- }
- function mousemove() {
- if (m0) {
- var m1 = [d3.event.pageX, d3.event.pageY]
- , o1 = [o0[0] + (m1[0] - m0[0]) / 6, o0[1] + (m0[1] - m1[1]) / 6];
- o1[1] = o1[1] > 30 ? 30 :
- o1[1] < -30 ? -30 :
- o1[1];
- proj.rotate(o1);
- refresh();
- }
- }
- function mouseup() {
- if (m0) {
- mousemove();
- m0 = null;
- localStorage["QDR.rotate"] = angular.toJson(proj.rotate());
- }
- }
- }
-
function updateForm (key, entity, resultIndex) {
var nodeInfo = QDRService.topology.nodeInfo();
var onode = nodeInfo[key]
@@ -818,7 +769,7 @@ var QDR = (function (QDR) {
})
// add as 2nd row
if (ports.length)
- attributes.splice(1, 0, {attributeName: 'Listening on', attributeValue: ports});
+ attributes.splice(1, 0, {attributeName: 'Listening on', attributeValue: ports, description: 'The port on which this router is listening for connections'});
}
$scope.$broadcast('showEntityForm', {entity: entity, attributes: attributes})
@@ -848,7 +799,7 @@ var QDR = (function (QDR) {
}
nodeIndex++
}
- QDR.log.warn("unable to find containerIndex for " + _id);
+ //QDR.log.warn("unable to find containerIndex for " + _id);
return -1;
}
@@ -899,38 +850,59 @@ var QDR = (function (QDR) {
// update force layout (called automatically each iteration)
function tick() {
+ circle.attr('transform', function (d) {
+ var cradius;
+ if (d.nodeType == "inter-router") {
+ cradius = d.left ? radius + 8 : radius;
+ } else {
+ cradius = d.left ? radiusNormal + 18 : radiusNormal;
+ }
+ d.x = Math.max(d.x, radiusNormal * 2);
+ d.y = Math.max(d.y, radiusNormal * 2);
+ d.x = Math.max(0, Math.min(width-cradius, d.x))
+ d.y = Math.max(0, Math.min(height-cradius, d.y))
+ return 'translate(' + d.x + ',' + d.y + ')';
+ });
+
// draw directed edges with proper padding from node centers
path.attr('d', function (d) {
//QDR.log.debug("in tick for d");
//console.dump(d);
+ var sourcePadding, targetPadding, r;
+
+ if (d.target.nodeType == "inter-router") {
+ r = radius;
+ // right arrow left line start
+ sourcePadding = d.left ? radius + 8 : radius;
+ // left arrow right line start
+ targetPadding = d.right ? radius + 16 : radius;
+ } else {
+ r = radiusNormal - 18;
+ sourcePadding = d.left ? radiusNormal + 18 : radiusNormal;
+ targetPadding = d.right ? radiusNormal + 16 : radiusNormal;
+ }
+ var dtx = Math.max(targetPadding, Math.min(width-r, d.target.x)),
+ dty = Math.max(targetPadding, Math.min(height-r, d.target.y)),
+ dsx = Math.max(sourcePadding, Math.min(width-r, d.source.x)),
+ dsy = Math.max(sourcePadding, Math.min(height-r, d.source.y));
- var deltaX = d.target.x - d.source.x,
- deltaY = d.target.y - d.source.y,
+ var deltaX = dtx - dsx,
+ deltaY = dty - dsy,
dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY),
normX = deltaX / dist,
normY = deltaY / dist;
- var sourcePadding, targetPadding;
- if (d.target.nodeType == "inter-router") {
- // right arrow left line start
- sourcePadding = d.left ? radius + 8 : radius;
- // left arrow right line start
- targetPadding = d.right ? radius + 16 : radius;
- } else {
- sourcePadding = d.left ? radiusNormal + 18 : radiusNormal;
- targetPadding = d.right ? radiusNormal + 16 : radiusNormal;
- }
- var sourceX = d.source.x + (sourcePadding * normX),
- sourceY = d.source.y + (sourcePadding * normY),
- targetX = d.target.x - (targetPadding * normX),
- targetY = d.target.y - (targetPadding * normY);
+ var sourceX = dsx + (sourcePadding * normX),
+ sourceY = dsy + (sourcePadding * normY),
+ targetX = dtx - (targetPadding * normX),
+ targetY = dty - (targetPadding * normY);
+ sourceX = Math.max(0, Math.min(width, sourceX))
+ sourceY = Math.max(0, Math.min(width, sourceY))
+ targetX = Math.max(0, Math.min(width, targetX))
+ targetY = Math.max(0, Math.min(width, targetY))
+
return 'M' + sourceX + ',' + sourceY + 'L' + targetX + ',' + targetY;
});
- circle.attr('transform', function (d) {
- d.x = Math.max(d.x, radiusNormal * 2);
- d.y = Math.max(d.y, radiusNormal * 2);
- return 'translate(' + d.x + ',' + d.y + ')';
- });
if (!animate) {
animate = true;
force.stop();
@@ -961,7 +933,7 @@ var QDR = (function (QDR) {
var aAr = sInfo['.router.node'].attributeNames;
var vAr = sInfo['.router.node'].results;
for (var hIdx=0; hIdx<vAr.length; ++hIdx) {
- var addrT = QDRService.valFor(aAr, vAr[hIdx], "routerId" );
+ var addrT = QDRService.valFor(aAr, vAr[hIdx], "id" );
if (addrT == d.name) {
//QDR.log.debug("found " + d.name + " at " + hIdx);
var nextHop = QDRService.valFor(aAr, vAr[hIdx], "nextHop");
@@ -995,6 +967,14 @@ var QDR = (function (QDR) {
return null;
}
+ function clearPopups() {
+ d3.select("#crosssection").style("display", "none");
+ $('.hastip').empty();
+ d3.select("#multiple_details").style("display", "none")
+ d3.select("#link_details").style("display", "none")
+ d3.select('#node_context_menu').style('display', 'none');
+
+ }
function removeCrosssection() {
setTimeout(function () {
d3.select("[id^=tooltipsy]").remove()
@@ -1013,6 +993,16 @@ var QDR = (function (QDR) {
.style("opacity", 0)
.each("end", function (d) {
d3.select("#multiple_details").style("display", "none")
+ stopUpdateConnectionsGrid();
+ })
+ hideLinkDetails();
+ }
+ function hideLinkDetails() {
+ d3.select("#link_details").transition()
+ .duration(500)
+ .style("opacity", 0)
+ .each("end", function (d) {
+ d3.select("#link_details").style("display", "none")
})
}
@@ -1053,7 +1043,7 @@ var QDR = (function (QDR) {
}
return;
}
- //QDR.log.debug("showing connections form");
+ //QDR.log.debug("showing connections form");
var resultIndex = 0; // the connection to use
var left = d.left ? d.target : d.source;
// right is the node that the arrow points to, left is the other node
@@ -1078,7 +1068,8 @@ var QDR = (function (QDR) {
left = d.target;
resultIndex = left.resultIndex;
}
- updateForm(left.key, 'connection', resultIndex);
+ if (resultIndex)
+ updateForm(left.key, 'connection', resultIndex);
}
mousedown_link = d;
@@ -1110,7 +1101,9 @@ var QDR = (function (QDR) {
})
.on("click", function (d) {
dblckickPos = d3.mouse(this);
+ QDR.log.debug("dblckickPos is [" + dblckickPos[0] + ", " + dblckickPos[1] + "]")
d3.event.stopPropagation();
+ clearPopups();
var diameter = 400;
var format = d3.format(",d");
var pack = d3.layout.pack()
@@ -1118,16 +1111,13 @@ var QDR = (function (QDR) {
.padding(-10)
.value(function(d) { return d.size; });
+ d3.select("#crosssection svg").remove();
var svg = d3.select("#crosssection").append("svg")
.attr("width", diameter)
.attr("height", diameter)
var svgg = svg.append("g")
.attr("transform", "translate(2,2)");
- svg.on('click', function (d) {
- removeCrosssection();
- })
-
var root = {
name: "links between " + d.source.name + " and " + d.target.name,
children: []
@@ -1189,6 +1179,7 @@ var QDR = (function (QDR) {
node.append("circle")
.attr("r", function(d) { return d.r; });
+// node.filter(function(d) { return !d.children; }).append("text")
node.append("text")
.attr("dy", function (d) { return d.children ? "-10em" : ".3em"})
.style("text-anchor", "middle")
@@ -1203,7 +1194,6 @@ var QDR = (function (QDR) {
svgg.transition().attr("transform", "translate(2,2) scale(1)")
})
-
// remove old links
path.exit().remove();
@@ -1227,15 +1217,13 @@ var QDR = (function (QDR) {
// add new circles and set their attr/class/behavior
return g.append('svg:circle')
.attr('class', 'node')
- .attr('r', function (d) {
- return radii[d.nodeType];
- })
+ .attr('r', function (d) { return radii[d.nodeType] } )
.classed('fixed', function (d) {return d.fixed})
.classed('temp', function(d) { return QDRService.nameFromId(d.key) == '__internal__'; } )
.classed('normal', function(d) { return d.nodeType == 'normal' } )
.classed('inter-router', function(d) { return d.nodeType == 'inter-router' } )
.classed('on-demand', function(d) { return d.nodeType == 'on-demand' } )
- .classed('console', function(d) { return d.properties.console_identifier == 'Dispatch console' } )
+ .classed('console', function(d) { return QDRService.isConsole(d) } )
.classed('artemis', function(d) { return QDRService.isArtemis(d) } )
.classed('qpid-cpp', function(d) { return QDRService.isQpid(d) } )
.classed('client', function(d) { return d.nodeType === 'normal' && !d.properties.console_identifier } )
@@ -1329,8 +1317,7 @@ var QDR = (function (QDR) {
selected_node = null;
}
else {
- // don't select nodes that represent multiple clients/consoles
- if (!d.normals || d.normals.length < 2)
+ if (d.nodeType !== 'normal' && d.nodeType !== 'on-demand')
selected_node = mousedown_node;
}
for (var i=0; i<links.length; ++i) {
@@ -1363,7 +1350,10 @@ var QDR = (function (QDR) {
})
.on("click", function (d) {
- if (!d.normals || d.normals.length < 2) {
+ // clicked on a circle
+ clearPopups();
+ if (!d.normals) {
+ // circle was a router or a broker
if ( QDRService.isArtemis(d) && Core.ConnectionName === 'Artemis' ) {
$location.path('/jmx/attributes?tab=artemis&con=Artemis')
}
@@ -1371,19 +1361,7 @@ var QDR = (function (QDR) {
}
clickPos = d3.mouse(this);
d3.event.stopPropagation();
- $scope.multiData = []
- d.normals.forEach( function (n) {
- $scope.multiData.push(n)
- })
- $scope.$apply();
- d3.select('#multiple_details')
- .style({
- display: 'block',
- opacity: 1,
- height: (d.normals.length + 1) * 30 + "px",
- 'overflow-y': d.normals.length > 10 ? 'scroll' : 'hidden',
- left: (mouseX + $(document).scrollLeft()) + "px",
- top: (mouseY + $(document).scrollTop()) + "px"})
+ startUpdateConnectionsGrid(d);
})
var appendContent = function (g) {
@@ -1400,13 +1378,13 @@ var QDR = (function (QDR) {
y = 4;
return y;})
.attr('class', 'id')
- .classed('console', function(d) { return d.properties.console_identifier == 'Dispatch console' } )
+ .classed('console', function(d) { return QDRService.isConsole(d) } )
.classed('normal', function(d) { return d.nodeType === 'normal' } )
.classed('on-demand', function(d) { return d.nodeType === 'on-demand' } )
.classed('artemis', function(d) { return QDRService.isArtemis(d) } )
.classed('qpid-cpp', function(d) { return QDRService.isQpid(d) } )
.text(function (d) {
- if (d.properties.console_identifier == 'Dispatch console') {
+ if (QDRService.isConsole(d)) {
return '\uf108'; // icon-desktop for this console
}
if (QDRService.isArtemis(d)) {
@@ -1420,6 +1398,7 @@ var QDR = (function (QDR) {
return d.name.length>7 ? d.name.substr(0,6)+'...' : d.name;
});
}
+
appendContent(g)
var appendTitle = function (g) {
@@ -1427,7 +1406,7 @@ var QDR = (function (QDR) {
var x = '';
if (d.normals && d.normals.length > 1)
x = " x " + d.normals.length;
- if (d.properties.console_identifier == 'Dispatch console') {
+ if (QDRService.isConsole(d)) {
return 'Dispatch console' + x
}
if (d.properties.product == 'qpid-cpp') {
@@ -1446,12 +1425,16 @@ var QDR = (function (QDR) {
// add subcircles
svg.selectAll('.subcircle').remove();
-
- svg.selectAll('.multiple')
- .insert('svg:circle', '.normal')
- .attr('class', 'subcircle')
- .attr('r', 18)
-
+ var multiples = svg.selectAll('.multiple')
+ multiples.each( function (d) {
+ d.normals.forEach( function (n, i) {
+ if (i<d.normals.length-1 && i<3) // only show a few shadow circles
+ this.insert('svg:circle', ":first-child")
+ .attr('class', 'subcircle node')
+ .attr('r', 15 - i)
+ .attr('transform', "translate("+ 4 * (i+1) +", 0)")
+ }, d3.select(this))
+ })
// dynamically create the legend based on which node types are present
var legendNodes = [];
@@ -1477,6 +1460,7 @@ var QDR = (function (QDR) {
// 45px between lines and add 10px space after 1st line
return "translate(0, "+(45*i+(i>0?10:0))+")"
})
+
appendCircle(lg)
appendContent(lg)
appendTitle(lg)
@@ -1486,10 +1470,18 @@ var QDR = (function (QDR) {
.attr('class', "label")
.text(function (d) {return d.key })
lsvg.exit().remove();
- var svgEl = document.getElementById("svglegend"),
- bb = svgEl.getBBox();
- svgEl.style.height = bb.y + bb.height;
- svgEl.style.width = bb.x + bb.width;
+ var svgEl = document.getElementById('svglegend')
+ if (svgEl) {
+ var bb;
+ // firefox can throw an exception on getBBox on an svg element
+ try {
+ bb = svgEl.getBBox();
+ } catch (e) {
+ bb = {y: 0, height: 200, x: 0, width: 200}
+ }
+ svgEl.style.height = (bb.y + bb.height) + 'px';
+ svgEl.style.width = (bb.x + bb.width) + 'px';
+ }
if (!mousedown_node || !selected_node)
return;
@@ -1502,6 +1494,124 @@ var QDR = (function (QDR) {
}
+ var startUpdateConnectionsGrid = function (d) {
+ var extendConnections = function () {
+ $scope.multiData = []
+ var normals = d.normals;
+ // find updated normals for d
+ d3.selectAll('.normal')
+ .each(function(newd) {
+ if (newd.id == d.id && newd.name == d.name) {
+ normals = newd.normals;
+ }
+ });
+ if (normals) {
+ normals.forEach( function (n) {
+ var nodeInfo = QDRService.topology.nodeInfo();
+ var links = nodeInfo[n.key]['.router.link'];
+ var linkTypeIndex = links.attributeNames.indexOf('linkType');
+ var connectionIdIndex = links.attributeNames.indexOf('connectionId');
+ n.linkData = [];
+ links.results.forEach( function (link) {
+ if (link[linkTypeIndex] === 'endpoint' && link[connectionIdIndex] === n.connectionId) {
+ var l = {};
+ l.owningAddr = QDRService.valFor(links.attributeNames, link, 'owningAddr');
+ l.dir = QDRService.valFor(links.attributeNames, link, 'linkDir');
+ if (l.owningAddr && l.owningAddr.length > 2)
+ if (l.owningAddr[0] === 'M')
+ l.owningAddr = l.owningAddr.substr(2)
+ else
+ l.owningAddr = l.owningAddr.substr(1)
+
+ l.deliveryCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'deliveryCount'));
+ l.undeliveredCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'undeliveredCount'));
+ l.unsettledCount = QDRService.pretty(QDRService.valFor(links.attributeNames, link, 'unsettledCount'));
+ l.adminStatus = QDRService.valFor(links.attributeNames, link, 'adminStatus');
+ l.identity = QDRService.valFor(links.attributeNames, link, 'identity')
+ l.connectionId = QDRService.valFor(links.attributeNames, link, 'connectionId')
+
+ // TODO: remove this fake quiescing/reviving logic when the routers do the work
+ initConnState(n.connectionId)
+ if ($scope.quiesceState[n.connectionId].linkStates[l.identity])
+ l.adminStatus = $scope.quiesceState[n.connectionId].linkStates[l.identity];
+ if ($scope.quiesceState[n.connectionId].state == 'quiescing') {
+ if (l.adminStatus === 'enabled') {
+ // 25% chance of switching
+ var chance = Math.floor(Math.random() * 2);
+ if (chance == 1) {
+ l.adminStatus = 'disabled';
+ $scope.quiesceState[n.connectionId].linkStates[l.identity] = 'disabled';
+ }
+ }
+ }
+ if ($scope.quiesceState[n.connectionId].state == 'reviving') {
+ if (l.adminStatus === 'disabled') {
+ // 25% chance of switching
+ var chance = Math.floor(Math.random() * 2);
+ if (chance == 1) {
+ l.adminStatus = 'enabled';
+ $scope.quiesceState[n.connectionId].linkStates[l.identity] = 'enabled';
+ }
+ }
+ }
+ QDR.log.debug("pushing link state for " + l.owningAddr + " status: "+ l.adminStatus)
+
+
+ n.linkData.push(l)
+ }
+ })
+ $scope.multiData.push(n)
+ if (n.connectionId == $scope.connectionId)
+ $scope.linkData = n.linkData;
+ initConnState(n.connectionId)
+ $scope.multiDetails.updateState(n)
+ })
+ }
+ $scope.$apply();
+
+ d3.select('#multiple_details')
+ .style({
+ height: (normals.length + 1) * 30 + "px",
+ 'overflow-y': normals.length > 10 ? 'scroll' : 'hidden'
+ })
+ }
+
+ QDRService.addUpdatedAction("normalsStats", extendConnections)
+ extendConnections();
+ clearPopups();
+ var display = 'block'
+ var left = mouseX + $(document).scrollLeft()
+ if (d.normals.length === 1) {
+ display = 'none'
+ left = left - 30;
+ mouseY = mouseY - 20
+ }
+ d3.select('#multiple_details')
+ .style({
+ display: display,
+ opacity: 1,
+ left: (mouseX + $(document).scrollLeft()) + "px",
+ top: (mouseY + $(document).scrollTop()) + "px"})
+ if (d.normals.length === 1) {
+ // simulate a click on the connection to popup the link details
+ $scope.multiDetails.showLinksList( {entity: d} )
+ }
+ }
+ var stopUpdateConnectionsGrid = function () {
+ QDRService.delUpdatedAction("normalsStats");
+ }
+
+ var initConnState = function (id) {
+ if (!angular.isDefined($scope.quiesceState[id])) {
+ $scope.quiesceState[id] = {
+ state: 'enabled',
+ buttonText: 'Quiesce',
+ buttonDisabled: false,
+ linkStates: {}
+ }
+ }
+ }
+
function nextHop(thisNode, d) {
if ((thisNode) && (thisNode != d)) {
var target = findNextHopNode(thisNode, d);
@@ -1541,7 +1651,6 @@ var QDR = (function (QDR) {
d3.select("#svg_legend svg").remove();
animate = true;
initForceGraph();
- initGlobe(cities);
//if ($location.path().startsWith("/topology"))
// Core.notification('info', "Qpid dispatch router topology changed");
@@ -1609,29 +1718,31 @@ var QDR = (function (QDR) {
saveChanged();
QDRService.startUpdating();
- initGlobe(cities)//, "Boston", "Tel Aviv-Yafo"]);
-
function doAddDialog(NewRouterName) {
- var modalInstance = $uibModal.open({
- animation: true,
+ var d = $dialog.dialog({
+ dialogClass: "modal dlg-large",
+ backdrop: true,
+ keyboard: true,
+ backdropClick: true,
controller: 'QDR.NodeDialogController',
templateUrl: 'node-config-template.html',
- size: 'lg',
resolve: {
newname: function () {
return NewRouterName;
}
}
});
- modalInstance.result.then(function (result) {
+ d.open().then(function (result) {
if (result)
- setTimeout(doDownloadDialog, 100, result);
+ doDownloadDialog(result);
});
};
function doDownloadDialog(result) {
- var modalInstance = $uibModal.open({
- animation: true,
+ d = $dialog.dialog({
+ backdrop: true,
+ keyboard: true,
+ backdropClick: true,
controller: 'QDR.DownloadDialogController',
templateUrl: 'download-dialog-template.html',
resolve: {
@@ -1640,12 +1751,16 @@ var QDR = (function (QDR) {
}
}
});
+ d.open().then(function (result) {
+ //QDR.log.debug("download dialog done")
+ })
+ if (!$scope.$$phase) $scope.$apply()
};
}]);
- QDR.module.controller("QDR.NodeDialogController", function($scope, QDRService, $uibModalInstance, newname) {
+ QDR.module.controller("QDR.NodeDialogController", function($scope, QDRService, dialog, newname) {
var schema = QDRService.schema;
- var myEntities = ['container', 'router', 'log', 'listener' ];
+ var myEntities = ['router', 'log', 'listener' ];
var typeMap = {integer: 'number', string: 'text', path: 'text', boolean: 'boolean'};
var newLinks = $('path.temp').toArray(); // jquery array of new links for the added router
var nodeInfo = QDRService.topology.nodeInfo();
@@ -1793,7 +1908,7 @@ var QDR = (function (QDR) {
ediv.attributes.filter(function (attr) { return attr.name == 'port'})[0].value = ++maxPort;
// connectors from other routers need to connect to this addr:port
myPort = maxPort;
- myAddr = ediv.attributes.filter(function (attr) { return attr.name == 'addr'})[0].value
+ myAddr = ediv.attributes.filter(function (attr) { return attr.name == 'host'})[0].value
// override the role. 'normal' is the default, but we want inter-router
ediv.attributes.filter(function( attr ) { return attr.name == 'role'})[0].selected = 'inter-router';
@@ -1819,8 +1934,8 @@ var QDR = (function (QDR) {
var res = listener.results[i];
var role = QDRService.valFor(attrs, res, 'role');
if (role == 'inter-router') {
- ediv.attributes.filter(function( attr ) { return attr.name == 'addr'})[0].value =
- QDRService.valFor(attrs, res, 'addr')
+ ediv.attributes.filter(function( attr ) { return attr.name == 'host'})[0].value =
+ QDRService.valFor(attrs, res, 'host')
ediv.attributes.filter(function( attr ) { return attr.name == 'port'})[0].value =
QDRService.valFor(attrs, res, 'port')
break;
@@ -1829,7 +1944,7 @@ var QDR = (function (QDR) {
if (link.__data__.right) {
// connectors from other nodes need to connect to the new router's listener addr:port
ediv.attributes.filter(function (attr) { return attr.name == 'port'})[0].value = myPort;
- ediv.attributes.filter(function (attr) { return attr.name == 'addr'})[0].value = myAddr;
+ ediv.attributes.filter(function (attr) { return attr.name == 'host'})[0].value = myAddr;
separatedEntities.push(ediv)
}
@@ -1845,9 +1960,6 @@ var QDR = (function (QDR) {
})
- $scope.cancel = function () {
- $uibModalInstance.close()
- };
$scope.testPattern = function (attr) {
if (attr.rawtype == 'path')
return /^(\/)?([^/\0]+(\/)?)+$/;
@@ -1859,7 +1971,7 @@ var QDR = (function (QDR) {
$scope.attributeType = '';
$scope.attributeRequired = '';
$scope.attributeUnique = '';
- $scope.active = 'container'
+ $scope.active = 'router'
$scope.fieldsetDivs = "/fieldsetDivs.html"
$scope.setActive = function (tabName) {
$scope.active = tabName
@@ -1879,8 +1991,11 @@ var QDR = (function (QDR) {
// handle the download button click
// copy the dialog's values to the original node
$scope.download = function () {
- $uibModalInstance.close({entities: $scope.entities, annotations: annotations});
+ dialog.close({entities: $scope.entities, annotations: annotations});
}
+ $scope.cancel = function () {
+ dialog.close()
+ };
$scope.selectAnnotationTab = function (tabName) {
var tabs = $( "#tabs" ).tabs();
@@ -1902,8 +2017,7 @@ var QDR = (function (QDR) {
});
-QDR.module.controller("QDR.DownloadDialogController", function($scope, QDRService, $templateCache, $window, $uibModalInstance, results) {
-
+QDR.module.controller("QDR.DownloadDialogController", function($scope, QDRService, $templateCache, $window, dialog, results) {
var result = results.entities;
var annotations = results.annotations;
var annotationKeys = Object.keys(annotations);
@@ -2002,26 +2116,19 @@ QDR.module.controller("QDR.DownloadDialogController", function($scope, QDRServic
// handle the download button click
$scope.download = function () {
- var blob = new Blob([$scope.output], { type: 'text/plain' });
- var downloadLink = angular.element('<a></a>');
- downloadLink.attr('href', ($window.URL || $window.webkitURL).createObjectURL(blob));
- downloadLink.attr('download', $scope.newRouterName);
- downloadLink[0].click();
+ var output = $scope.output + "\n\n"
+ var blob = new Blob([output], { type: 'text/plain;charset=utf-16' });
+ saveAs(blob, $scope.newRouterName);
}
$scope.downloadPart = function (part) {
var linkName = part.link.__data__.source.name + 'additional.conf';
- var blob = new Blob([part.output], { type: 'text/plain' });
- var downloadLink = angular.element('<a></a>');
- downloadLink.attr('href', ($window.URL || $window.webkitURL).createObjectURL(blob));
- downloadLink.attr('download', linkName);
- downloadLink[0].click();
-
- QDR.log.debug(part);
+ var blob = new Blob([part.output], { type: 'text/plain;charset=utf-16' });
+ saveAs(blob, linkName);
}
$scope.done = function () {
- $uibModalInstance.close();
+ dialog.close();
}
});
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
[07/11] qpid-dispatch git commit: DISPATCH-316 Hawtio and stand-alone
consoles now use common code
Posted by ea...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/d98ae37e/console/hawtio/src/main/webapp/plugin/lib/rhea-min.js
----------------------------------------------------------------------
diff --git a/console/hawtio/src/main/webapp/plugin/lib/rhea-min.js b/console/hawtio/src/main/webapp/plugin/lib/rhea-min.js
deleted file mode 100644
index 4841569..0000000
--- a/console/hawtio/src/main/webapp/plugin/lib/rhea-min.js
+++ /dev/null
@@ -1,7 +0,0 @@
-require=function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}({1:[function(require,module,exports){(function(process,Buffer){"use strict";var frames=require("./frames.js");var log=require("./log.js");var sasl=require("./sasl.js");var types=require("./types.js");var util=require("./util.js");var EndpointState=require("./endpoint.js");var Session=require("./session.js");var Transport=require("./transport.js");var net=require("net");var tls=require("tls");var EventEmitter=require("events").EventEmitter;var AMQP_PROTOCOL_ID=0;var TLS_PROTOCOL_ID=2;function ConnectionError(message,condition,connection){Error
.call(this);Error.captureStackTrace(this,this.constructor);this.message=message;this.condition=condition;this.description=message;this.connection=connection}require("util").inherits(ConnectionError,Error);function get_socket_id(socket){if(socket.get_id_string)return socket.get_id_string();return socket.localAddress+":"+socket.localPort+" -> "+socket.remoteAddress+":"+socket.remotePort}function session_per_connection(conn){var ssn=null;return{get_session:function(){if(!ssn){ssn=conn.create_session();ssn.begin()}return ssn}}}function restrict(count,f){if(count){var current=count;var reset;return function(successful_attempts){if(reset!==successful_attempts){current=count;reset=successful_attempts}if(current--)return f(successful_attempts);else return-1}}else{return f}}function backoff(initial,max){var delay=initial;var reset;return function(successful_attempts){if(reset!==successful_attempts){delay=initial;reset=successful_attempts}var current=delay;var next=delay*2;delay=max>next?next
:max;return current}}function get_connect_fn(options){if(options.transport===undefined||options.transport==="tcp"){return net.connect}else if(options.transport==="tls"||options.transport==="ssl"){return tls.connect}else{throw Error("Unrecognised transport: "+options.transport)}}function connection_details(options){var details={};details.connect=options.connect?options.connect:get_connect_fn(options);details.host=options.host?options.host:"localhost";details.port=options.port?options.port:5672;details.options=options;return details}var aliases=["container_id","hostname","max_frame_size","channel_max","idle_time_out","outgoing_locales","incoming_locales","offered_capabilities","desired_capabilities","properties"];function remote_property_shortcut(name){return function(){return this.remote.open?this.remote.open[name]:undefined}}var conn_counter=1;var Connection=function(options,container){this.options={};if(options){for(var k in options){this.options[k]=options[k]}}this.container=conta
iner;if(!this.options.id){this.options.id="connection-"+conn_counter++}if(!this.options.container_id){this.options.container_id=container?container.id:util.generate_uuid()}if(!this.options.connection_details){var self=this;this.options.connection_details=function(){return connection_details(self.options)}}var reconnect=this.get_option("reconnect",true);if(typeof reconnect==="boolean"&&reconnect){var initial=this.get_option("initial_reconnect_delay",100);var max=this.get_option("max_reconnect_delay",6e4);this.options.reconnect=restrict(this.get_option("reconnect_limit"),backoff(initial,max))}else if(typeof reconnect==="number"){var fixed=this.options.reconnect;this.options.reconnect=restrict(this.get_option("reconnect_limit"),function(){return fixed})}this.registered=false;this.state=new EndpointState;this.local_channel_map={};this.remote_channel_map={};this.local={};this.remote={};this.local.open=frames.open(this.options);this.local.close=frames.close({});this.session_policy=session
_per_connection(this);this.amqp_transport=new Transport(this.options.id,AMQP_PROTOCOL_ID,frames.TYPE_AMQP,this);this.sasl_transport=undefined;this.transport=this.amqp_transport;this.conn_established_counter=0;this.heartbeat_out=undefined;this.heartbeat_in=undefined;this.abort_idle=false;this.socket_ready=false;this.scheduled_reconnect=undefined;this.default_sender=undefined;for(var i in aliases){var f=aliases[i];Object.defineProperty(this,f,{get:remote_property_shortcut(f)})}Object.defineProperty(this,"error",{get:function(){return this.remote.close?this.remote.close.error:undefined}})};Connection.prototype=Object.create(EventEmitter.prototype);Connection.prototype.constructor=Connection;Connection.prototype.dispatch=function(name,context){log.events("Connection got event: "+name);if(this.listeners(name).length){EventEmitter.prototype.emit.apply(this,arguments);return true}else if(this.container){return this.container.dispatch.apply(this.container,arguments)}};Connection.prototype.r
eset=function(){if(this.abort_idle){this.abort_idle=false;this.local.close.error=undefined;this.state=new EndpointState;this.state.open()}this.amqp_transport=new Transport(this.options.id,AMQP_PROTOCOL_ID,frames.TYPE_AMQP,this);this.sasl_transport=undefined;this.transport=this.amqp_transport;this.state.disconnected();this.remote={};this.remote_channel_map={};for(var k in this.local_channel_map){this.local_channel_map[k].reset()}this.socket_ready=false};Connection.prototype.connect=function(){this.is_server=false;this._connect(this.options.connection_details(this.conn_established_counter));this.open();return this};Connection.prototype.reconnect=function(){this.scheduled_reconnect=undefined;log.reconnect("reconnecting...");this.reset();this._connect(this.options.connection_details(this.conn_established_counter));process.nextTick(this._process.bind(this));return this};Connection.prototype._connect=function(details){if(details.connect){this.init(details.connect(details.port,details.host
,details.options,this.connected.bind(this)))}else{this.init(get_connect_fn(details)(details.port,details.host,details.options,this.connected.bind(this)))}return this};Connection.prototype.accept=function(socket){this.is_server=true;log.io("["+this.id+"] client accepted: "+get_socket_id(socket));this.socket_ready=true;return this.init(socket)};Connection.prototype.init=function(socket){this.socket=socket;this.socket.on("data",this.input.bind(this));this.socket.on("error",this.on_error.bind(this));this.socket.on("end",this.eof.bind(this));if(this.is_server){var mechs;if(this.container&&Object.getOwnPropertyNames(this.container.sasl_server_mechanisms).length){mechs=this.container.sasl_server_mechanisms}if(this.socket.encrypted&&this.socket.authorized&&this.get_option("enable_sasl_external",false)){mechs=sasl.server_add_external(mechs?util.clone(mechs):{})}if(mechs){this.sasl_transport=new sasl.Server(this,mechs)}}else{var mechanisms=this.get_option("sasl_mechanisms");if(!mechanisms){va
r username=this.get_option("username");var password=this.get_option("password");if(username){mechanisms=sasl.client_mechanisms();if(password)mechanisms.enable_plain(username,password);else mechanisms.enable_anonymous(username)}}if(this.socket.encrypted&&this.options.cert&&this.get_option("enable_sasl_external",false)){if(!mechanisms)mechanisms=sasl.client_mechanisms();mechanisms.enable_external()}if(mechanisms){this.sasl_transport=new sasl.Client(this,mechanisms)}}this.transport=this.sasl_transport?this.sasl_transport:this.amqp_transport;return this};Connection.prototype.attach_sender=function(options){return this.session_policy.get_session().attach_sender(options)};Connection.prototype.open_sender=Connection.prototype.attach_sender;Connection.prototype.attach_receiver=function(options){return this.session_policy.get_session().attach_receiver(options)};Connection.prototype.open_receiver=Connection.prototype.attach_receiver;Connection.prototype.get_option=function(name,default_value)
{if(this.options[name]!==undefined)return this.options[name];else if(this.container)return this.container.get_option(name,default_value);else return default_value};Connection.prototype.send=function(msg){if(this.default_sender===undefined){this.default_sender=this.open_sender({target:{}})}return this.default_sender.send(msg)};Connection.prototype.connected=function(){this.socket_ready=true;this.conn_established_counter++;log.io("["+this.options.id+"] connected "+get_socket_id(this.socket));this.output()};Connection.prototype.sasl_failed=function(text){this.transport_error={condition:"amqp:unauthorized-access",description:text};this._handle_error()};Connection.prototype._handle_error=function(){var error=this.get_error();if(error){var handled=this.dispatch("connection_error",this._context());handled=this.dispatch("connection_close",this._context())||handled;if(!handled){EventEmitter.prototype.emit.call(this.container,"error",new ConnectionError(error.description,error.condition,this)
)}return true}else{return false}};Connection.prototype.get_error=function(){if(this.transport_error)return this.transport_error;if(this.remote.close&&this.remote.close.error)return this.remote.close.error;return undefined};Connection.prototype.output=function(){if(this.socket&&this.socket_ready){if(this.heartbeat_out)clearTimeout(this.heartbeat_out);this.transport.write(this.socket);if((this.is_closed()&&this.state.has_settled()||this.abort_idle||this.transport_error)&&!this.transport.has_writes_pending()){this.socket.end()}else if(this.is_open()&&this.remote.open.idle_time_out){this.heartbeat_out=setTimeout(this._write_frame.bind(this),this.remote.open.idle_time_out/2)}}};Connection.prototype.input=function(buff){if(this.heartbeat_in)clearTimeout(this.heartbeat_in);log.io("["+this.options.id+"] read "+buff.length+" bytes");var buffer;if(this.previous_input){buffer=Buffer.concat([this.previous_input,buff],this.previous_input.length+buff.length);this.previous_input=null}else{buffer=b
uff}var read=this.transport.read(buffer,this);if(read<buffer.length){this.previous_input=buffer.slice(read)}if(this.local.open.idle_time_out)this.heartbeat_in=setTimeout(this.idle.bind(this),this.local.open.idle_time_out);if(this.transport.has_writes_pending()){this.output()}else if(this.is_closed()&&this.state.has_settled()){this.socket.end()}else if(this.is_open()&&this.remote.open.idle_time_out&&!this.heartbeat_out){this.heartbeat_out=setTimeout(this._write_frame.bind(this),this.remote.open.idle_time_out/2)}};Connection.prototype.idle=function(){if(this.is_open()){this.abort_idle=true;this.local.close.error={condition:"amqp:resource-limit-exceeded",description:"max idle time exceeded"};this.close()}};Connection.prototype.on_error=function(e){console.log("["+this.options.id+"] error: "+e);this._disconnected()};Connection.prototype.eof=function(e){this._disconnected()};Connection.prototype._disconnected=function(){if(this.heartbeat_out)clearTimeout(this.heartbeat_out);if(this.heart
beat_in)clearTimeout(this.heartbeat_in);if(!this.is_closed()&&this.scheduled_reconnect==undefined){if(!this.dispatch("disconnected",this._context())){console.log("["+this.options.id+"] disconnected")}if(!this.is_server&&!this.transport_error&&this.options.reconnect){var delay=this.options.reconnect(this.conn_established_counter);if(delay>=0){log.reconnect("Scheduled reconnect in "+delay+"ms");this.scheduled_reconnect=setTimeout(this.reconnect.bind(this),delay)}}}};Connection.prototype.open=function(){if(this.state.open()){this._register()}};Connection.prototype.close=function(error){if(error)this.local.close.error=error;if(this.state.close()){this._register()}};Connection.prototype.is_open=function(){return this.state.is_open()};Connection.prototype.is_closed=function(){return this.state.is_closed()};Connection.prototype.create_session=function(){var i=0;while(this.local_channel_map[i])i++;var session=new Session(this,i);this.local_channel_map[i]=session;return session};Connection.p
rototype.on_open=function(frame){if(this.state.remote_opened()){this.remote.open=frame.performative;this.open();this.dispatch("connection_open",this._context())}else{throw Error("Open already received")}};Connection.prototype.on_close=function(frame){if(this.state.remote_closed()){this.remote.close=frame.performative;this.close();if(this.remote.close.error){this._handle_error()}else{this.dispatch("connection_close",this._context())}if(this.heartbeat_out)clearTimeout(this.heartbeat_out)}else{throw Error("Close already received")}};Connection.prototype._register=function(){if(!this.registered){this.registered=true;process.nextTick(this._process.bind(this))}};Connection.prototype._process=function(){this.registered=false;do{if(this.state.need_open()){this._write_open()}for(var k in this.local_channel_map){this.local_channel_map[k]._process()}if(this.state.need_close()){this._write_close()}}while(!this.state.has_settled())};Connection.prototype._write_frame=function(channel,frame,payloa
d){this.amqp_transport.encode(frames.amqp_frame(channel,frame,payload));this.output()};Connection.prototype._write_open=function(){this._write_frame(0,this.local.open.described())};Connection.prototype._write_close=function(){this._write_frame(0,this.local.close.described())};Connection.prototype.on_begin=function(frame){var session;if(frame.performative.remote_channel===null||frame.performative.remote_channel===undefined){session=this.create_session();session.local.begin.remote_channel=frame.channel}else{session=this.local_channel_map[frame.performative.remote_channel];if(!session)throw Error("Invalid value for remote channel "+frame.performative.remote_channel)}session.on_begin(frame);this.remote_channel_map[frame.channel]=session};Connection.prototype.get_peer_certificate=function(){if(this.socket&&this.socket.getPeerCertificate){return this.socket.getPeerCertificate()}else{return undefined}};Connection.prototype.get_tls_socket=function(){if(this.socket&&(this.options.transport==
="tls"||this.options.transport==="ssl")){return this.socket}else{return undefined}};Connection.prototype._context=function(c){var context=c?c:{};context.connection=this;if(this.container)context.container=this.container;return context};function delegate_to_session(name){Connection.prototype["on_"+name]=function(frame){var session=this.remote_channel_map[frame.channel];if(!session){throw Error(name+" received on invalid channel "+frame.channel)}session["on_"+name](frame)}}delegate_to_session("end");delegate_to_session("attach");delegate_to_session("detach");delegate_to_session("transfer");delegate_to_session("disposition");delegate_to_session("flow");module.exports=Connection}).call(this,require("_process"),require("buffer").Buffer)},{"./endpoint.js":2,"./frames.js":3,"./log.js":5,"./sasl.js":8,"./session.js":9,"./transport.js":11,"./types.js":12,"./util.js":13,_process:25,buffer:19,events:23,net:18,tls:18,util:33}],2:[function(require,module,exports){"use strict";var EndpointState=f
unction(){this.init()};EndpointState.prototype.init=function(){this.local_open=false;this.remote_open=false;this.open_requests=0;this.close_requests=0;this.initialised=false};EndpointState.prototype.open=function(){this.initialised=true;if(!this.local_open){this.local_open=true;this.open_requests++;return true}else{return false}};EndpointState.prototype.close=function(){if(this.local_open){this.local_open=false;this.close_requests++;return true}else{return false}};EndpointState.prototype.disconnected=function(){var was_open=this.local_open;this.init();if(was_open){this.open()}else{this.close()}};EndpointState.prototype.remote_opened=function(frame){if(!this.remote_open){this.remote_open=true;return true}else{return false}};EndpointState.prototype.remote_closed=function(frame){if(this.remote_open){this.remote_open=false;return true}else{return false}};EndpointState.prototype.is_open=function(){return this.local_open&&this.remote_open};EndpointState.prototype.is_closed=function(){retu
rn this.initialised&&!this.local_open&&!this.remote_open};EndpointState.prototype.has_settled=function(){return this.open_requests==0&&this.close_requests==0};EndpointState.prototype.need_open=function(){if(this.open_requests>0){this.open_requests--;return true}else{return false}};EndpointState.prototype.need_close=function(){if(this.close_requests>0){this.close_requests--;return true}else{return false}};module.exports=EndpointState},{}],3:[function(require,module,exports){"use strict";var types=require("./types.js");var frames={};var by_descriptor={};frames.read_header=function(buffer){var offset=4;var header={};var name=buffer.toString("ascii",0,offset);if(name!=="AMQP"){throw Error("Invalid protocol header for AMQP "+name)}header.protocol_id=buffer.readUInt8(offset++);header.major=buffer.readUInt8(offset++);header.minor=buffer.readUInt8(offset++);header.revision=buffer.readUInt8(offset++);if(header.major!==1||header.minor!==0){throw Error("Unsupported AMQP version: "+JSON.stringi
fy(header))}return header};frames.write_header=function(buffer,header){var offset=4;buffer.write("AMQP",0,offset,"ascii");buffer.writeUInt8(header.protocol_id,offset++);buffer.writeUInt8(header.major,offset++);buffer.writeUInt8(header.minor,offset++);buffer.writeUInt8(header.revision,offset++);return 8};frames.TYPE_AMQP=0;frames.TYPE_SASL=1;frames.read_frame=function(buffer){var reader=new types.Reader(buffer);var frame={};frame.size=reader.read_uint(4);if(reader.remaining<frame.size){return null}var doff=reader.read_uint(1);if(doff<2){throw Error("Invalid data offset, must be at least 2 was "+doff)}frame.type=reader.read_uint(1);if(frame.type===frames.TYPE_AMQP){frame.channel=reader.read_uint(2)}else if(frame.type===frames.TYPE_SASL){reader.skip(2)}else{throw Error("Unknown frame type "+frame.type)}if(doff>1){reader.skip(doff*4-8)}if(reader.remaining()){frame.performative=reader.read();var c=by_descriptor[frame.performative.descriptor.value];if(c){frame.performative=new c(frame.per
formative.value)}if(reader.remaining()){frame.payload=reader.read_bytes(reader.remaining())}}return frame};frames.write_frame=function(frame){var writer=new types.Writer;writer.skip(4);writer.write_uint(2,1);writer.write_uint(frame.type,1);if(frame.type===frames.TYPE_AMQP){writer.write_uint(frame.channel,2)}else if(frame.type===frames.TYPE_SASL){writer.write_uint(0,2)}else{throw Error("Unknown frame type "+frame.type)}if(frame.performative){writer.write(frame.performative);if(frame.payload){writer.write_bytes(frame.payload)}}var buffer=writer.toBuffer();buffer.writeUInt32BE(buffer.length,0);return buffer};frames.amqp_frame=function(channel,performative,payload){return{channel:channel||0,type:frames.TYPE_AMQP,performative:performative,payload:payload}};frames.sasl_frame=function(performative){return{channel:0,type:frames.TYPE_SASL,performative:performative}};function define_frame(type,def){var c=types.define_composite(def);frames[def.name]=c.create;by_descriptor[Number(c.descriptor.n
umeric).toString(10)]=c;by_descriptor[c.descriptor.symbolic]=c}var open={name:"open",code:16,fields:[{name:"container_id",type:"string",mandatory:true},{name:"hostname",type:"string"},{name:"max_frame_size",type:"uint",default_value:4294967295},{name:"channel_max",type:"ushort",default_value:65535},{name:"idle_time_out",type:"uint"},{name:"outgoing_locales",type:"symbol",multiple:true},{name:"incoming_locales",type:"symbol",multiple:true},{name:"offered_capabilities",type:"symbol",multiple:true},{name:"desired_capabilities",type:"symbol",multiple:true},{name:"properties",type:"symbolic_map"}]};var begin={name:"begin",code:17,fields:[{name:"remote_channel",type:"ushort"},{name:"next_outgoing_id",type:"uint",mandatory:true},{name:"incoming_window",type:"uint",mandatory:true},{name:"outgoing_window",type:"uint",mandatory:true},{name:"handle_max",type:"uint",default_value:"4294967295"},{name:"offered_capabilities",type:"symbol",multiple:true},{name:"desired_capabilities",type:"symbol",m
ultiple:true},{name:"properties",type:"symbolic_map"}]};var attach={name:"attach",code:18,fields:[{name:"name",type:"string",mandatory:true},{name:"handle",type:"uint",mandatory:true},{name:"role",type:"boolean",mandatory:true},{name:"snd_settle_mode",type:"ubyte",default_value:2},{name:"rcv_settle_mode",type:"ubyte",default_value:0},{name:"source",type:"*"},{name:"target",type:"*"},{name:"unsettled",type:"map"},{name:"incomplete_unsettled",type:"boolean",default_value:false},{name:"initial_delivery_count",type:"uint"},{name:"max_message_size",type:"ulong"},{name:"offered_capabilities",type:"symbol",multiple:true},{name:"desired_capabilities",type:"symbol",multiple:true},{name:"properties",type:"symbolic_map"}]};var flow={name:"flow",code:19,fields:[{name:"next_incoming_id",type:"uint"},{name:"incoming_window",type:"uint",mandatory:true},{name:"next_outgoing_id",type:"uint",mandatory:true},{name:"outgoing_window",type:"uint",mandatory:true},{name:"handle",type:"uint"},{name:"deliver
y_count",type:"uint"},{name:"link_credit",type:"uint"},{name:"available",type:"uint"},{name:"drain",type:"boolean",default_value:false},{name:"echo",type:"boolean",default_value:false},{name:"properties",type:"symbolic_map"}]};var transfer={name:"transfer",code:20,fields:[{name:"handle",type:"uint",mandatory:true},{name:"delivery_id",type:"uint"},{name:"delivery_tag",type:"binary"},{name:"message_format",type:"uint"},{name:"settled",type:"boolean"},{name:"more",type:"boolean",default_value:false},{name:"rcv_settle_mode",type:"ubyte"},{name:"state",type:"delivery_state"},{name:"resume",type:"boolean",default_value:false},{name:"aborted",type:"boolean",default_value:false},{name:"batchable",type:"boolean",default_value:false}]};var disposition={name:"disposition",code:21,fields:[{name:"role",type:"boolean",mandatory:true},{name:"first",type:"uint",mandatory:true},{name:"last",type:"uint"},{name:"settled",type:"boolean",default_value:false},{name:"state",type:"*"},{name:"batchable",typ
e:"boolean",default_value:false}]};var detach={name:"detach",code:22,fields:[{name:"handle",type:"uint",mandatory:true},{name:"closed",type:"boolean",default_value:false},{name:"error",type:"error"}]};var end={name:"end",code:23,fields:[{name:"error",type:"error"}]};var close={name:"close",code:24,fields:[{name:"error",type:"error"}]};define_frame(frames.TYPE_AMQP,open);define_frame(frames.TYPE_AMQP,begin);define_frame(frames.TYPE_AMQP,attach);define_frame(frames.TYPE_AMQP,flow);define_frame(frames.TYPE_AMQP,transfer);define_frame(frames.TYPE_AMQP,disposition);define_frame(frames.TYPE_AMQP,detach);define_frame(frames.TYPE_AMQP,end);define_frame(frames.TYPE_AMQP,close);var sasl_mechanisms={name:"sasl_mechanisms",code:64,fields:[{name:"sasl_server_mechanisms",type:"symbol",multiple:true,mandatory:true}]};var sasl_init={name:"sasl_init",code:65,fields:[{name:"mechanism",type:"symbol",mandatory:true},{name:"initial_response",type:"binary"},{name:"hostname",type:"string"}]};var sasl_chal
lenge={name:"sasl_challenge",code:66,fields:[{name:"challenge",type:"binary",mandatory:true}]};var sasl_response={name:"sasl_response",code:67,fields:[{name:"response",type:"binary",mandatory:true}]};var sasl_outcome={name:"sasl_outcome",code:68,fields:[{name:"code",type:"ubyte",mandatory:true},{name:"additional_data",type:"binary"}]};define_frame(frames.TYPE_SASL,sasl_mechanisms);define_frame(frames.TYPE_SASL,sasl_init);define_frame(frames.TYPE_SASL,sasl_challenge);define_frame(frames.TYPE_SASL,sasl_response);define_frame(frames.TYPE_SASL,sasl_outcome);module.exports=frames},{"./types.js":12}],4:[function(require,module,exports){(function(Buffer){"use strict";var frames=require("./frames.js");var log=require("./log.js");var message=require("./message.js");var terminus=require("./terminus.js");var types=require("./types.js");var EndpointState=require("./endpoint.js");var FlowController=function(window){this.window=window};FlowController.prototype.update=function(context){var delta=t
his.window-context.receiver.credit;context.receiver.flow(delta)};function auto_settle(context){context.delivery.settled=true}function auto_accept(context){context.delivery.update(undefined,message.accepted().described())}function LinkError(message,condition,link){Error.call(this);Error.captureStackTrace(this,this.constructor);this.message=message;this.condition=condition;this.description=message;this.link=link}require("util").inherits(LinkError,Error);var EventEmitter=require("events").EventEmitter;var link=Object.create(EventEmitter.prototype);link.dispatch=function(name,context){log.events("Link got event: "+name);EventEmitter.prototype.emit.apply(this.observers,arguments);if(this.listeners(name).length){EventEmitter.prototype.emit.apply(this,arguments);return true}else{return this.session.dispatch.apply(this.session,arguments)}};link.set_source=function(fields){this.local.attach.source=terminus.source(fields).described()};link.set_target=function(fields){this.local.attach.target=
terminus.target(fields).described()};link.attach=function(){if(this.state.open()){this.connection._register()}};link.open=link.attach;link.detach=function(){this.local.detach.closed=false;if(this.state.close()){this.connection._register()}};link.close=function(error){if(error)this.local.detach.error=error;this.local.detach.closed=true;if(this.state.close()){this.connection._register()}};link.is_open=function(){return this.session.is_open()&&this.state.is_open()};link.is_closed=function(){return this.session.is_closed()||this.state.is_closed()};link._process=function(){do{if(this.state.need_open()){this.session.output(this.local.attach.described())}if(this.issue_flow){this.session._write_flow(this);this.issue_flow=false}if(this.state.need_close()){this.session.output(this.local.detach.described())}}while(!this.state.has_settled())};link.on_attach=function(frame){if(this.state.remote_opened()){if(!this.remote.handle){this.remote.handle=frame.handle}frame.performative.source=terminus.u
nwrap(frame.performative.source);frame.performative.target=terminus.unwrap(frame.performative.target);this.remote.attach=frame.performative;this.open();this.dispatch(this.is_receiver()?"receiver_open":"sender_open",this._context())}else{throw Error("Attach already received")}};link.prefix_event=function(event){return(this.local.attach.role?"receiver_":"sender_")+event};link.on_detach=function(frame){if(this.state.remote_closed()){this.remote.detach=frame.performative;this.close();var error=this.remote.detach.error;if(error){var handled=this.dispatch(this.prefix_event("error"),this._context());handled=this.dispatch(this.prefix_event("close"),this._context())||handled;if(!handled){EventEmitter.prototype.emit.call(this.connection.container,"error",new LinkError(error.description,error.condition,this))}}else{this.dispatch(this.prefix_event("close"),this._context())}}else{throw Error("Detach already received")}};function is_internal(name){switch(name){case"name":case"handle":case"role":c
ase"initial_delivery_count":return true;default:return false}}var aliases=["snd_settle_mode","rcv_settle_mode","source","target","max_message_size","offered_capabilities","desired_capabilities","properties"];function remote_property_shortcut(name){return function(){return this.remote.attach?this.remote.attach[name]:undefined}}link.init=function(session,name,local_handle,opts,is_receiver){this.session=session;this.connection=session.connection;this.name=name;this.options=opts===undefined?{}:opts;this.state=new EndpointState;this.issue_flow=false;this.local={handle:local_handle};this.local.attach=frames.attach({handle:local_handle,name:name,role:is_receiver});for(var f in this.local.attach){if(!is_internal(f)&&this.options[f]!==undefined){this.local.attach[f]=this.options[f]}}this.local.detach=frames.detach({handle:local_handle,closed:true});this.remote={handle:undefined};this.delivery_count=0;this.credit=0;this.observers=new EventEmitter;for(var i in aliases){var f=aliases[i];Object.
defineProperty(this,f,{get:remote_property_shortcut(f)})}Object.defineProperty(this,"error",{get:function(){return this.remote.detach?this.remote.detach.error:undefined}})};link.reset=function(){this.state.disconnected();this.remote={handle:undefined};this.delivery_count=0;this.credit=0};link.has_credit=function(){return this.credit>0};link.is_receiver=function(){return this.local.attach.role};link._context=function(c){var context=c?c:{};if(this.is_receiver()){context.receiver=this}else{context.sender=this}return this.session._context(context)};link.get_option=function(name,default_value){if(this.options[name]!==undefined)return this.options[name];else return this.session.get_option(name,default_value)};var Sender=function(session,name,local_handle,opts){this.init(session,name,local_handle,opts,false);this._draining=false;this._drained=false;this.local.attach.initial_delivery_count=0;this.tag=0;if(this.get_option("autosettle",true)){this.observers.on("settled",auto_settle)}var sende
r=this;if(this.get_option("treat_modified_as_released",true)){this.observers.on("modified",function(context){sender.dispatch("released",context)})}};Sender.prototype=Object.create(link);Sender.prototype.constructor=Sender;Sender.prototype._get_drain=function(){if(this._draining&&this._drained&&this.credit){while(this.credit){++this.delivery_count;--this.credit}return true}else{return false}};Sender.prototype.set_drained=function(drained){this._drained=drained;if(this._draining&&this._drained){this.issue_flow=true}};Sender.prototype.next_tag=function(){return new Buffer(new String((this.tag++)))};Sender.prototype.sendable=function(frame){return this.credit&&this.session.outgoing.available()};Sender.prototype.on_flow=function(frame){var flow=frame.performative;this.credit=flow.delivery_count+flow.link_credit-this.delivery_count;this._draining=flow.drain;this._drained=this.credit>0;if(this.is_open()){this.dispatch("sender_flow",this._context());if(this._draining){this.dispatch("sender_
draining",this._context())}if(this.sendable()){this.dispatch("sendable",this._context())}}};Sender.prototype.on_transfer=function(frame){throw Error("got transfer on sending link")};Sender.prototype.send=function(msg,tag){var delivery=this.session.send(this,tag?tag:this.next_tag(),message.encode(msg),0);if(this.local.attach.snd_settle_mode===1){delivery.settled=true}return delivery};var Receiver=function(session,name,local_handle,opts){this.init(session,name,local_handle,opts,true);this.drain=false;this.set_credit_window(this.get_option("credit_window",100));if(this.get_option("autoaccept",true)){this.observers.on("message",auto_accept)}};Receiver.prototype=Object.create(link);Receiver.prototype.constructor=Receiver;Receiver.prototype.on_flow=function(frame){this.dispatch("receiver_flow",this._context());if(frame.performative.drain){if(frame.performative.link_credit>0)console.log("ERROR: received flow with drain set, but non zero credit");else this.dispatch("receiver_drained",this._
context())}};Receiver.prototype.flow=function(credit){if(credit>0){this.credit+=credit;this.issue_flow=true;this.connection._register()}};Receiver.prototype.add_credit=Receiver.prototype.flow;Receiver.prototype._get_drain=function(){return this.drain};Receiver.prototype.set_credit_window=function(credit_window){if(credit_window>0){var flow_controller=new FlowController(credit_window);var listener=flow_controller.update.bind(flow_controller);this.observers.on("message",listener);this.observers.on("receiver_open",listener)}};module.exports={Sender:Sender,Receiver:Receiver}}).call(this,require("buffer").Buffer)},{"./endpoint.js":2,"./frames.js":3,"./log.js":5,"./message.js":6,"./terminus.js":10,"./types.js":12,buffer:19,events:23,util:33}],5:[function(require,module,exports){"use strict";var debug=require("debug");module.exports={frames:debug("rhea:frames"),raw:debug("rhea:raw"),reconnect:debug("rhea:reconnect"),events:debug("rhea:events"),message:debug("rhea:message"),flow:debug("rhea
:flow"),io:debug("rhea:io")}},{debug:15}],6:[function(require,module,exports){"use strict";var log=require("./log.js");
-var types=require("./types.js");var by_descriptor={};var unwrappers={};var wrappers=[];var message={};function define_section(descriptor,unwrap,wrap){unwrap.descriptor=descriptor;unwrappers[descriptor.symbolic]=unwrap;unwrappers[Number(descriptor.numeric).toString(10)]=unwrap;if(wrap){wrappers.push(wrap)}}function define_composite_section(def){var c=types.define_composite(def);message[def.name]=c.create;by_descriptor[Number(c.descriptor.numeric).toString(10)]=c;by_descriptor[c.descriptor.symbolic]=c;var unwrap=function(msg,section){msg[def.name]=new c(section.value)};var wrap=function(sections,msg){if(msg[def.name]){if(msg[def.name].described){sections.push(msg[def.name].described())}else{sections.push(c.create(msg[def.name]).described())}}};define_section(c.descriptor,unwrap,wrap)}function define_map_section(def){var descriptor={numeric:def.code};descriptor.symbolic="amqp:"+def.name.replace(/_/g,"-")+":map";var unwrap=function(msg,section){msg[def.name]=types.unwrap(section)};var w
rap=function(sections,msg){if(msg[def.name]){sections.push(types.described(types.wrap_ulong(descriptor.numeric),types.wrap_map(msg[def.name])))}};define_section(descriptor,unwrap,wrap)}define_composite_section({name:"header",code:112,fields:[{name:"durable",type:"boolean",default_value:false},{name:"priority",type:"ubyte",default_value:4},{name:"ttl",type:"uint"},{name:"first_acquirer",type:"boolean",default_value:false},{name:"delivery_count",type:"uint",default_value:0}]});define_map_section({name:"delivery_annotations",code:113});define_map_section({name:"message_annotations",code:114});define_composite_section({name:"properties",code:115,fields:[{name:"message_id",type:"message_id"},{name:"user_id",type:"binary"},{name:"to",type:"string"},{name:"subject",type:"string"},{name:"reply_to",type:"string"},{name:"correlation_id",type:"message_id"},{name:"content_type",type:"symbol"},{name:"content_encoding",type:"symbol"},{name:"absolute_expiry_time",type:"timestamp"},{name:"creation_
time",type:"timestamp"},{name:"group_id",type:"string"},{name:"group_sequence",type:"uint"},{name:"reply_to_group_id",type:"string"}]});define_map_section({name:"application_properties",code:116});define_section({numeric:119,symbolic:"amqp:value:*"},function(msg,section){msg.body=types.unwrap(section)},function(sections,msg){sections.push(types.described(types.wrap_ulong(119),types.wrap(msg.body)))});define_map_section({name:"footer",code:120});function reverse_lookup(map){var reversed={};for(var key in map){var values=map[key];for(var i in values){reversed[values[i]]=key}}return reversed}var special_sections={properties:["message_id","user_id","to","subject","reply_to","correlation_id","content_type","content_encoding","absolute_expiry_time","creation_time","group_id","group_sequence","reply_to_group_id"],header:["durable","priority","ttl","first_acquirer","delivery_count"]};var special_fields=reverse_lookup(special_sections);var section_names=["header","delivery_annotations","mess
age_annotations","properties","application_properties","body","footer"];function copy(src,tgt){for(var k in src){var v=src[k];if(typeof v==="object"){copy(v,tgt[k])}else{tgt[k]=v}}}function add_property_shortcut(o,group,name){Object.defineProperty(o,name,{get:function(){return this[group]?this[group][name]:undefined},set:function(v){if(this[group]===undefined){this[group]={}}this[group][name]=v}})}function create_message(m){var msg={toJSON:function(){var o={};for(var i in section_names){var key=section_names[i];if(typeof this[key]==="function")continue;var fields=special_sections[key];if(fields){for(var j in fields){if(this[fields[j]]!==undefined){if(o[key]===undefined)o[key]={};o[key][fields[j]]=this[fields[j]]}}}else if(this[key]){o[key]=this[key]}}return o},inspect:function(){return JSON.stringify(this.toJSON())},toString:function(){return JSON.stringify(this.toJSON())}};for(var field in special_fields){add_property_shortcut(msg,special_fields[field],field)}if(m)copy(m,msg);retur
n msg}function massage(msg){var out=undefined;for(var key in msg){if(typeof msg[key]!=="function"&§ion_names.indexOf(key)<0){if(out===undefined)out={};var group=special_fields[key]||"application_properties";if(out[group]===undefined){out[group]={}}out[group][key]=msg[key]}else{if(out!==undefined){out[key]=msg[key]}}}return out||msg}message.encode=function(obj){var sections=[];var msg=massage(obj);wrappers.forEach(function(wrapper_fn){wrapper_fn(sections,msg)});var writer=new types.Writer;for(var i=0;i<sections.length;i++){log.message("Encoding section "+(i+1)+" of "+sections.length+": "+sections[i]);writer.write(sections[i])}var data=writer.toBuffer();log.message("encoded "+data.length+" bytes");return data};message.decode=function(buffer){var msg=create_message();var reader=new types.Reader(buffer);while(reader.remaining()){var s=reader.read();log.message("decoding section: "+JSON.stringify(s)+" of type: "+JSON.stringify(s.descriptor));if(s.descriptor){var unwrap=unwrappers[s.d
escriptor.value];if(unwrap){unwrap(msg,s)}else{console.log("WARNING: did not recognise message section with descriptor "+s.descriptor)}}else{console.log("WARNING: expected described message section got "+JSON.stringify(s))}}if(msg.application_properties){for(var key in msg.application_properties){add_property_shortcut(msg,"application_properties",key)}}return msg};var outcomes={};function define_outcome(def){var c=types.define_composite(def);c.composite_type=def.name;message[def.name]=c.create;outcomes[Number(c.descriptor.numeric).toString(10)]=c;outcomes[c.descriptor.symbolic]=c;message["is_"+def.name]=function(o){if(o&&o.descriptor){var c=outcomes[o.descriptor.value];if(c){return c.descriptor.numeric==def.code}}return false}}message.unwrap_outcome=function(outcome){if(outcome&&outcome.descriptor){var c=outcomes[outcome.descriptor.value];if(c){return new c(types.unwrap(outcome))}}console.log("unrecognised outcome: "+JSON.stringify(outcome));return outcome};message.are_outcomes_equi
valent=function(a,b){if(a===undefined&&b===undefined)return true;else if(a===undefined||b===undefined)return false;else return a.descriptor.value==b.descriptor.value&&JSON.stringify(a)==JSON.stringify(b)};define_outcome({name:"received",code:35,fields:[{name:"section_number",type:"uint",mandatory:true},{name:"section_offset",type:"ulong",mandatory:true}]});define_outcome({name:"accepted",code:36,fields:[]});define_outcome({name:"rejected",code:37,fields:[{name:"error",type:"error"}]});define_outcome({name:"released",code:38,fields:[]});define_outcome({name:"modified",code:39,fields:[{name:"delivery_failed",type:"boolean"},{name:"undeliverable_here",type:"boolean"},{name:"message_annotations",type:"map"}]});module.exports=message},{"./log.js":5,"./types.js":12}],7:[function(require,module,exports){"use strict";var url=require("url");var simple_id_generator={counter:1,next:function(){return this.counter++}};var Client=function(container,address){var u=url.parse(address);this.connectio
n=container.connect({host:u.hostname,port:u.port});this.connection.on("message",this._response.bind(this));this.connection.on("receiver_open",this._ready.bind(this));this.sender=this.connection.attach_sender(u.path.substr(1));this.receiver=this.connection.attach_receiver({source:{dynamic:true}});this.id_generator=simple_id_generator;this.pending=[];this.outstanding={}};Client.prototype._request=function(id,name,args,callback){var request={properties:{}};request.properties.subject=name;request.body=args;request.properties.message_id=id;request.properties.reply_to=this.receiver.remote.attach.source.address;this.outstanding[id]=callback;this.sender.send(request)};Client.prototype._response=function(context){var id=context.message.properties.correlation_id;var callback=this.outstanding[id];if(callback){if(context.message.properties.subject==="ok"){callback(context.message.body)}else{callback(undefined,{name:context.message.properties.subject,description:context.message.body})}}else{cons
ole.log("no request pending for "+id+", ignoring response")}};Client.prototype._ready=function(context){this._process_pending()};Client.prototype._process_pending=function(){for(var i=0;i<this.pending.length;i++){var r=this.pending[i];this._request(r.id,r.name,r.args,r.callback)}this.pending=[]};Client.prototype.call=function(name,args,callback){var id=this.id_generator.next();if(this.receiver.is_open()&&this.pending.length===0){this._request(id,name,args,callback)}else{this.pending.push({name:name,args:args,callback:callback,id:id})}};Client.prototype.close=function(){this.receiver.close();this.sender.close();this.connection.close()};Client.prototype.define=function(name){this[name]=function(args,callback){this.call(name,args,callback)}};var Cache=function(ttl,purged){this.ttl=ttl;this.purged=purged;this.entries={};this.timeout=undefined};Cache.prototype.clear=function(){if(this.timeout)clearTimeout(this.timeout);this.entries={}};Cache.prototype.put=function(key,value){this.entries
[key]={value:value,last_accessed:Date.now()};if(!this.timeout)this.timeout=setTimeout(this.purge.bind(this),this.ttl)};Cache.prototype.get=function(key){var entry=this.entries[key];if(entry){entry.last_accessed=Date.now();return entry.value}else{return undefined}};Cache.prototype.purge=function(){var now=Date.now();var expired=[];var live=0;for(var k in this.entries){if(now-this.entries[k].last_accessed>=this.ttl){expired.push(k)}else{live++}}for(var i=0;i<expired.length;i++){var entry=this.entries[expired[i]];delete this.entries[expired[i]];this.purged(entry.value)}if(live&&!this.timeout){this.timeout=setTimeout(this.purge.bind(this),this.ttl)}};var LinkCache=function(factory,ttl){this.factory=factory;this.cache=new Cache(ttl,function(link){link.close()})};LinkCache.prototype.clear=function(){this.cache.clear()};LinkCache.prototype.get=function(address){var link=this.cache.get(address);if(link===undefined){link=this.factory(address);this.cache.put(address,link)}return link};var Ser
ver=function(container,address,options){this.options=options||{};var u=url.parse(address);this.connection=container.connect({host:u.hostname,port:u.port});this.connection.on("connection_open",this._connection_open.bind(this));this.connection.on("message",this._request.bind(this));this.receiver=this.connection.attach_receiver(u.path.substr(1));this.callbacks={};this._send=undefined;this._clear=undefined};function match(desired,offered){if(offered){if(Array.isArray(offered)){return offered.indexOf(desired)>-1}else{return desired===offered}}else{return false}}Server.prototype._connection_open=function(context){if(match("ANONYMOUS-RELAY",this.connection.remote.open.offered_capabilities)){var relay=this.connection.attach_sender({target:{}});this._send=function(msg){relay.send(msg)}}else{var cache=new LinkCache(this.connection.attach_sender.bind(this.connection),this.options.cache_ttl||6e4);this._send=function(msg){var s=cache.get(msg.properties.to);if(s)s.send(msg)};this._clear=function(
){cache.clear()}}};Server.prototype._respond=function(response){var server=this;return function(result,error){if(error){response.properties.subject=error.name||"error";response.body=error.description||error}else{response.properties.subject="ok";response.body=result}server._send(response)}};Server.prototype._request=function(context){var request=context.message;var response={properties:{}};response.properties.to=request.properties.reply_to;response.properties.correlation_id=request.properties.message_id;var callback=this.callbacks[request.properties.subject];if(callback){callback(request.body,this._respond(response))}else{response.properties.subject="bad-method";response.body="Unrecognised method "+request.properties.subject;this._send(response)}};Server.prototype.bind_sync=function(f,name){this.callbacks[name||f.name]=function(args,callback){var result=f(args);callback(result)}};Server.prototype.bind=function(f,name){this.callbacks[name||f.name]=f};Server.prototype.close=function(){
if(this._clear)this._clear();this.receiver.close();this.connection.close()};module.exports={server:function(container,address,options){return new Server(container,address,options)},client:function(connection,address){return new Client(connection,address)}}},{url:30}],8:[function(require,module,exports){(function(Buffer){"use strict";var frames=require("./frames.js");var log=require("./log.js");var Transport=require("./transport.js");var sasl_codes={OK:0,AUTH:1,SYS:2,SYS_PERM:3,SYS_TEMP:4};var SASL_PROTOCOL_ID=3;function intersection(lista,listb){return lista.filter(function(a){return listb.indexOf(a)>=0})}function extract(buffer){var results=[];var start=0;var i=0;while(i<buffer.length){if(buffer[i]===0){if(i>start)results.push(buffer.toString("utf8",start,i));else results.push(null);start=++i}else{++i}}if(i>start)results.push(buffer.toString("utf8",start,i));else results.push(null);return results}var PlainServer=function(callback){this.callback=callback;this.outcome=undefined;this.
username=undefined};PlainServer.prototype.start=function(response){var fields=extract(response);if(fields.length!==3){this.connection.sasl_failed("Unexpected response in PLAIN, got "+fields.length+" fields, expected 3")}if(this.callback(fields[1],fields[2])){this.outcome=true;this.username=fields[1]}else{this.outcome=false}};var PlainClient=function(username,password){this.username=username;this.password=password};PlainClient.prototype.start=function(){var response=new Buffer(1+this.username.length+1+this.password.length);response.writeUInt8(0,0);response.write(this.username,1);response.writeUInt8(0,1+this.username.length);response.write(this.password,1+this.username.length+1);return response};var AnonymousServer=function(){this.outcome=undefined;this.username=undefined};AnonymousServer.prototype.start=function(response){this.outcome=true;this.username=response?response.toString("utf8"):"anonymous"};var AnonymousClient=function(name){this.username=name?name:"anonymous"};AnonymousCli
ent.prototype.start=function(){var response=new Buffer(1+this.username.length);response.writeUInt8(0,0);response.write(this.username,1);return response};var ExternalServer=function(){this.outcome=undefined;this.username=undefined};ExternalServer.prototype.start=function(response){this.outcome=true};var ExternalClient=function(){this.username=undefined};ExternalClient.prototype.start=function(){return null};var SaslServer=function(connection,mechanisms){this.connection=connection;this.transport=new Transport(connection.amqp_transport.identifier,SASL_PROTOCOL_ID,frames.TYPE_SASL,this);this.next=connection.amqp_transport;this.mechanisms=mechanisms;this.mechanism=undefined;this.outcome=undefined;this.username=undefined;var mechlist=Object.getOwnPropertyNames(mechanisms);this.transport.encode(frames.sasl_frame(frames.sasl_mechanisms({sasl_server_mechanisms:mechlist}).described()))};SaslServer.prototype.do_step=function(challenge){if(this.mechanism.outcome===undefined){this.transport.enco
de(frames.sasl_frame(frames.sasl_challenge({challenge:challenge}).described()))}else{this.outcome=this.mechanism.outcome?sasl_codes.OK:sasl_codes.AUTH;this.transport.encode(frames.sasl_frame(frames.sasl_outcome({code:this.outcome}).described()));if(this.outcome===sasl_codes.OK){this.username=this.mechanism.username;this.transport.write_complete=true;this.transport.read_complete=true}}};SaslServer.prototype.on_sasl_init=function(frame){var f=this.mechanisms[frame.performative.mechanism];if(f){this.mechanism=f();var challenge=this.mechanism.start(frame.performative.initial_response);this.do_step(challenge)}else{this.outcome=sasl_codes.AUTH;this.transport.encode(frames.sasl_frame(frames.sasl_outcome({code:this.outcome}).described()))}};SaslServer.prototype.on_sasl_response=function(frame){this.do_step(this.mechanism.step(frame.performative.response))};SaslServer.prototype.has_writes_pending=function(){return this.transport.has_writes_pending()||this.next.has_writes_pending()};SaslServe
r.prototype.write=function(socket){if(this.transport.write_complete&&this.transport.pending.length===0){return this.next.write(socket)}else{return this.transport.write(socket)}};SaslServer.prototype.read=function(buffer){if(this.transport.read_complete){return this.next.read(buffer)}else{return this.transport.read(buffer)}};var SaslClient=function(connection,mechanisms){this.connection=connection;this.transport=new Transport(connection.amqp_transport.identifier,SASL_PROTOCOL_ID,frames.TYPE_SASL,this);this.next=connection.amqp_transport;this.mechanisms=mechanisms;this.mechanism=undefined;this.mechanism_name=undefined;this.failed=false};SaslClient.prototype.on_sasl_mechanisms=function(frame){for(var i=0;this.mechanism===undefined&&i<frame.performative.sasl_server_mechanisms.length;i++){var mech=frame.performative.sasl_server_mechanisms[i];var f=this.mechanisms[mech];if(f){this.mechanism=f();this.mechanism_name=mech}}if(this.mechanism){var response=this.mechanism.start();this.transport
.encode(frames.sasl_frame(frames.sasl_init({mechanism:this.mechanism_name,initial_response:response}).described()))}else{this.failed=true;this.connection.sasl_failed("No suitable mechanism; server supports "+frame.performative.sasl_server_mechanisms)}};SaslClient.prototype.on_sasl_challenge=function(frame){var response=this.mechanism.step(frame.performative.challenge);this.transport.encode(frames.sasl_frame(frames.sasl_response({response:response}).described()))};SaslClient.prototype.on_sasl_outcome=function(frame){switch(frame.performative.code){case sasl_codes.OK:this.transport.read_complete=true;this.transport.write_complete=true;break;default:this.transport.write_complete=true;this.connection.sasl_failed("Failed to authenticate: "+frame.performative.code)}};SaslClient.prototype.has_writes_pending=function(){return this.transport.has_writes_pending()||this.next.has_writes_pending()};SaslClient.prototype.write=function(socket){if(this.transport.write_complete){return this.next.wri
te(socket)}else{return this.transport.write(socket)}};SaslClient.prototype.read=function(buffer){if(this.transport.read_complete){return this.next.read(buffer)}else{return this.transport.read(buffer)}};var default_server_mechanisms={enable_anonymous:function(){this["ANONYMOUS"]=function(){return new AnonymousServer}},enable_plain:function(callback){this["PLAIN"]=function(){return new PlainServer(callback)}}};var default_client_mechanisms={enable_anonymous:function(name){this["ANONYMOUS"]=function(){return new AnonymousClient(name)}},enable_plain:function(username,password){this["PLAIN"]=function(){return new PlainClient(username,password)}},enable_external:function(){this["EXTERNAL"]=function(){return new ExternalClient}}};module.exports={Client:SaslClient,Server:SaslServer,server_mechanisms:function(){return Object.create(default_server_mechanisms)},client_mechanisms:function(){return Object.create(default_client_mechanisms)},server_add_external:function(mechs){mechs["EXTERNAL"]=fu
nction(){return new ExternalServer};return mechs}}}).call(this,require("buffer").Buffer)},{"./frames.js":3,"./log.js":5,"./transport.js":11,buffer:19}],9:[function(require,module,exports){(function(Buffer){"use strict";var frames=require("./frames.js");var link=require("./link.js");var log=require("./log.js");var message=require("./message.js");var types=require("./types.js");var util=require("./util.js");var EndpointState=require("./endpoint.js");var EventEmitter=require("events").EventEmitter;var CircularBuffer=function(capacity){this.capacity=capacity;this.size=0;this.head=0;this.tail=0;this.entries=[]};CircularBuffer.prototype.available=function(){return this.capacity-this.size};CircularBuffer.prototype.push=function(o){if(this.size<this.capacity){this.entries[this.tail]=o;this.tail=(this.tail+1)%this.capacity;this.size++}else{throw Error("circular buffer overflow: head="+this.head+" tail="+this.tail+" size="+this.size+" capacity="+this.capacity)}};CircularBuffer.prototype.pop_i
f=function(f){var count=0;while(this.size&&f(this.entries[this.head])){this.entries[this.head]=undefined;this.head=(this.head+1)%this.capacity;this.size--;count++}return count};CircularBuffer.prototype.by_id=function(id){if(this.size>0){var gap=id-this.entries[this.head].id;if(gap<this.size){return this.entries[(this.head+gap)%this.capacity]}}return undefined};CircularBuffer.prototype.get_head=function(id){return this.size>0?this.entries[this.head]:undefined};function write_dispositions(deliveries){var first;var last;var next_id;for(var i=0;i<deliveries.length;i++){var delivery=deliveries[i];if(first===undefined){first=delivery;last=delivery;next_id=delivery.id}if(!message.are_outcomes_equivalent(last.state,delivery.state)||last.settled!==delivery.settled||next_id!==delivery.id){first.link.session.output(frames.disposition({role:first.link.is_receiver(),first:first.id,last:last.id,state:first.state,settled:first.settled}).described());first=delivery;last=delivery;next_id=delivery.id
}else{if(last.id!==delivery.id){last=delivery}next_id++}}if(first!==undefined&&last!==undefined){first.link.session.output(frames.disposition({role:first.link.is_receiver(),first:first.id,last:last.id,state:first.state,settled:first.settled}).described())}}var Outgoing=function(){this.deliveries=new CircularBuffer(2048);this.updated=[];this.pending_dispositions=[];this.next_delivery_id=0;this.next_pending_delivery=0;this.next_transfer_id=0;this.window=types.MAX_UINT;this.remote_next_transfer_id=undefined;this.remote_window=undefined};Outgoing.prototype.available=function(){return this.deliveries.available()};Outgoing.prototype.send=function(sender,tag,data,format){var d={id:this.next_delivery_id++,tag:tag,link:sender,data:data,format:format?format:0,sent:false,settled:false,state:undefined,remote_settled:false,remote_state:undefined};var self=this;d.update=function(settled,state){self.update(d,settled,state)};this.deliveries.push(d);return d};Outgoing.prototype.on_begin=function(fie
lds){this.remote_window=fields.incoming_window};Outgoing.prototype.on_flow=function(fields){this.remote_next_transfer_id=fields.next_incoming_id;this.remote_window=fields.incoming_window};Outgoing.prototype.on_disposition=function(fields){var last=fields.last?fields.last:fields.first;for(var i=fields.first;i<=last;i++){var d=this.deliveries.by_id(i);if(d&&!d.remote_settled){var updated=false;if(fields.settled){d.remote_settled=fields.settled;updated=true}if(fields.state&&fields.state!==d.remote_state){d.remote_state=message.unwrap_outcome(fields.state);updated=true}if(updated){this.updated.push(d)}}}};Outgoing.prototype.update=function(delivery,settled,state){if(delivery){delivery.settled=settled;if(state!==undefined)delivery.state=state;if(!delivery.remote_settled){this.pending_dispositions.push(delivery)}delivery.link.connection._register()}};Outgoing.prototype.transfer_window=function(){if(this.remote_window){return this.remote_window-(this.next_transfer_id-this.remote_next_trans
fer_id)}};Outgoing.prototype.process=function(){while(this.next_pending_delivery<this.next_delivery_id){var d=this.deliveries.by_id(this.next_pending_delivery);if(d){if(d.link.has_credit()){d.link.delivery_count++;d.transfers_required=1;if(this.transfer_window()>=d.transfers_required){this.next_transfer_id+=d.transfers_required;this.window-=d.transfers_required;d.link.session.output(frames.transfer({handle:d.link.local.handle,message_format:d.format,delivery_id:d.id,delivery_tag:d.tag,settled:d.settled}).described(),d.data);d.link.credit--;this.next_pending_delivery++}else{log.flow("Incoming window of peer preventing sending further transfers: remote_window="+this.remote_window+", remote_next_transfer_id="+this.remote_next_transfer_id+", next_transfer_id="+this.next_transfer_id);break}}else{log.flow("Link has no credit");break}}else{console.log("ERROR: Next pending delivery not found: "+this.next_pending_delivery);break}}for(var i=0;i<this.updated.length;i++){var d=this.updated[i];i
f(d.remote_state&&d.remote_state.constructor.composite_type){d.link.dispatch(d.remote_state.constructor.composite_type,d.link._context({delivery:d}))}if(d.remote_settled)d.link.dispatch("settled",d.link._context({delivery:d}))}this.updated=[];if(this.pending_dispositions.length){write_dispositions(this.pending_dispositions);this.pending_dispositions=[]}this.deliveries.pop_if(function(d){return d.settled&&d.remote_settled})};var Incoming=function(){this.deliveries=new CircularBuffer(2048);this.updated=[];this.next_transfer_id=0;this.next_delivery_id=undefined;this.window=2048;this.remote_next_transfer_id=undefined;this.remote_window=undefined};Incoming.prototype.update=function(delivery,settled,state){if(delivery){delivery.settled=settled;if(state!==undefined)delivery.state=state;if(!delivery.remote_settled){this.updated.push(delivery)}delivery.link.connection._register()}};Incoming.prototype.on_transfer=function(frame,receiver){this.next_transfer_id++;if(receiver.is_open()){if(this.
next_delivery_id===undefined){this.next_delivery_id=frame.performative.delivery_id}var current;var data;var last=this.deliveries.get_head();if(last&&last.incomplete){if(frame.performative.delivery_id!==undefined&&this.next_delivery_id!=frame.performative.delivery_id){throw Error("frame sequence error: delivery "+this.next_delivery_id+" not complete, got "+frame.performative.delivery_id)}current=last;data=Buffer.concat([current.data,frame.payload],current.data.size()+frame.payload.size())}else if(this.next_delivery_id===frame.performative.delivery_id){current={id:frame.performative.delivery_id,tag:frame.performative.delivery_tag,link:receiver,settled:false,state:undefined,remote_settled:frame.performative.settled===undefined?false:frame.performative.settled,remote_state:frame.performative.state};var self=this;current.update=function(settled,state){var settled_=settled;if(settled_===undefined){settled_=receiver.local.attach.rcv_settle_mode!==1}self.update(current,settled_,state)};curr
ent.accept=function(){this.update(undefined,message.accepted().described())};current.release=function(params){if(params){this.update(undefined,message.modified(params).described())}else{this.update(undefined,message.released().described())}};current.reject=function(error){this.update(true,message.rejected({error:error}).described())};current.modified=function(params){this.update(true,message.modified(params).described())};this.deliveries.push(current);data=frame.payload}else{throw Error("frame sequence error: expected "+this.next_delivery_id+", got "+frame.performative.delivery_id)}current.incomplete=frame.performative.more;if(current.incomplete){current.data=data}else{receiver.credit--;receiver.delivery_count++;this.next_delivery_id++;receiver.dispatch("message",receiver._context({message:message.decode(data),delivery:current}))}}};Incoming.prototype.process=function(){if(this.updated.length>0){write_dispositions(this.updated);this.updated=[]}this.deliveries.pop_if(function(d){retu
rn d.settled})};Incoming.prototype.on_begin=function(fields){this.remote_window=fields.outgoing_window};Incoming.prototype.on_flow=function(fields){this.remote_next_transfer_id=fields.next_outgoing_id;this.remote_window=fields.outgoing_window};Incoming.prototype.on_disposition=function(fields){var last=fields.last?fields.last:fields.first;for(var i=fields.first;i<=last;i++){var d=this.deliveries.by_id(i);if(d&&!d.remote_settled){var updated=false;if(fields.settled){d.remote_settled=fields.settled;d.link.dispatch("settled",d.link._context({delivery:d}))}}}};var Session=function(connection,local_channel){this.connection=connection;this.outgoing=new Outgoing;this.incoming=new Incoming;this.state=new EndpointState;this.local={channel:local_channel,handles:{}};this.local.begin=frames.begin({next_outgoing_id:this.outgoing.next_transfer_id,incoming_window:this.incoming.window,outgoing_window:this.outgoing.window});this.local.end=frames.end();this.remote={handles:{}};this.links={};this.opti
ons={}};Session.prototype=Object.create(EventEmitter.prototype);Session.prototype.constructor=Session;Session.prototype.reset=function(){this.state.disconnected();this.outgoing=new Outgoing;this.incoming=new Incoming;this.remote={handles:{}};for(var l in this.links){this.links[l].reset()}};Session.prototype.dispatch=function(name,context){log.events("Session got event: "+name);if(this.listeners(name).length){EventEmitter.prototype.emit.apply(this,arguments);return true}else{return this.connection.dispatch.apply(this.connection,arguments)}};Session.prototype.output=function(frame,payload){this.connection._write_frame(this.local.channel,frame,payload)};Session.prototype.create_sender=function(name,opts){return this.create_link(name,link.Sender,opts)};Session.prototype.create_receiver=function(name,opts){return this.create_link(name,link.Receiver,opts)};function attach(factory,args,remote_terminus){var opts=args?args:{};if(typeof args==="string"){opts={};opts[remote_terminus]=args}if(!
opts.name)opts.name=util.generate_uuid();var l=factory(opts.name,opts);for(var t in{source:0,target:0}){if(opts[t]){if(typeof opts[t]==="string"){opts[t]={address:opts[t]}}l["set_"+t](opts[t])}}l.attach();return l}Session.prototype.get_option=function(name,default_value){if(this.options[name]!==undefined)return this.options[name];else return this.connection.get_option(name,default_value)};Session.prototype.attach_sender=function(args){return attach(this.create_sender.bind(this),args,"target")};Session.prototype.open_sender=Session.prototype.attach_sender;Session.prototype.attach_receiver=function(args){return attach(this.create_receiver.bind(this),args,"source")};Session.prototype.open_receiver=Session.prototype.attach_receiver;Session.prototype.create_link=function(name,constructor,opts){var i=0;while(this.local.handles[i])i++;var l=new constructor(this,name,i,opts);this.links[name]=l;this.local.handles[i]=l;return l};Session.prototype.begin=function(){if(this.state.open()){this.co
nnection._register()}};Session.prototype.open=Session.prototype.begin;Session.prototype.end=function(error){if(error)this.local.end.error=error;if(this.state.close()){this.connection._register()}};Session.prototype.close=Session.prototype.end;Session.prototype.is_open=function(){return this.connection.is_open()&&this.state.is_open()};Session.prototype.is_closed=function(){return this.connection.is_closed()||this.state.is_closed()};Session.prototype._process=function(){do{if(this.state.need_open()){this.output(this.local.begin.described())}this.outgoing.process();this.incoming.process();for(var k in this.links){this.links[k]._process()}if(this.state.need_close()){this.output(this.local.end.described())}}while(!this.state.has_settled())};Session.prototype.send=function(sender,tag,data,format){var d=this.outgoing.send(sender,tag,data,format);this.connection._register();return d};Session.prototype._write_flow=function(link){var fields={next_incoming_id:this.incoming.next_transfer_id,inc
oming_window:this.incoming.window,next_outgoing_id:this.outgoing.next_transfer_id,outgoing_window:this.outgoing.window};if(link){if(link._get_drain())fields.drain=true;fields.delivery_count=link.delivery_count;fields.handle=link.local.handle;fields.link_credit=link.credit}this.output(frames.flow(fields).described())};Session.prototype.on_begin=function(frame){if(this.state.remote_opened()){if(!this.remote.channel){this.remote.channel=frame.channel}this.remote.begin=frame.performative;this.outgoing.on_begin(frame.performative);this.incoming.on_begin(frame.performative);this.open();this.dispatch("session_open",this._context())}else{throw Error("Begin already received")}};Session.prototype.on_end=function(frame){if(this.state.remote_closed()){this.remote.end=frame.performative;this.close();this.dispatch("session_close",this._context())}else{throw Error("End already received")}};Session.prototype.on_attach=function(frame){var name=frame.performative.name;var link=this.links[name];if(!li
nk){link=frame.performative.role?this.create_sender(name):this.create_receiver(name)}this.remote.handles[frame.performative.handle]=link;
-link.on_attach(frame);link.remote.attach=frame.performative};Session.prototype.on_disposition=function(frame){if(frame.performative.role){log.events("Received disposition for outgoing transfers");this.outgoing.on_disposition(frame.performative)}else{log.events("Received disposition for incoming transfers");this.incoming.on_disposition(frame.performative)}this.connection._register()};Session.prototype.on_flow=function(frame){this.outgoing.on_flow(frame.performative);this.incoming.on_flow(frame.performative);if(frame.performative.handle!==undefined){this._get_link(frame).on_flow(frame)}this.connection._register()};Session.prototype._context=function(c){var context=c?c:{};context.session=this;return this.connection._context(context)};Session.prototype._get_link=function(frame){var handle=frame.performative.handle;var link=this.remote.handles[handle];if(!link){throw Error("Invalid handle "+handle)}return link};Session.prototype.on_detach=function(frame){this._get_link(frame).on_detach(f
rame);var handle=frame.performative.handle;var link=this.remote.handles[handle];delete this.remote.handles[handle];delete this.local.handles[link.local.handle];delete this.links[link.name]};Session.prototype.on_transfer=function(frame){this.incoming.on_transfer(frame,this._get_link(frame))};module.exports=Session}).call(this,require("buffer").Buffer)},{"./endpoint.js":2,"./frames.js":3,"./link.js":4,"./log.js":5,"./message.js":6,"./types.js":12,"./util.js":13,buffer:19,events:23}],10:[function(require,module,exports){"use strict";var types=require("./types.js");var terminus={};var by_descriptor={};function define_terminus(def){var c=types.define_composite(def);terminus[def.name]=c.create;by_descriptor[Number(c.descriptor.numeric).toString(10)]=c;by_descriptor[c.descriptor.symbolic]=c}terminus.unwrap=function(field){if(field&&field.descriptor){var c=by_descriptor[field.descriptor.value];if(c){return new c(field.value)}else{console.log("Unknown terminus: "+field.descriptor)}}return nu
ll};define_terminus({name:"source",code:40,fields:[{name:"address",type:"string"},{name:"durable",type:"uint",default_value:0},{name:"expiry_policy",type:"symbol",default_value:"session-end"},{name:"timeout",type:"uint",default_value:0},{name:"dynamic",type:"boolean",default_value:false},{name:"dynamic_node_properties",type:"symbolic_map"},{name:"distribution_mode",type:"symbol"},{name:"filter",type:"symbolic_map"},{name:"default_outcome",type:"*"},{name:"outcomes",type:"symbol",multiple:true},{name:"capabilities",type:"symbol",multiple:true}]});define_terminus({name:"target",code:41,fields:[{name:"address",type:"string"},{name:"durable",type:"uint",default_value:0},{name:"expiry_policy",type:"symbol",default_value:"session-end"},{name:"timeout",type:"uint",default_value:0},{name:"dynamic",type:"boolean",default_value:false},{name:"dynamic_node_properties",type:"symbolic_map"},{name:"capabilities",type:"symbol",multiple:true}]});module.exports=terminus},{"./types.js":12}],11:[functi
on(require,module,exports){(function(Buffer){"use strict";var frames=require("./frames.js");var log=require("./log.js");var Transport=function(identifier,protocol_id,frame_type,handler){this.identifier=identifier;this.protocol_id=protocol_id;this.frame_type=frame_type;this.handler=handler;this.pending=[];this.header_sent=undefined;this.header_received=undefined;this.write_complete=false;this.read_complete=false};Transport.prototype.has_writes_pending=function(){return this.pending.length>0};Transport.prototype.encode=function(frame){var buffer=frames.write_frame(frame);log.frames("["+this.identifier+"] PENDING: "+JSON.stringify(frame));this.pending.push(buffer)};Transport.prototype.write=function(socket){if(!this.header_sent){var buffer=new Buffer(8);var header={protocol_id:this.protocol_id,major:1,minor:0,revision:0};frames.write_header(buffer,header);socket.write(buffer);this.header_sent=header}for(var i=0;i<this.pending.length;i++){socket.write(this.pending[i]);log.raw("["+this.i
dentifier+"] SENT: "+JSON.stringify(this.pending[i]))}this.pending=[]};Transport.prototype.read=function(buffer){var offset=0;if(!this.header_received){if(buffer.length<8){return offset}else{this.header_received=frames.read_header(buffer);log.frames("["+this.identifier+"] RECV: "+JSON.stringify(this.header_received));if(this.header_received.protocol_id!==this.protocol_id){throw Error("Invalid AMQP protocol id "+this.header_received.protocol_id+" expecting: "+this.protocol_id)}offset=8}}while(offset<buffer.length&&!this.read_complete){var frame_size=buffer.readUInt32BE(offset);log.io("["+this.identifier+"] got frame of size "+frame_size);if(buffer.length<offset+frame_size){log.io("["+this.identifier+"] incomplete frame; have only "+(buffer.length-offset)+" of "+frame_size);break}else{var frame=frames.read_frame(buffer.slice(offset,offset+frame_size));log.frames("["+this.identifier+"] RECV: "+JSON.stringify(frame));if(frame.type!==this.frame_type){throw Error("Invalid frame type: "+fr
ame.type)}offset+=frame_size;if(frame.performative){frame.performative.dispatch(this.handler,frame)}}}return offset};module.exports=Transport}).call(this,require("buffer").Buffer)},{"./frames.js":3,"./log.js":5,buffer:19}],12:[function(require,module,exports){(function(Buffer){"use strict";function Typed(type,value){this.type=type;this.value=value}Typed.prototype.toString=function(){return this.value?this.value.toString():null};Typed.prototype.toLocaleString=function(){return this.value?this.value.toLocaleString():null};Typed.prototype.valueOf=function(){return this.value};Typed.prototype.toJSON=function(){return this.value&&this.value.toJSON?this.value.toJSON():this.value};function hex(i){return Number(i).toString(16)}var types={by_code:{}};Object.defineProperty(types,"MAX_UINT",{value:4294967295,writable:false,configurable:false});Object.defineProperty(types,"MAX_USHORT",{value:65535,writable:false,configurable:false});function define_type(name,typecode,annotations,empty_value){va
r subcategory=typecode>>>4;var t;if(subcategory===4){t=function(){this.type=t;this.value=empty_value}}else if(subcategory===14||subcategory===15){t=function(v,code,descriptor){this.type=t;this.value=v;this.array_constructor={typecode:code};if(descriptor){this.array_constructor.descriptor=descriptor}}}else{t=function(v){this.type=t;this.value=v}}t.typecode=typecode;t.prototype=Object.create(Typed.prototype);t.toString=function(){return name+"#"+hex(typecode)};switch(subcategory){case 4:t.width=0;t.category="fixed";break;case 5:t.width=1;t.category="fixed";break;case 6:t.width=2;t.category="fixed";break;case 7:t.width=4;t.category="fixed";break;case 8:t.width=8;t.category="fixed";break;case 9:t.width=16;t.category="fixed";break;case 10:t.width=1;t.category="variable";break;case 11:t.width=4;t.category="variable";break;case 12:t.width=1;t.category="compound";break;case 13:t.width=4;t.category="compound";break;case 14:t.width=1;t.category="array";break;case 15:t.width=4;t.category="arra
y";break}if(annotations){for(var a in annotations){t[a]=annotations[a]}}types.by_code[t.typecode]=t;types[name]=t;return t}function buffer_ops(name){return{read:function(buffer,offset){return buffer["read"+name](offset)},write:function(buffer,value,offset){buffer["write"+name](value,offset)}}}function buffer_ops_be(name){return{read:function(buffer,offset){return buffer["read"+name+"BE"](offset)},write:function(buffer,value,offset){buffer["write"+name+"BE"](value,offset)}}}var MAX_UINT=4294967296;var MIN_INT=-2147483647;function write_ulong(buffer,value,offset){if(typeof value==="number"||value instanceof Number){var hi=Math.floor(value/MAX_UINT);var lo=value%MAX_UINT;buffer.writeUInt32BE(hi,offset);buffer.writeUInt32BE(lo,offset+4)}else{value.copy(buffer,offset)}}function read_ulong(buffer,offset){var hi=buffer.readUInt32BE(offset);var lo=buffer.readUInt32BE(offset+4);if(hi<2097153){return hi*MAX_UINT+lo}else{return buffer.slice(offset,offset+8)}}function write_long(buffer,value,of
fset){if(typeof value==="number"||value instanceof Number){var abs=Math.abs(value);var hi=Math.floor(abs/MAX_UINT);var lo=abs%MAX_UINT;buffer.writeInt32BE(hi,offset);buffer.writeUInt32BE(lo,offset+4);if(value<0){var carry=1;for(var i=0;i<8;i++){var index=offset+(7-i);var value=(buffer[index]^255)+carry;buffer[index]=value&255;carry=value>>8}}}else{value.copy(buffer,offset)}}function read_long(buffer,offset){var hi=buffer.readInt32BE(offset);var lo=buffer.readUInt32BE(offset+4);if(hi<2097153&&hi>-2097153){return hi*MAX_UINT+lo}else{return buffer.slice(offset,offset+8)}}define_type("Null",64,undefined,null);define_type("Boolean",86,buffer_ops("UInt8"));define_type("True",65,undefined,true);define_type("False",66,undefined,false);define_type("Ubyte",80,buffer_ops("UInt8"));define_type("Ushort",96,buffer_ops("UInt16BE"));define_type("Uint",112,buffer_ops("UInt32BE"));define_type("SmallUint",82,buffer_ops("UInt8"));define_type("Uint0",67,undefined,0);define_type("Ulong",128,{write:write_
ulong,read:read_ulong});define_type("SmallUlong",83,buffer_ops("UInt8"));define_type("Ulong0",68,undefined,0);define_type("Byte",81,buffer_ops("Int8"));define_type("Short",97,buffer_ops("Int16BE"));define_type("Int",113,buffer_ops("Int32BE"));define_type("SmallInt",84,buffer_ops("Int8"));define_type("Long",129,{write:write_long,read:read_long});define_type("SmallLong",85,buffer_ops("Int8"));define_type("Float",114,buffer_ops_be("Float"));define_type("Double",130,buffer_ops_be("Double"));define_type("Decimal32",116);define_type("Decimal64",132);define_type("Decimal128",148);define_type("CharUTF32",115);define_type("Timestamp",131,{write:write_long,read:read_long});define_type("Uuid",152);define_type("Vbin8",160);define_type("Vbin32",176);define_type("Str8",161,{encoding:"utf8"});define_type("Str32",177,{encoding:"utf8"});define_type("Sym8",163,{encoding:"ascii"});define_type("Sym32",179,{encoding:"ascii"});define_type("List0",69,undefined,[]);define_type("List8",192);define_type("Lis
t32",208);define_type("Map8",193);define_type("Map32",209);define_type("Array8",224);define_type("Array32",240);function is_one_of(o,typelist){for(var i=0;i<typelist.length;i++){if(o.type.typecode===typelist[i].typecode)return true}return false}types.is_ulong=function(o){return is_one_of(o,[types.Ulong,types.Ulong0,types.SmallUlong])};types.is_string=function(o){return is_one_of(o,[types.Str8,types.Str32])};types.is_symbol=function(o){return is_one_of(o,[types.Sym8,types.Sym32])};types.is_list=function(o){return is_one_of(o,[types.List0,types.List8,types.List32])};types.is_map=function(o){return is_one_of(o,[types.Map8,types.Map32])};types.wrap_boolean=function(v){return v?new types.True:new types.False};types.wrap_ulong=function(l){if(l===0)return new types.Ulong0;else return l>255?new types.Ulong(l):new types.SmallUlong(l)};types.wrap_uint=function(l){if(l===0)return new types.Uint0;else return l>255?new types.Uint(l):new types.SmallUint(l)};types.wrap_ushort=function(l){return ne
w types.Ushort(l)};types.wrap_ubyte=function(l){return new types.Ubyte(l)};types.wrap_long=function(l){return l>127||l<-128?new types.Long(l):new types.SmallLong(l)};types.wrap_int=function(l){return l>127||l<-128?new types.Int(l):new types.SmallInt(l)};types.wrap_short=function(l){return new types.Short(l)};types.wrap_byte=function(l){return new types.Byte(l)};types.wrap_float=function(l){return new types.Float(l)};types.wrap_double=function(l){return new types.Double(l)};types.wrap_timestamp=function(l){return new types.Timestamp(l)};types.wrap_binary=function(s){return s.length>255?new types.Vbin32(s):new types.Vbin8(s)};types.wrap_string=function(s){return s.length>255?new types.Str32(s):new types.Str8(s)};types.wrap_symbol=function(s){return s.length>255?new types.Sym32(s):new types.Sym8(s)};types.wrap_list=function(l){if(l.length===0)return new types.List0;var items=l.map(types.wrap);return new types.List32(items)};types.wrap_map=function(m,key_wrapper){var items=[];for(var k
in m){items.push(key_wrapper?key_wrapper(k):types.wrap(k));items.push(types.wrap(m[k]))}return new types.Map32(items)};types.wrap_symbolic_map=function(m){return types.wrap_map(m,types.wrap_symbol)};types.wrap_array=function(l,code,descriptors){if(code){return new types.Array32(l,code,descriptors)}else{throw Error("An array must specify a type for its elements")}};types.wrap=function(o){var t=typeof o;if(t==="string"){return types.wrap_string(o)}else if(t=="boolean"){return o?new types.True:new types.False}else if(t=="number"||o instanceof Number){if(isNaN(o)){throw Error("Cannot wrap NaN! "+o)}else if(Math.floor(o)-o!==0){return new types.Double(o)}else if(o>0){if(o<MAX_UINT){return types.wrap_uint(o)}else{return types.wrap_ulong(o)}}else{if(o>MIN_INT){return types.wrap_int(o)}else{return types.wrap_long(o)}}}else if(o instanceof Date){return types.wrap_timestamp(o.getTime())}else if(o instanceof Typed){return o}else if(t=="undefined"||o===null){return new types.Null}else if(Array.
isArray(o)){return types.wrap_list(o)}else{return types.wrap_map(o)}};types.wrap_described=function(value,descriptor){var result=types.wrap(value);if(descriptor){if(typeof descriptor==="string"){result=types.described(types.wrap_string(descriptor),result)}else if(typeof descriptor==="number"||descriptor instanceof Number){result=types.described(types.wrap_ulong(descriptor),result)}}return result};types.wrap_message_id=function(o){var t=typeof o;if(t==="string"){return types.wrap_string(o)}else if(t=="number"||o instanceof Number){return types.wrap_ulong(o)}else{throw Error("invalid message id:"+o)}};types.wrap_delivery_state=function(o){return new Null};function mapify(elements){var result={};for(var i=0;i+1<elements.length;){result[elements[i++]]=elements[i++]}return result}var by_descriptor={};types.unwrap=function(o,leave_described){if(o instanceof Typed){if(o.descriptor){var c=by_descriptor[o.descriptor.value];if(c){return new c(o.value)}else if(leave_described){return o}}var u=
types.unwrap(o.value,true);return types.is_map(o)?mapify(u):u}else if(Array.isArray(o)){return o.map(function(i){return types.unwrap(i,true)})}else{return o}};types.described=function(descriptor,typedvalue){var o=Object.create(typedvalue);if(descriptor.length){o.descriptor=descriptor.shift();return described(descriptor,o)}else{o.descriptor=descriptor;return o}};function get_type(code){var type=types.by_code[code];if(!type){throw Error("Unrecognised typecode: "+hex(code))}return type}types.Reader=function(buffer){this.buffer=buffer;this.position=0};types.Reader.prototype.read_typecode=function(){return this.read_uint(1)};types.Reader.prototype.read_uint=function(width){var current=this.position;this.position+=width;var name=width>1?"readUInt"+width*8+"BE":"readUInt"+8;return this.buffer[name](current)};types.Reader.prototype.read_fixed_width=function(type){var current=this.position;this.position+=type.width;if(type.read){return type.read(this.buffer,current)}else{return this.buffer.s
lice(current,this.position)}};types.Reader.prototype.read_variable_width=function(type){var size=this.read_uint(type.width);var slice=this.read_bytes(size);return type.encoding?slice.toString(type.encoding):slice};types.Reader.prototype.read=function(){var constructor=this.read_constructor();var value=this.read_value(get_type(constructor.typecode));return constructor.descriptor?types.described(constructor.descriptor,value):value};types.Reader.prototype.read_constructor=function(){var code=this.read_typecode();if(code===0){var d=[];d.push(this.read());var c=this.read_constructor();while(c.descriptor){d.push(c.descriptor);c=this.read_constructor()}return{typecode:c.typecode,descriptor:d.length==1?d[0]:d}}else{return{typecode:code}}};types.Reader.prototype.read_value=function(type){if(type.width===0){return new type}else if(type.category==="fixed"){return new type(this.read_fixed_width(type))}else if(type.category==="variable"){return new type(this.read_variable_width(type))}else if(ty
pe.category==="compound"){return this.read_compound(type)}else if(type.category==="array"){return this.read_array(type)}else{throw Error("Invalid category for type: "+type)}};types.Reader.prototype.read_multiple=function(n,f){var read_fn=f?f:this.read.bind(this);var items=[];while(items.length<n){items.push(read_fn.apply(this))}return items};types.Reader.prototype.read_size_count=function(width){return{size:this.read_uint(width),count:this.read_uint(width)}};types.Reader.prototype.read_compound=function(type){var limits=this.read_size_count(type.width);return new type(this.read_multiple(limits.count))};types.Reader.prototype.read_array=function(type){var limits=this.read_size_count(type.width);var constructor=this.read_constructor();var value=new type(this.read_multiple(limits.count,this.read_value.bind(this,get_type(constructor.typecode))),constructor.typecode,constructor.descriptor);return value};types.Reader.prototype.toString=function(){var s="buffer@"+this.position;if(this.posi
tion)s+=": ";for(var i=this.position;i<this.buffer.length;i++){if(i>0)s+=",";s+="0x"+Number(this.buffer[i]).toString(16)}return s};types.Reader.prototype.reset=function(){this.position=0};types.Reader.prototype.skip=function(bytes){this.position+=bytes};types.Reader.prototype.read_bytes=function(bytes){var current=this.position;this.position+=bytes;return this.buffer.slice(current,this.position)};types.Reader.prototype.remaining=function(){return this.buffer.length-this.position};types.Writer=function(buffer){this.buffer=buffer?buffer:new Buffer(1024);this.position=0};types.Writer.prototype.toBuffer=function(){return this.buffer.slice(0,this.position)};function max(a,b){return a>b?a:b}types.Writer.prototype.ensure=function(length){if(this.buffer.length<length){var bigger=new Buffer(max(this.buffer.length*2,length));this.buffer.copy(bigger);this.buffer=bigger}};types.Writer.prototype.write_typecode=function(code){this.write_uint(code,1)};types.Writer.prototype.write_uint=function(val
ue,width){var current=this.position;this.ensure(this.position+width);this.position+=width;var name=width>1?"writeUInt"+width*8+"BE":"writeUInt"+8;if(!this.buffer[name]){throw Error("Buffer doesn't define "+name)}return this.buffer[name](value,current)};types.Writer.prototype.write_fixed_width=function(type,value){var current=this.position;this.ensure(this.position+type.width);this.position+=type.width;if(type.write){type.write(this.buffer,value,current)}else if(value.copy){value.copy(this.buffer,current)}else{throw Error("Can't handle write for "+type)}};types.Writer.prototype.write_variable_width=function(type,value){var source=type.encoding?new Buffer(value,type.encoding):new Buffer(value);this.write_uint(source.length,type.width);this.write_bytes(source)};types.Writer.prototype.write_bytes=function(source){var current=this.position;this.ensure(this.position+source.length);this.position+=source.length;source.copy(this.buffer,current)};types.Writer.prototype.write_constructor=funct
ion(typecode,descriptor){if(descriptor){this.write_typecode(0);this.write(descriptor)}this.write_typecode(typecode)};types.Writer.prototype.write=function(o){if(!(o instanceof Typed)){throw Error("Can't write "+JSON.stringify(o))}this.write_constructor(o.type.typecode,o.descriptor);this.write_value(o.type,o.value,o.array_constructor)};types.Writer.prototype.write_value=function(type,value,constructor){if(type.width===0){return}else if(type.category==="fixed"){this.write_fixed_width(type,value)}else if(type.category==="variable"){this.write_variable_width(type,value)}else if(type.category==="compound"){this.write_compound(type,value)}else if(type.category==="array"){this.write_array(type,value,constructor)}else{throw Error("Invalid category "+type.category+" for type: "+type)}};types.Writer.prototype.backfill_size=function(width,saved){var gap=this.position-saved;this.position=saved;this.write_uint(gap-width,width);this.position+=gap-width};types.Writer.prototype.write_compound=funct
ion(type,value){var saved=this.position;this.position+=type.width;this.write_uint(value.length,type.width);for(var i=0;i<value.length;i++){if(value[i]===undefined||value[i]===null){this.write(new types.Null)}else{this.write(value[i])}}this.backfill_size(type.width,saved)};types.Writer.prototype.write_array=function(type,value,constructor){var saved=this.position;this.position+=type.width;this.write_uint(value.length,type.width);this.write_constructor(constructor.typecode,constructor.descriptor);var type=get_type(constructor.typecode);for(var i=0;i<value.length;i++){this.write_value(type,value[i])}this.backfill_size(type.width,saved)};types.Writer.prototype.toString=function(){var s="buffer@"+this.position;if(this.position)s+=": ";for(var i=0;i<this.position;i++){if(i>0)s+=",";s+=("00"+Number(this.buffer[i]).toString(16)).slice(-2)}return s};types.Writer.prototype.skip=function(bytes){this.ensure(this.position+bytes);this.position+=bytes};types.Writer.prototype.clear=function(){this.
buffer.fill(0);this.position=0};types.Writer.prototype.remaining=function(){return this.buffer.length-this.position};function get_constructor(typename){if(typename==="symbol"){return{typecode:types.Sym8.typecode}}throw Error("TODO: Array of type "+typename+" not yet supported")}function wrap_field(definition,instance){if(instance!==undefined&&instance!==null){if(Array.isArray(instance)){if(!definition.multiple){throw Error("Field "+definition.name+" does not support multiple values, got "+JSON.stringify(instance))}var constructor=get_constructor(definition.type);return types.wrap_array(instance,constructor.typecode,constructor.descriptor)}else if(definition.type==="*"){return instance}else{var wrapper=types["wrap_"+definition.type];if(wrapper){return wrapper(instance)}else{throw Error("No wrapper for field "+definition.name+" of type "+definition.type)}}}else if(definition.mandatory){throw Error("Field "+definition.name+" is mandatory")}else{return new types.Null}}function get_acces
sors(index,field_definition){var getter=function(){return field_definition.type==="*"?this.value[index]:types.unwrap(this.value[index])};var setter=function(o){this.value[index]=wrap_field(field_definition,o)};return{get:getter,set:setter,enumerable:true,configurable:false}}types.define_composite=function(def){var c=function(fields){this.value=fields?fields:[]};c.descriptor={numeric:def.code,symbolic:"amqp:"+def.name+":list"};c.prototype.dispatch=function(target,frame){target["on_"+def.name](frame)};for(var i=0;i<def.fields.length;i++){var f=def.fields[i];Object.defineProperty(c.prototype,f.name,get_accessors(i,f))}c.toString=function(){return def.name+"#"+Number(def.code).toString(16)};c.prototype.toJSON=function(){var o={};for(var f in this){if(f!=="value"&&this[f]){o[f]=this[f]}}return o};c.create=function(fields){var o=new c;for(var f in fields){o[f]=fields[f]}return o};c.prototype.described=function(fields){return types.described(types.wrap_ulong(c.descriptor.numeric),types.wra
p_list(this.value))};return c};function add_type(def){var c=types.define_composite(def);types["wrap_"+def.name]=function(fields){return c.create(fields).described()};by_descriptor[Number(c.descriptor.numeric).toString(10)]=c;by_descriptor[c.descriptor.symbolic]=c}add_type({name:"error",code:29,fields:[{name:"condition",type:"symbol",mandatory:true},{name:"description",type:"string"},{name:"info",type:"map"}]});module.exports=types}).call(this,require("buffer").Buffer)},{buffer:19}],13:[function(require,module,exports){"use strict";var util={};util.generate_uuid=function(){var uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=Math.random()*16|0,v=c=="x"?r:r&3|8;return v.toString(16)});return uuid};util.clone=function(o){var copy=Object.create(o.prototype||{});var names=Object.getOwnPropertyNames(o);for(var i=0;i<names.length;i++){var key=names[i];copy[key]=o[key]}return copy};module.exports=util},{}],14:[function(require,module,exports){(function(Buffer){"
use strict";function nulltransform(data){return data}function from_arraybuffer(data){if(data instanceof ArrayBuffer)return new Buffer(new Uint8Array(data));else return new Buffer(data)}function to_typedarray(data){return new Uint8Array(data)}function wrap(ws){var data_recv=nulltransform;var data_send=nulltransform;if(ws.binaryType){ws.binaryType="arraybuffer";data_recv=from_arraybuffer;data_send=to_typedarray}return{end:function(){ws.close()},write:function(data){try{ws.send(data_send(data),{binary:true})}catch(e){ws.onerror(e)}},on:function(event,handler){if(event==="data"){ws.onmessage=function(msg_evt){handler(data_recv(msg_evt.data))}}else if(event==="end"){ws.onclose=handler}else if(event==="error"){ws.onerror=handler}else{console.log("ERROR: Attempt to set unrecognised handler on websocket wrapper: "+event)}},get_id_string:function(){return ws.url}}}module.exports={connect:function(Impl){return function(url,protocols,options){return function(){return{connect:function(port_igno
re,host_ignore,options_ignore,callback){v
<TRUNCATED>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org