From af670273c453705103e4d95b2ca5d44ddb52357d Mon Sep 17 00:00:00 2001 From: cybafelo Date: Tue, 19 Nov 2019 15:06:49 +0100 Subject: [PATCH] event updates - query uipdate --- src/r3-a-2-event-0.js | 233 +++++------------- src/r3-a-2-event-1.js | 128 +++++----- src/r3-a-3-api-component.js | 1 + src/r3-a-3-utils.js | 22 ++ src/r3-a-4-component.js | 88 ++++--- src/r3-api-graph-table.js | 5 + src/r3-api-query-0.js | 5 + src/r3-api-query-alerts-firstTimeLogin-0.js | 2 +- src/r3-api-query-alerts-timeseries.js | 7 +- src/r3-api-query-logins-0.js | 2 +- src/r3-d3-raycaster.js | 3 + src/r3-d3-viewport-fixedAspect-0.js | 24 ++ src/r3-entityManager.js | 39 +-- src/r3-graph-barchart-stacked.js | 1 + src/r3-query-0.js | 18 +- src/r3-query-alerts-0.js | 6 + src/r3-query-alerts-buckets.js | 6 +- src/r3-query-alerts-firstTimeLogin-0.js | 4 + ...uery-alerts-firstTimeLogin-applications.js | 11 +- src/r3-query-alerts-firstTimeLogin-devices.js | 13 +- src/r3-query-alerts-firstTimeLogin-vpn.js | 2 + src/r3-query-alerts-list.js | 54 +++- src/r3-query-alerts-summary.js | 5 +- src/r3-query-alerts-timeseries.js | 68 ++++- src/r3-query-devices-0.js | 1 + src/r3-query-devices-known.js | 1 + src/r3-query-devices-sql.js | 23 +- src/r3-query-devices-unknown.js | 1 + src/r3-query-logins-0.js | 6 + src/r3-query-logins-applications.js | 7 + src/r3-query-logins-devices.js | 13 +- src/r3-query-logins-vpn.js | 1 + src/r3-query-userDevices-0.js | 3 +- src/r3-query-users.js | 16 +- src/r3-renderer-d3-0.js | 4 +- src/r3-renderer-d3-canvas-0.js | 2 +- src/r3-runtime-graphics-chart.js | 12 +- src/r3-runtime-graphics-google.js | 187 +++++++++++++- src/r3-system-input.js | 1 + src/r3-system-query.js | 34 +++ src/r3-system-storage.js | 87 ++++--- src/r3-vector3.js | 24 ++ 42 files changed, 786 insertions(+), 384 deletions(-) diff --git a/src/r3-a-2-event-0.js b/src/r3-a-2-event-0.js index 442ac47..d8784a2 100644 --- a/src/r3-a-2-event-0.js +++ b/src/r3-a-2-event-0.js @@ -10,7 +10,6 @@ R3.Event = function() { * @type {{}} */ R3.Event.Subscriptions = {}; -R3.Event.OnceSubscriptions = {}; /** * Subscribe to some events @@ -24,46 +23,6 @@ R3.Event.prototype.subscribe = function( return R3.Event.Subscribe(eventName, callback.bind(this)); }; - -// /** -// * Stop listening for this event after the callback returns true -// * @param eventName -// * @param callback -// * @returns {{fn, remove: remove}} -// */ -// R3.Event.prototype.subscribeOnce = function( -// eventName, -// callback -// ) { -// throw new Error('implement first properly'); -// // var fn = callback.bind(this); -// // -// // if (R3.Event.OnceSubscriptions.hasOwnProperty(eventName)) { -// // R3.Event.OnceSubscriptions[eventName].push(fn); -// // } else { -// // R3.Event.OnceSubscriptions[eventName] = []; -// // R3.Event.OnceSubscriptions[eventName].push(fn); -// // } -// // -// // /** -// // * Return a handle to the caller to allow us to unsubscribe to this event -// // */ -// // return { -// // fn : fn, -// // remove : function() { -// // R3.Event.Subscriptions[eventName].splice( -// // R3.Event.Subscriptions[eventName].indexOf(fn), -// // 1 -// // ); -// // } -// // } -// }; - -/** - * - * @param eventName - * @param data - */ /** * Publish some event happened with some data * @param eventName @@ -87,8 +46,8 @@ R3.Event.prototype.emit = function( }; /** - * Static method call - * @param eventName + * Static Synchrnonous Event - Calls clientCallback directly after the event result is obtained + * @param eventId * @param data * @param clientCallback is executed ideally when the event completed * @param clientErrorCallback @@ -96,111 +55,41 @@ R3.Event.prototype.emit = function( * @constructor */ R3.Event.Emit = function( - eventName, + eventId, data, clientCallback, clientErrorCallback ) { - var count = 0; + if (R3.Event.Subscriptions.hasOwnProperty(eventId)) { - if (R3.Event.Subscriptions.hasOwnProperty(eventName)) { + var subscriptionIds = Object.keys(R3.Event.Subscriptions[eventId]); - if (R3.Event.Subscriptions[eventName].length === 0) { - - if (clientCallback) { - /** - * We execute the client callback immediately since there are no subscriptions to this event - */ - clientCallback(); - } - - if (clientErrorCallback) { - clientErrorCallback({ - message : 'No subscriptions for event ' + eventName - }) - } - } - - /** - * We need to execute all the callbacks, but not execute them twice, but also keep in mind they can remove - * themselves during execution - */ - // var length = R3.Event.Subscriptions[eventName].length; - // - // for (var i = 0; i < length; i++) { - // - // var object = R3.Event.Subscriptions[eventName][i]; - // - // if (object.fn && object.executed === false) { - // object.fn(data, clientCallback, clientErrorCallback); - // object.executed = true; - // } - // - // if (length !== R3.Event.Subscriptions[eventName].length) { - // /** - // * this callback removed a subscription - reset i and reset the length - // */ - // i = 0; - // length = R3.Event.Subscriptions[eventName].length; - // } - // } - // - // R3.Event.Subscriptions[eventName].map( - // function(object){ - // object.executed = false; - // } - // ) - - R3.Event.Subscriptions[eventName].map( - function(subscription) { - if (subscription) { - - try { - var result = subscription(data, clientCallback, clientErrorCallback); - } catch (error) { - - if (clientErrorCallback) { - try { - clientErrorCallback(error); - } catch (error2) { - console.error('failed to execute client callback error:', error2); - } - } - - return; - } + subscriptionIds.map( + function(subscriptionId) { + try { + var result = R3.Event.Subscriptions[eventId][subscriptionId](data); if (clientCallback) { clientCallback(result); } - count++; + } catch (error) { + if (clientErrorCallback) { + clientErrorCallback(error); + } else { + console.error(error); + } } } ) - } else { - if (clientCallback) { - /** - * We execute the client callback immediately since there are no subscriptions to this event - */ - clientCallback(); - } - - if (clientErrorCallback) { - clientErrorCallback({ - message : 'No subscriptions for event ' + eventName - }) - } } - - return count; }; /** * Execute the functions which subscribe to this event, but don't process the client callback - the subscription function * should execute the client callback - * @param eventName + * @param eventId * @param data * @param clientCallback * @param clientErrorCallback @@ -208,76 +97,78 @@ R3.Event.Emit = function( * @constructor */ R3.Event.Async = function( - eventName, + eventId, data, clientCallback, clientErrorCallback ) { + if (R3.Event.Subscriptions.hasOwnProperty(eventId)) { - var count = 0; + var subscriptionIds = Object.keys(R3.Event.Subscriptions[eventId]); - if (R3.Event.Subscriptions.hasOwnProperty(eventName)) { - R3.Event.Subscriptions[eventName].map( - function(subscription) { - if (subscription) { - subscription(data, clientCallback, clientErrorCallback); - count++; + subscriptionIds.map( + function(subscriptionId) { + try { + R3.Event.Subscriptions[eventId][subscriptionId](data, clientCallback, clientErrorCallback); + } catch (error) { + if (clientErrorCallback) { + clientErrorCallback(error); + } else { + console.error(error); + } } } ) } - - return count; }; R3.Event.Subscribe = function( eventName, - fn + fn, ) { + /** + * Todo - maybe eventually store a boolean which indicates if the function has been executed + */ + var subscriptionId = R3.Utils.RandomId(10); if (R3.Event.Subscriptions.hasOwnProperty(eventName)) { - R3.Event.Subscriptions[eventName].push(fn); - // { - // fn : fn, - // executed : false - // } - // ); + + if (R3.Event.Subscriptions[eventName][subscriptionId]) { + throw new Error('A component can only subscribe to a particular event ID once'); + } + + R3.Event.Subscriptions[eventName][subscriptionId] = fn; } else { - R3.Event.Subscriptions[eventName] = []; - R3.Event.Subscriptions[eventName].push(fn); - // { - // fn : fn, - // executed : false - // } - // ); + R3.Event.Subscriptions[eventName] = {}; + R3.Event.Subscriptions[eventName][subscriptionId] = fn; } /** * Return a handle to the caller to allow us to unsubscribe to this event */ return { - fn : fn, - remove : function() { + fn: fn, + remove: function (eventId, subscriptionId) { - var index = R3.Event.Subscriptions[eventName].indexOf(fn); - // reduce( - // function(result, object, index) { - // if (object.fn === fn) { - // result = index; - // } - // return result; - // }, - // -1 - // ); + return function () { - if (index === -1) { - throw new Error('could not remove subscription'); + /** + * Stop listening for this event from this component + */ + delete R3.Event.Subscriptions[eventId][subscriptionId]; + + /** + * If the length of listeners is 0, stop referencing this event + * @type {string[]} + */ + var listeners = Object.keys(R3.Event.Subscriptions[eventId]); + if (listeners.length === 0) { + delete R3.Event.Subscriptions[eventId]; + } } - R3.Event.Subscriptions[eventName].splice( - index, - 1 - ); - } - } + }(eventName, subscriptionId), + subscriptionId : subscriptionId + }; + }; \ No newline at end of file diff --git a/src/r3-a-2-event-1.js b/src/r3-a-2-event-1.js index b1b77c7..f575341 100644 --- a/src/r3-a-2-event-1.js +++ b/src/r3-a-2-event-1.js @@ -84,37 +84,40 @@ R3.Event.PAUSE = 0x53; R3.Event.PAUSE_ALL_AUDIO = 0x54; R3.Event.PLAY_AUDIO = 0x55; R3.Event.PROJECT_LOADED = 0x56; -R3.Event.QUERY_PARSED = 0x57; -R3.Event.RECEIVE_DESTINATION_CHANGED = 0x58; -R3.Event.REGISTER_DEPENDENCIES = 0x59; -R3.Event.REGISTER_UPDATE = 0x5a; -R3.Event.REMOVE_COMPONENT = 0x5b; -R3.Event.REMOVE_MESH = 0x5c; -R3.Event.REMOVE_PARTICLE_ENGINE = 0x5d; -R3.Event.RENDERER_SIZE_CHANGE = 0x5e; -R3.Event.REPLACE_COMPONENT = 0x5f; -R3.Event.RESOLVE_DEPENDENCIES = 0x60; -R3.Event.RESTART = 0x61; -R3.Event.SAVE_COMPONENT = 0x62; -R3.Event.SAVE_COMPONENT_ERROR = 0x63; -R3.Event.SAVING = 0x64; -R3.Event.SELECTION_MODE_CHANGE = 0x65; -R3.Event.SIGN_IN = 0x66; -R3.Event.SIGN_OUT = 0x67; -R3.Event.START = 0x68; -R3.Event.STOP_ALL_AUDIO = 0x69; -R3.Event.STOP_AUDIO = 0x6a; -R3.Event.STOP_VISUALIZE = 0x6b; -R3.Event.TEXTURE_ANIMATED_CHANGE = 0x6c; -R3.Event.TEXTURE_INSTANCE_UPDATED = 0x6d; -R3.Event.TOUCH_CANCEL = 0x6e; -R3.Event.TOUCH_END = 0x6f; -R3.Event.TOUCH_MOVE = 0x70; -R3.Event.TOUCH_START = 0x71; -R3.Event.UNRESOLVED_DEPENDENCIES_UPDATE = 0x72; -R3.Event.VISUALIZE = 0x73; -R3.Event.WINDOW_RESIZE = 0x74; -R3.Event.MAX_EVENTS = 0x75; +R3.Event.QUERY = 0x57; +R3.Event.QUERY_INTERVAL_CHANGE = 0x58; +R3.Event.QUERY_PARSED = 0x59; +R3.Event.RECEIVE_DESTINATION_CHANGED = 0x5a; +R3.Event.REGISTER_COMPONENT = 0x5b; +R3.Event.REGISTER_DEPENDENCIES = 0x5c; +R3.Event.REGISTER_UPDATE = 0x5d; +R3.Event.REMOVE_COMPONENT = 0x5e; +R3.Event.REMOVE_MESH = 0x5f; +R3.Event.REMOVE_PARTICLE_ENGINE = 0x60; +R3.Event.RENDERER_SIZE_CHANGE = 0x61; +R3.Event.REPLACE_COMPONENT = 0x62; +R3.Event.RESOLVE_DEPENDENCIES = 0x63; +R3.Event.RESTART = 0x64; +R3.Event.SAVE_COMPONENT = 0x65; +R3.Event.SAVE_COMPONENT_ERROR = 0x66; +R3.Event.SAVING = 0x67; +R3.Event.SELECTION_MODE_CHANGE = 0x68; +R3.Event.SIGN_IN = 0x69; +R3.Event.SIGN_OUT = 0x6a; +R3.Event.START = 0x6b; +R3.Event.STOP_ALL_AUDIO = 0x6c; +R3.Event.STOP_AUDIO = 0x6d; +R3.Event.STOP_VISUALIZE = 0x6e; +R3.Event.TEXTURE_ANIMATED_CHANGE = 0x6f; +R3.Event.TEXTURE_INSTANCE_UPDATED = 0x70; +R3.Event.TOUCH_CANCEL = 0x71; +R3.Event.TOUCH_END = 0x72; +R3.Event.TOUCH_MOVE = 0x73; +R3.Event.TOUCH_START = 0x74; +R3.Event.UNRESOLVED_DEPENDENCIES_UPDATE = 0x75; +R3.Event.VISUALIZE = 0x76; +R3.Event.WINDOW_RESIZE = 0x77; +R3.Event.MAX_EVENTS = 0x78; /** * R3.Event.GetEventName @@ -211,36 +214,39 @@ R3.Event.GetEventName = function(eventId) { case 0x54 : return 'pause_all_audio'; case 0x55 : return 'play_audio'; case 0x56 : return 'project_loaded'; - case 0x57 : return 'query_parsed'; - case 0x58 : return 'receive_destination_changed'; - case 0x59 : return 'register_dependencies'; - case 0x5a : return 'register_update'; - case 0x5b : return 'remove_component'; - case 0x5c : return 'remove_mesh'; - case 0x5d : return 'remove_particle_engine'; - case 0x5e : return 'renderer_size_change'; - case 0x5f : return 'replace_component'; - case 0x60 : return 'resolve_dependencies'; - case 0x61 : return 'restart'; - case 0x62 : return 'save_component'; - case 0x63 : return 'save_component_error'; - case 0x64 : return 'saving'; - case 0x65 : return 'selection_mode_change'; - case 0x66 : return 'sign_in'; - case 0x67 : return 'sign_out'; - case 0x68 : return 'start'; - case 0x69 : return 'stop_all_audio'; - case 0x6a : return 'stop_audio'; - case 0x6b : return 'stop_visualize'; - case 0x6c : return 'texture_animated_change'; - case 0x6d : return 'texture_instance_updated'; - case 0x6e : return 'touch_cancel'; - case 0x6f : return 'touch_end'; - case 0x70 : return 'touch_move'; - case 0x71 : return 'touch_start'; - case 0x72 : return 'unresolved_dependencies_update'; - case 0x73 : return 'visualize'; - case 0x74 : return 'window_resize'; + case 0x57 : return 'query'; + case 0x58 : return 'query_interval_change'; + case 0x59 : return 'query_parsed'; + case 0x5a : return 'receive_destination_changed'; + case 0x5b : return 'register_component'; + case 0x5c : return 'register_dependencies'; + case 0x5d : return 'register_update'; + case 0x5e : return 'remove_component'; + case 0x5f : return 'remove_mesh'; + case 0x60 : return 'remove_particle_engine'; + case 0x61 : return 'renderer_size_change'; + case 0x62 : return 'replace_component'; + case 0x63 : return 'resolve_dependencies'; + case 0x64 : return 'restart'; + case 0x65 : return 'save_component'; + case 0x66 : return 'save_component_error'; + case 0x67 : return 'saving'; + case 0x68 : return 'selection_mode_change'; + case 0x69 : return 'sign_in'; + case 0x6a : return 'sign_out'; + case 0x6b : return 'start'; + case 0x6c : return 'stop_all_audio'; + case 0x6d : return 'stop_audio'; + case 0x6e : return 'stop_visualize'; + case 0x6f : return 'texture_animated_change'; + case 0x70 : return 'texture_instance_updated'; + case 0x71 : return 'touch_cancel'; + case 0x72 : return 'touch_end'; + case 0x73 : return 'touch_move'; + case 0x74 : return 'touch_start'; + case 0x75 : return 'unresolved_dependencies_update'; + case 0x76 : return 'visualize'; + case 0x77 : return 'window_resize'; default : throw new Error('Event type not defined : ' + eventId); } diff --git a/src/r3-a-3-api-component.js b/src/r3-a-3-api-component.js index 8358b99..9421d7f 100644 --- a/src/r3-a-3-api-component.js +++ b/src/r3-a-3-api-component.js @@ -5,6 +5,7 @@ * @param name * @param register * @param selected + * @param isPublic * @constructor */ R3.API.Component = function( diff --git a/src/r3-a-3-utils.js b/src/r3-a-3-utils.js index 398eb18..25859f6 100644 --- a/src/r3-a-3-utils.js +++ b/src/r3-a-3-utils.js @@ -25,6 +25,28 @@ R3.Utils.GetFirstParent = function(object, constructor) { }; +R3.Utils.SyntaxHighlight = function(json) { + if (typeof json != 'string') { + json = JSON.stringify(json, undefined, 2); + } + json = json.replace(/&/g, '&').replace(//g, '>'); + return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) { + var cls = 'number'; + if (/^"/.test(match)) { + if (/:$/.test(match)) { + cls = 'key'; + } else { + cls = 'string'; + } + } else if (/true|false/.test(match)) { + cls = 'boolean'; + } else if (/null/.test(match)) { + cls = 'null'; + } + return '' + match + ''; + }); +}; + R3.Utils.GetParentProject = function(component) { if (R3.Utils.UndefinedOrNull(component.parent)) { diff --git a/src/r3-a-4-component.js b/src/r3-a-4-component.js index 32bf9ea..6df92c3 100644 --- a/src/r3-a-4-component.js +++ b/src/r3-a-4-component.js @@ -30,6 +30,17 @@ R3.Component = function() { this.instanceCreated.bind(this) ); + /** + * This component, no doubt - is a parent to some other components. + * We register this component with the EntityManager, so it can link the parent property of all + * this component's child components to this + */ + + R3.Event.Emit( + R3.Event.REGISTER_COMPONENT, + this + ); + this.buildVectoredComponents(); this.buildLinkedComponents(); @@ -198,7 +209,7 @@ R3.Component.prototype.instanceCreated = function(data) { /** * Ignore components with no parent */ - if (data.component.parent === null) { + if (R3.Utils.UndefinedOrNull(data.component.parent)) { return; } @@ -361,6 +372,7 @@ R3.Component.prototype.buildLinkedComponents = function() { */ this[property] = this[property].reduce( + function (component, _property) { return function (result, item, index) { @@ -379,7 +391,7 @@ R3.Component.prototype.buildLinkedComponents = function() { componentId: item, }, function (__component, __property, __index, __id, __dependencyString) { - return function (data) { + return function (rawComponent) { if (R3.Utils.UndefinedOrNull(__component[__property])) { throw new Error('The component took too long to load and the component property was damaged: ' + R3.GetComponentName(__component) + '.' + __property); @@ -393,7 +405,9 @@ R3.Component.prototype.buildLinkedComponents = function() { throw new Error('The component loaded however it no longer exists as an id: ' + R3.GetComponentName(__component) + '.' + __property + '[' + __index + '] !==' + __id); } - __component[__property][__index] = data.component; + var Constructor = R3.GetConstructorFromComponentType(rawComponent.componentType); + + __component[__property][__index] = new Constructor(rawComponent); var deleteIndex = __component.dependencies.indexOf(__dependencyString); @@ -410,12 +424,12 @@ R3.Component.prototype.buildLinkedComponents = function() { } } - }(this, _property, index, item, dependencyString), - function (component, __property) { - return function (error) { - console.error('Failed to load ' + R3.GetComponentName(component) + '.' + __property + ' because of ' + error); + }(component, _property, index, item, dependencyString), + function (__component, __property) { + return function (__error) { + console.error('Failed to load ' + R3.GetComponentName(__component) + '.' + __property + ' because of ' + __error); }; - }(this, _property) + }(component, _property) ); result.push(item); @@ -474,6 +488,7 @@ R3.Component.prototype.buildLinkedComponents = function() { throw new Error('Unhandled situation - could not process : ' + R3.GetComponentName(component) + '.' + _property + '[' + index + ']'); }; + }(this, property), [] ); @@ -489,7 +504,7 @@ R3.Component.prototype.buildLinkedComponents = function() { /** * This object is not loaded yet - we should notify (a storage system perhaps) that it should be loaded and add it as a dependency */ - var dependencyString = R3.GetComponentName(component) + '.' + _property + '(' + this[property] + ')'; + var dependencyString = R3.GetComponentName(this) + '.' + property + '(' + this[property] + ')'; R3.Utils.PushUnique(this.dependencies, dependencyString); R3.Event.Async( @@ -497,36 +512,40 @@ R3.Component.prototype.buildLinkedComponents = function() { { componentId: this[property], }, - function (component, _property, _id, _dependencyString) { - return function (data) { + function (__component, __property, __id, __dependencyString) { - if (R3.Utils.UndefinedOrNull(component[_property])) { - throw new Error('The component took too long to load and the component property was damaged: ' + R3.GetComponentName(component) + '.' + _property); + return function (rawComponent) { + + if (R3.Utils.UndefinedOrNull(__component[__property])) { + throw new Error('The component took too long to load and the component property was damaged: ' + R3.GetComponentName(__component) + '.' + __property); } - if (component[_property] !== _id) { - throw new Error('The component loaded however it no longer exists as an id: ' + R3.GetComponentName(component) + '.' + _property + ' !==' + _id); + if (__component[__property] !== __id) { + throw new Error('The component loaded however it no longer exists as an id: ' + R3.GetComponentName(__component) + '.' + __property + ' !==' + __id); } - component[_property] = data.component; + var Constructor = R3.GetConstructorFromComponentType(rawComponent.componentType); - var deleteIndex = component.dependencies.indexOf(_dependencyString); + __component[__property] = new Constructor(rawComponent); + + var deleteIndex = __component.dependencies.indexOf(__dependencyString); if (deleteIndex === -1) { - throw new Error('The dependency ' + _dependencyString + ' was removed during the time that the component was loading'); + throw new Error('The dependency ' + __dependencyString + ' was removed during the time that the component was loading'); } - component.dependencies = component.dependencies.splice(deleteIndex, 1); + __component.dependencies = __component.dependencies.splice(deleteIndex, 1); - if (component.dependencies.length === 0) { - component.performInstanceCreation(); + if (__component.dependencies.length === 0) { + __component.performInstanceCreation(); } } + }(this, property, this[property], dependencyString), - function (component, _property) { - return function (error) { - console.error('Failed to load ' + R3.GetComponentName(component) + '.' + _property + ' because of ' + error); + function (__component, __property) { + return function (__error) { + console.error('Failed to load ' + R3.GetComponentName(__component) + '.' + __property + ' because of ' + __error); }; }(this, property) ); @@ -623,17 +642,6 @@ R3.Component.prototype.createInstance = function() { this.loaded = true; - /** - * Use this event to know that the object has now loaded and all 'INSTANCE_CREATED' events have been handled. - * The idToObject property of this component can now be trusted. - */ - R3.Event.Emit( - R3.Event.INSTANCE_LOADED, - { - component: this - } - ); - if (this instanceof R3.Project) { R3.Event.Emit( R3.Event.PROJECT_LOADED, @@ -652,6 +660,16 @@ R3.Component.prototype.createInstance = function() { ) } + /** + * Use this event to know that the object has now loaded and all 'INSTANCE_CREATED' events have been handled. + * The idToObject property of this component can now be trusted. + */ + R3.Event.Emit( + R3.Event.INSTANCE_LOADED, + { + component: this + } + ); }; R3.Component.prototype.updateInstance = function(property) { diff --git a/src/r3-api-graph-table.js b/src/r3-api-graph-table.js index a0094ed..54b528f 100644 --- a/src/r3-api-graph-table.js +++ b/src/r3-api-graph-table.js @@ -27,6 +27,11 @@ R3.API.Graph.Table = function( } this.rows = apiComponent.rows; + if (R3.Utils.UndefinedOrNull(apiComponent.pageSize)) { + apiComponent.pageSize = 10; + } + this.pageSize = apiComponent.pageSize; + }; R3.API.Graph.Table.prototype = Object.create(R3.API.Graph.prototype); diff --git a/src/r3-api-query-0.js b/src/r3-api-query-0.js index 97eb32a..092c2de 100644 --- a/src/r3-api-query-0.js +++ b/src/r3-api-query-0.js @@ -52,6 +52,10 @@ R3.API.Query = function( } this.httpMethod = apiComponent.httpMethod; + if (R3.Utils.UndefinedOrNull(apiComponent.tooltips)) { + apiComponent.tooltips = []; + } + this.tooltips = apiComponent.tooltips; }; R3.API.Query.prototype = Object.create(R3.API.Component.prototype); @@ -61,6 +65,7 @@ R3.API.Query.QUERY_SIZE = 'QUERY_SIZE'; R3.API.Query.QUERY_START = 'QUERY_START'; R3.API.Query.QUERY_END = 'QUERY_END'; R3.API.Query.QUERY_TIMEZONE = 'QUERY_TIMEZONE'; +R3.API.Query.QUERY_TIME_INTERVAL = 'QUERY_TIME_INTERVAL'; R3.API.Query.QUERY_BUCKET_FIELD = 'QUERY_BUCKET_FIELD'; R3.API.Query.QUERY_LOGIN_TYPE = 'QUERY_LOGIN_TYPE'; R3.API.Query.QUERY_ACKNOWLEDGED = 'QUERY_ACKNOWLEDGED'; diff --git a/src/r3-api-query-alerts-firstTimeLogin-0.js b/src/r3-api-query-alerts-firstTimeLogin-0.js index 9d5b997..6e1854c 100644 --- a/src/r3-api-query-alerts-firstTimeLogin-0.js +++ b/src/r3-api-query-alerts-firstTimeLogin-0.js @@ -47,7 +47,7 @@ R3.API.Query.Alerts.FirstTimeLogin = function( ' "term" : { "alert_type.keyword": "First Time Login" }\n' + ' },\n' + ' {\n' + - ' "regexp" : { "login.login_type.keyword": "' + R3.API.Query.QUERY_LOGIN_TYPE + '" }\n' + + ' "regexp" : { "login.type.keyword": "' + R3.API.Query.QUERY_LOGIN_TYPE + '" }\n' + ' }\n' + ' ]\n' + ' }\n' + diff --git a/src/r3-api-query-alerts-timeseries.js b/src/r3-api-query-alerts-timeseries.js index 2ca752a..f2d311c 100644 --- a/src/r3-api-query-alerts-timeseries.js +++ b/src/r3-api-query-alerts-timeseries.js @@ -28,7 +28,7 @@ R3.API.Query.Alerts.Timeseries = function( ' "mins": {\n' + ' "date_histogram": {\n' + ' "field": "timestamp",\n' + - ' "calendar_interval": "1d",\n' + + ' "calendar_interval": "' + R3.API.Query.QUERY_TIME_INTERVAL + '",\n' + ' "time_zone": "' + R3.API.Query.QUERY_TIMEZONE + '",\n' + ' "min_doc_count": 0,\n' + ' "format" : "yyyy-MM-dd"\n' + @@ -63,6 +63,11 @@ R3.API.Query.Alerts.Timeseries = function( } this.text = apiComponent.text; + if (R3.Utils.UndefinedOrNull(apiComponent.timeInterval)) { + apiComponent.timeInterval = '1d'; + } + this.timeInterval = apiComponent.timeInterval; + R3.API.Query.Alerts.call( this, apiComponent diff --git a/src/r3-api-query-logins-0.js b/src/r3-api-query-logins-0.js index cf80175..2817804 100644 --- a/src/r3-api-query-logins-0.js +++ b/src/r3-api-query-logins-0.js @@ -46,7 +46,7 @@ R3.API.Query.Logins = function( ' }\n' + ' },\n' + ' {\n' + - ' "regexp" : { "login_type.keyword": "(' + R3.API.Query.QUERY_LOGIN_TYPE + ')" }\n' + + ' "regexp" : { "type.keyword": "(' + R3.API.Query.QUERY_LOGIN_TYPE + ')" }\n' + ' }\n' + ' ]\n' + ' }\n' + diff --git a/src/r3-d3-raycaster.js b/src/r3-d3-raycaster.js index f49e953..ae4f010 100644 --- a/src/r3-d3-raycaster.js +++ b/src/r3-d3-raycaster.js @@ -9,6 +9,9 @@ R3.D3.Raycaster = function( __RUNTIME_COMPONENT__; + this.linkedComponents.position = R3.Vector3; + this.linkedComponents.direction = R3.Vector3; + __UPGRADE_TO_RUNTIME__; }; diff --git a/src/r3-d3-viewport-fixedAspect-0.js b/src/r3-d3-viewport-fixedAspect-0.js index a514ab0..f531e6a 100644 --- a/src/r3-d3-viewport-fixedAspect-0.js +++ b/src/r3-d3-viewport-fixedAspect-0.js @@ -28,6 +28,30 @@ R3.D3.Viewport.FixedAspect.prototype.constructor = R3.D3.Viewport.FixedAspect; R3.D3.Viewport.FixedAspect.prototype.createInstance = function() { + /** + * We have a dependency on our parent which could still need to call 'createInstance' + */ + + // if (typeof this.parent === 'string') { + // + // if (R3.Utils.UndefinedOrNull(this.instanceLoaded)) { + // + // this.instanceLoaded = R3.Event.Subscribe( + // R3.Event.INSTANCE_LOADED, + // function (data) { + // if (data.component.id === this.parent) { + // this.parent = data.component; + // this.createInstance(); + // this.instanceLoaded.remove(); + // } + // }.bind(this) + // ); + // + // } + // + // return; + // } + this.calculateDimensions(); this.instance = this.graphics.Vector4( diff --git a/src/r3-entityManager.js b/src/r3-entityManager.js index 94ee58e..4d67201 100644 --- a/src/r3-entityManager.js +++ b/src/r3-entityManager.js @@ -19,11 +19,6 @@ R3.EntityManager = function( this.instanceDisposal = []; - R3.Event.Subscribe( - R3.Event.INSTANCE_CREATED, - this.instanceCreated.bind(this) - ); - R3.Event.Subscribe( R3.Event.REMOVE_COMPONENT, this.removeComponent.bind(this) @@ -32,6 +27,11 @@ R3.EntityManager = function( R3.Event.Subscribe( R3.Event.INSTANCE_DISPOSAL, this.removeInstances.bind(this) + ); + + R3.Event.Subscribe( + R3.Event.REGISTER_COMPONENT, + this.registerComponent.bind(this) ) // R3.Event.Subscribe( @@ -42,24 +42,35 @@ R3.EntityManager = function( }; -R3.EntityManager.prototype.instanceCreated = function(data) { +R3.EntityManager.prototype.registerComponent = function(component) { /** - * Register this component in componentType to Component register + * Register this component in the componentType to component register */ - if (R3.Utils.UndefinedOrNull(this.register[data.component.componentType])) { - this.register[data.component.componentType] = {}; + if (R3.Utils.UndefinedOrNull(this.register[component.componentType])) { + this.register[component.componentType] = {}; } - if (R3.Utils.UndefinedOrNull(this.register[data.component.componentType][data.component.id])) { - this.register[data.component.componentType][data.component.id] = data.component; + this.register[component.componentType][component.id] = component; + + /** + * Register this component in the id to component register + */ + if (R3.Utils.UndefinedOrNull(this.idRegister[component.id])) { + this.idRegister[component.id] = component; } /** - * Register this component in the Component.id to Component register + * If this component has a parent - link it right away */ - if (R3.Utils.UndefinedOrNull(this.idRegister[data.component.id])) { - this.idRegister[data.component.id] = data.component; + if (typeof component.parent === 'string') { + + if (R3.Utils.UndefinedOrNull(this.idRegister[component.parent])) { + throw new Error('A component links to a parent which has not been registered yet'); + } + + component.parent = this.idRegister[component.parent]; + } }; diff --git a/src/r3-graph-barchart-stacked.js b/src/r3-graph-barchart-stacked.js index b83a657..989ef76 100644 --- a/src/r3-graph-barchart-stacked.js +++ b/src/r3-graph-barchart-stacked.js @@ -39,6 +39,7 @@ R3.Graph.Barchart.Stacked.prototype.createInstance = function() { R3.Graph.Barchart.Stacked.prototype.updateInstance = function(property) { if (property === 'query') { + this.chart.destroy(); this.instance = this.graphics.BarchartStacked(this); } diff --git a/src/r3-query-0.js b/src/r3-query-0.js index e8f2627..64ed8b7 100644 --- a/src/r3-query-0.js +++ b/src/r3-query-0.js @@ -46,9 +46,23 @@ R3.Query.prototype.updateInstance = function(property) { return; } + if (property === 'tooltips') { + console.warn('todo: update query tooltips'); + return; + } + __UPDATE_INSTANCE__; }; -R3.Query.prototype.parse = function() { - console.warn('override R3.Query.prototype.parse() in child function'); +R3.Query.prototype.parse = function(data) { + console.warn(data); + + if (data.hits && data.hits.hits) { + data.hits.hits.map( + function(hit) { + this.tooltips.push(hit._source); + }.bind(this) + ) + } + }; \ No newline at end of file diff --git a/src/r3-query-alerts-0.js b/src/r3-query-alerts-0.js index 7394127..b08cab7 100644 --- a/src/r3-query-alerts-0.js +++ b/src/r3-query-alerts-0.js @@ -27,3 +27,9 @@ R3.Query.Alerts.prototype.updateInstance = function(property) { R3.Query.prototype.updateInstance.call(this, property); }; + +R3.Query.Alerts.prototype.parse = function(data) { + + R3.Query.prototype.parse.call(this, data); + +}; \ No newline at end of file diff --git a/src/r3-query-alerts-buckets.js b/src/r3-query-alerts-buckets.js index 33bc2c3..ea03cd3 100644 --- a/src/r3-query-alerts-buckets.js +++ b/src/r3-query-alerts-buckets.js @@ -124,10 +124,14 @@ R3.Query.Alerts.Buckets.prototype.parse = function(data) { ] ); + this.tooltips.push(bucket); + result.push(key.concat(priorities)); return result; - }, + }.bind(this), [] ); + //R3.Query.Alerts.prototype.parse.call(this, data); + }; diff --git a/src/r3-query-alerts-firstTimeLogin-0.js b/src/r3-query-alerts-firstTimeLogin-0.js index ca0aff5..960f70e 100644 --- a/src/r3-query-alerts-firstTimeLogin-0.js +++ b/src/r3-query-alerts-firstTimeLogin-0.js @@ -42,5 +42,9 @@ R3.Query.Alerts.FirstTimeLogin.prototype.updateInstance = function(property) { }; R3.Query.Alerts.FirstTimeLogin.prototype.parse = function(data) { + console.warn('not yet implemented'); + + R3.Query.Alerts.prototype.parse.call(this, data); + }; diff --git a/src/r3-query-alerts-firstTimeLogin-applications.js b/src/r3-query-alerts-firstTimeLogin-applications.js index 5e47b83..fe64542 100644 --- a/src/r3-query-alerts-firstTimeLogin-applications.js +++ b/src/r3-query-alerts-firstTimeLogin-applications.js @@ -58,14 +58,7 @@ R3.Query.Alerts.FirstTimeLogin.Applications.prototype.parse = function(data) { ]; if (data.hits.hits.length === 0) { - this.rows = [ - [ - 'no data', - null, - null, - null - ] - ] + this.rows = [null]; } else { this.rows = data.hits.hits.reduce( function (result, hit) { @@ -81,4 +74,6 @@ R3.Query.Alerts.FirstTimeLogin.Applications.prototype.parse = function(data) { ); } + R3.Query.Alerts.FirstTimeLogin.prototype.parse.call(this, data); + }; diff --git a/src/r3-query-alerts-firstTimeLogin-devices.js b/src/r3-query-alerts-firstTimeLogin-devices.js index 36fc85a..5d47edc 100644 --- a/src/r3-query-alerts-firstTimeLogin-devices.js +++ b/src/r3-query-alerts-firstTimeLogin-devices.js @@ -65,16 +65,7 @@ R3.Query.Alerts.FirstTimeLogin.Devices.prototype.parse = function(data) { }, ]; - if (data.hits.hits.length === 0) { - this.rows = [ - [ - 'no data', - null, - null, - null - ] - ] - } else { + if (data.hits && data.hits.hits) { this.rows = data.hits.hits.reduce( function (result, hit) { var row = [ @@ -90,4 +81,6 @@ R3.Query.Alerts.FirstTimeLogin.Devices.prototype.parse = function(data) { [] ); } + + R3.Query.Alerts.FirstTimeLogin.prototype.parse.call(this, data); }; diff --git a/src/r3-query-alerts-firstTimeLogin-vpn.js b/src/r3-query-alerts-firstTimeLogin-vpn.js index f82aa5e..e017931 100644 --- a/src/r3-query-alerts-firstTimeLogin-vpn.js +++ b/src/r3-query-alerts-firstTimeLogin-vpn.js @@ -86,4 +86,6 @@ R3.Query.Alerts.FirstTimeLogin.VPN.prototype.parse = function(data) { [] ); + R3.Query.Alerts.FirstTimeLogin.prototype.parse.call(this, data); + }; diff --git a/src/r3-query-alerts-list.js b/src/r3-query-alerts-list.js index fd7b193..cf1de8d 100644 --- a/src/r3-query-alerts-list.js +++ b/src/r3-query-alerts-list.js @@ -42,10 +42,6 @@ R3.Query.Alerts.List.prototype.updateInstance = function(property) { R3.Query.Alerts.List.prototype.parse = function(data) { this.columns = [ - { - type : 'datetime', - name : 'Time' - }, { type : 'number', name : 'Priority' @@ -55,28 +51,60 @@ R3.Query.Alerts.List.prototype.parse = function(data) { name : 'Alert Type' }, { - type : 'boolean', + type : 'string', + name : 'Hostname' + }, + { + type : 'string', + name : 'Device' + }, + { + type : 'string', + name : 'MAC Address' + }, + { + type : 'string', name : 'Acknowledged' + }, + { + type : 'datetime', + name : 'Time' } ]; + + this.rows = data.hits.hits.reduce( function(result, hit) { var row = []; - row.push(new Date(hit._source.timestamp)); + row.push(hit._source.priority); row.push(hit._source.alert_type); - row.push(hit._source.acknowledged); - // if (hit._source.acknowledged) { - // row.push({v:'ButtonName', f:''}); - // } else { - // row.push({v:'ButtonName', f:''}); - // } + + var hostname = 'unknown'; + if (hit._source.login && hit._source.login.destination_hostname) { + hostname = hit._source.login.destination_hostname; + } + row.push(hostname); + + var device = 'unknown'; + if (hit._source.device && hit._source.device.ip_v4) { + device = hit._source.device.ip_v4; + } + row.push(device); + + row.push(hit._source.mac); + + row.push({v:'ButtonName', f:hit._source.acknowledged?'Yes':'No'}); + row.push(new Date(hit._source.timestamp)); result.push(row); + return result; - }, + }.bind(this), [] ); + R3.Query.Alerts.prototype.parse.call(this, data); + }; diff --git a/src/r3-query-alerts-summary.js b/src/r3-query-alerts-summary.js index 99f173e..8a77586 100644 --- a/src/r3-query-alerts-summary.js +++ b/src/r3-query-alerts-summary.js @@ -44,9 +44,12 @@ R3.Query.Alerts.Summary.prototype.parse = function(data) { this.priorities = data.aggregations.priorities.buckets.reduce( function(result, bucket) { result.push(bucket.doc_count); + this.tooltips.push(bucket); return result; - }, + }.bind(this), [] ); + // R3.Query.Alerts.prototype.parse.call(this, data); + }; diff --git a/src/r3-query-alerts-timeseries.js b/src/r3-query-alerts-timeseries.js index 5f02a37..b2fc473 100644 --- a/src/r3-query-alerts-timeseries.js +++ b/src/r3-query-alerts-timeseries.js @@ -59,20 +59,72 @@ R3.Query.Alerts.Timeseries.prototype.parse = function(data) { return day + '-' + monthNames[monthIndex] + '-' + year; } - result.push(formatDate(new Date(bucket.key))); + function formatHour(date) { + + var day = date.getDate(); + var hour = date.getHours(); + var monthIndex = date.getMonth(); + + var monthNames = [ + "Jan", "Feb", "Mar", + "Apr", "May", "Jun", "Jul", + "Aug", "Sep", "Oct", + "Nov", "Dec" + ]; + return monthIndex+1 + '/' + day + ' ' + date.toLocaleTimeString(); + return monthNames[monthIndex] + ' ' + day + '-' + hour + ':00'; + } + + function formatMinute(date) { + + var hour = date.getHours(); + var minute = date.getMinutes(); + + return date.toLocaleTimeString(); + return hour + ':' + minute; + } + + if (this.timeInterval === '1d') { + result.push(formatDate(new Date(bucket.key))); + } else if (this.timeInterval === '1h') { + result.push(formatHour(new Date(bucket.key))); + } else if (this.timeInterval === '1m') { + result.push(formatMinute(new Date(bucket.key))); + } else { + console.warn('invalid time format'); + } + return result; - }, + }.bind(this), [] ); this.datasets = data.aggregations.mins.buckets.reduce( function(result, bucket) { - console.log('todo here'); - bucket.priorities.buckets.map( - function(prio) { - result[prio.key - 1].data.push(prio.doc_count); + + var count = bucket.priorities.buckets.reduce( + function(struct, prio) { + struct[prio.key - 1] = prio.doc_count; + return struct; + }, + [ + 0, + 0, + 0, + 0 + ] + ); + + if (R3.Utils.UndefinedOrNull(count)) { + count = [0, 0, 0, 0]; + } + + count.map( + function(data, index) { + result[index].data.push(data); } - ) + ); + return result; }, [ @@ -138,4 +190,6 @@ R3.Query.Alerts.Timeseries.prototype.parse = function(data) { // [] // ); + R3.Query.Alerts.prototype.parse.call(this, data); + }; diff --git a/src/r3-query-devices-0.js b/src/r3-query-devices-0.js index ce42c54..cb3e54d 100644 --- a/src/r3-query-devices-0.js +++ b/src/r3-query-devices-0.js @@ -78,4 +78,5 @@ R3.Query.Devices.prototype.parse = function(data) { ); } + R3.Query.prototype.parse.call(this, data); }; diff --git a/src/r3-query-devices-known.js b/src/r3-query-devices-known.js index 85f930e..02f78ca 100644 --- a/src/r3-query-devices-known.js +++ b/src/r3-query-devices-known.js @@ -81,4 +81,5 @@ R3.Query.Devices.Known.prototype.parse = function(data) { ); } + R3.Query.Devices.prototype.parse.call(this, data); }; diff --git a/src/r3-query-devices-sql.js b/src/r3-query-devices-sql.js index aad5541..c8112de 100644 --- a/src/r3-query-devices-sql.js +++ b/src/r3-query-devices-sql.js @@ -45,20 +45,28 @@ R3.Query.Devices.SQL.prototype.parse = function(data) { this.columns = [ { type: 'string', - name: 'Hostname' + name: 'IP' }, { type: 'string', - name: 'IP' + name: 'Hostname' }, { type: 'string', name: 'MAC Address' }, { - type: 'datetime', - name: 'Created' + type: 'string', + name: 'Agent ID' }, + { + type: 'string', + name: 'Acknowledged' + }, + { + type: 'datetime', + name: 'First Seen' + } ]; if (data.error) { @@ -69,14 +77,17 @@ R3.Query.Devices.SQL.prototype.parse = function(data) { this.rows = data.devices.reduce( function (result, device) { var row = [ - device.hostname, device.ip_v4, + device.hostname, device.mac, + device.agent_id, + {v:'ButtonName', f:device.acknowledged?'Yes':'No'}, new Date(device.created) ]; result.push(row); + this.tooltips.push(device); return result; - }, + }.bind(this), [] ); } diff --git a/src/r3-query-devices-unknown.js b/src/r3-query-devices-unknown.js index cf34af9..eb792e7 100644 --- a/src/r3-query-devices-unknown.js +++ b/src/r3-query-devices-unknown.js @@ -82,4 +82,5 @@ R3.Query.Devices.Unknown.prototype.parse = function(data) { ); } + R3.Query.Devices.prototype.parse.call(this, data); }; diff --git a/src/r3-query-logins-0.js b/src/r3-query-logins-0.js index 4f16580..b8ed72e 100644 --- a/src/r3-query-logins-0.js +++ b/src/r3-query-logins-0.js @@ -29,3 +29,9 @@ R3.Query.Logins.prototype.updateInstance = function(property) { R3.Query.prototype.updateInstance.call(this, property); }; + +R3.Query.Logins.prototype.parse = function(data) { + + R3.Query.prototype.parse.call(this, data); + +}; \ No newline at end of file diff --git a/src/r3-query-logins-applications.js b/src/r3-query-logins-applications.js index e6430ba..730804e 100644 --- a/src/r3-query-logins-applications.js +++ b/src/r3-query-logins-applications.js @@ -51,6 +51,10 @@ R3.Query.Logins.Applications.prototype.parse = function(data) { type: 'string', name: 'Application' }, + { + type: 'string', + name: 'Login Result' + }, { type: 'datetime', name: 'Time' @@ -62,6 +66,7 @@ R3.Query.Logins.Applications.prototype.parse = function(data) { var row = [ hit._source.username, hit._source.application, + hit._source.success?'Login Success':'Login Failure', new Date(hit._source.timestamp) ]; result.push(row); @@ -70,4 +75,6 @@ R3.Query.Logins.Applications.prototype.parse = function(data) { [] ); + R3.Query.Logins.prototype.parse.call(this, data); + }; diff --git a/src/r3-query-logins-devices.js b/src/r3-query-logins-devices.js index e3e4188..36a5a56 100644 --- a/src/r3-query-logins-devices.js +++ b/src/r3-query-logins-devices.js @@ -51,6 +51,10 @@ R3.Query.Logins.Devices.prototype.parse = function(data) { type : 'string', name : 'Device' }, + { + type : 'string', + name : 'Login Result' + }, { type : 'string', name : 'Type' @@ -65,15 +69,14 @@ R3.Query.Logins.Devices.prototype.parse = function(data) { }, ]; - this.rows = data.hits.hits.reduce( function(result, hit) { - console.log('device login : ', hit); var row = [ hit._source.username, hit._source.destination_hostname, - hit._source.login_type, - hit._source.login_protocol, + hit._source.success?'Login Success':'Login Failure', + hit._source.type, + hit._source.application, new Date(hit._source.timestamp) ]; result.push(row); @@ -82,4 +85,6 @@ R3.Query.Logins.Devices.prototype.parse = function(data) { [] ); + R3.Query.Logins.prototype.parse.call(this, data); + }; diff --git a/src/r3-query-logins-vpn.js b/src/r3-query-logins-vpn.js index 642d678..ac8c843 100644 --- a/src/r3-query-logins-vpn.js +++ b/src/r3-query-logins-vpn.js @@ -76,4 +76,5 @@ R3.Query.Logins.VPN.prototype.parse = function(data) { [] ); + R3.Query.Logins.prototype.parse.call(this, data); }; diff --git a/src/r3-query-userDevices-0.js b/src/r3-query-userDevices-0.js index 4f2ddab..db54e36 100644 --- a/src/r3-query-userDevices-0.js +++ b/src/r3-query-userDevices-0.js @@ -75,6 +75,7 @@ R3.Query.UserDevices.prototype.parse = function(data) { return result; }, [] - ) + ); + R3.Query.prototype.parse.call(this, data); }; \ No newline at end of file diff --git a/src/r3-query-users.js b/src/r3-query-users.js index 05a5666..d27b8f5 100644 --- a/src/r3-query-users.js +++ b/src/r3-query-users.js @@ -44,19 +44,15 @@ R3.Query.Users.prototype.parse = function(data) { this.columns = [ { type: 'string', - name: 'Email' + name: 'User' }, { type: 'datetime', - name: 'Created' + name: 'First Seen' }, ]; - if (data.error) { - this.rows = [ - ['error', null, null, null] - ] - } else { + if (!data.error) { this.rows = data.users.reduce( function (result, user) { var row = [ @@ -64,10 +60,14 @@ R3.Query.Users.prototype.parse = function(data) { new Date(user.created) ]; result.push(row); + + this.tooltips.push(user); + return result; - }, + }.bind(this), [] ); } + }; diff --git a/src/r3-renderer-d3-0.js b/src/r3-renderer-d3-0.js index c0a95a3..0a10679 100644 --- a/src/r3-renderer-d3-0.js +++ b/src/r3-renderer-d3-0.js @@ -7,10 +7,10 @@ R3.Renderer.D3 = function( inherited ) { - __INHERIT_ONLY__ + __INHERIT_ONLY__; this.linkedComponents.viewports = [R3.D3.Viewport]; - this.linkedComponents.scenes = [R3.D3.Scenes]; + this.linkedComponents.scenes = [R3.D3.Scene]; R3.Renderer.call( this, diff --git a/src/r3-renderer-d3-canvas-0.js b/src/r3-renderer-d3-canvas-0.js index 5583b23..ec5e1be 100644 --- a/src/r3-renderer-d3-canvas-0.js +++ b/src/r3-renderer-d3-canvas-0.js @@ -9,7 +9,7 @@ R3.Renderer.D3.Canvas = function( inherited ) { - __INHERIT_AND_INSTANTIATE__ + __INHERIT_AND_INSTANTIATE__; this.linkedComponents.canvas = R3.Canvas; diff --git a/src/r3-runtime-graphics-chart.js b/src/r3-runtime-graphics-chart.js index 4ddd940..e9e285a 100644 --- a/src/r3-runtime-graphics-chart.js +++ b/src/r3-runtime-graphics-chart.js @@ -29,7 +29,17 @@ R3.Runtime.Graphics.Chart.prototype.createInstance = function() { */ R3.Runtime.Graphics.Chart.prototype.BarchartStacked = function(runtimeObject) { - var ctx = document.getElementById(runtimeObject.domElement.domElementId).getContext('2d'); + var domElement = document.getElementById(runtimeObject.domElement.domElementId); + // + // var divs = domElement.parentElement.getElementsByTagName('div'); + // + // for (var div of divs) { + // domElement.parentElement.removeChild(div); + // } + + var ctx = domElement.getContext('2d'); + + var barChartData = { labels: runtimeObject.query.labels, diff --git a/src/r3-runtime-graphics-google.js b/src/r3-runtime-graphics-google.js index 3ac721a..564cf47 100644 --- a/src/r3-runtime-graphics-google.js +++ b/src/r3-runtime-graphics-google.js @@ -22,15 +22,169 @@ R3.Runtime.Graphics.Google.prototype.createInstance = function() { this.instance = google.charts; }; +R3.Runtime.Graphics.Google.Tooltip = function(domTable, table, graph) { + + var tooltip = document.createElement('div'); + tooltip.setAttribute('class', 'google-visualization-tooltip tooltip-minimized'); + + var header = document.createElement('div'); + header.setAttribute('class', 'tooltip-header'); + + var headerTitle = document.createElement('div'); + headerTitle.innerText = 'Click for more info...'; + + var button = document.createElement('button'); + button.setAttribute('class', 'btn btn-info btn-white close-button'); + button.innerText = 'X'; + + header.appendChild(headerTitle); + header.appendChild(button); + + var tooltipContent = document.createElement('pre'); + + tooltip.appendChild(header); + tooltip.appendChild(tooltipContent); + + if (graph.tooltip) { + document.body.removeChild(graph.tooltip); + } + + graph.tooltip = tooltip; + + document.body.appendChild(tooltip); + + if (graph.mouseover) { + domTable.removeEventListener('mouseover', graph.mouseover); + } + + if (graph.mouseout) { + domTable.removeEventListener('mouseout', graph.mouseout); + } + + if (graph.mousemove) { + domTable.removeEventListener('mousemove', graph.mousemove); + } + + graph.mouseover = function(tooltip) { + return function(event) { + tooltip.style.display = 'flex'; + tooltip.style.left = (event.pageX + 10) + "px"; + tooltip.style.top = (event.pageY + 10) + "px"; + }; + }(tooltip); + + graph.mouseout = function(tooltip) { + return function(event) { + tooltip.style.display = 'none'; + }; + }(tooltip); + + graph.mousemove = function(tooltip) { + return function(event) { + tooltip.style.left = (event.pageX + 10) + "px"; + tooltip.style.top = (event.pageY + 10) + "px"; + }; + }(tooltip); + + button.addEventListener('click', function(graph, tooltip, button, domTable) { + return function(event) { + domTable.addEventListener('mouseover', graph.mouseover); + domTable.addEventListener('mouseout', graph.mouseout); + domTable.addEventListener('mousemove', graph.mousemove); + tooltip.style.left = (event.pageX + 10) + "px"; + tooltip.style.top = (event.pageY + 10) + "px"; + tooltip.style.display = 'none'; + tooltip.setAttribute('class', 'google-visualization-tooltip tooltip-minimized'); + button.style.display = 'none'; + } + }(graph, tooltip, button, domTable)); + + google.visualization.events.addListener( + table, + 'ready', + function(domTable, graph) { + return function() { + domTable.addEventListener('mouseover', graph.mouseover); + domTable.addEventListener('mouseout', graph.mouseout); + domTable.addEventListener('mousemove', graph.mousemove); + }; + }(domTable, graph) + ); + + google.visualization.events.addListener( + table, + 'select', + function(domTable, graph, tooltipContent) { + return function() { + domTable.removeEventListener('mouseover', graph.mouseover); + domTable.removeEventListener('mouseout', graph.mouseout); + domTable.removeEventListener('mousemove', graph.mousemove); + tooltip.setAttribute('class', 'google-visualization-tooltip tooltip-maximized'); + button.style.display = 'block'; + + var selection = table.getSelection(); + + var row = 0; + + if (selection && selection[0]) { + row = selection[0].row + } + + tooltipContent.innerHTML = R3.Utils.SyntaxHighlight(JSON.stringify(graph.query.tooltips[row], null, 2)); + } + }(domTable, graph, tooltipContent) + ); + + return { + main : tooltip, + closeButton : button, + header : header, + title : headerTitle, + content : tooltipContent + }; +}; + R3.Runtime.Graphics.Google.prototype.Table = function(runtimeObject) { google.charts.load('current', {'packages':['table']}); google.charts.setOnLoadCallback( function(graph) { + return function() { + var dataTable = new google.visualization.DataTable(); + // var makeTooltipActive = function(object, moveEventListener, overOutEventListener, table) { + // return function(event) { + // var selection = table.getSelection(); + // + // object.domElement.instance.removeEventListener('mousemove', moveTooltip); + // + // var closeButton = document.getElementById('button-close-tooltip'); + // closeButton.style.display = 'block'; + // var tooltip = document.getElementById('div-tooltip'); + // tooltip.setAttribute('class', 'google-visualization-tooltip tooltip-maximized'); + // var tooltipContent = document.getElementById('pre-tooltip-content'); + // tooltipContent.style.display = 'block'; + // + // + // var row = selection[0].row; + // var tooltip = document.getElementById('div-tooltip'); + // var tooltipContent = document.getElementById('pre-tooltip-content'); + // var tooltipHeader = document.getElementById('div-tooltip-header'); + // tooltipContent.innerHTML = R3.Utils.SyntaxHighlight(JSON.stringify(object.query.tooltips[row], null, 2)); + // tooltip.style.display = 'flex'; + // moveTooltip(event); + // + // } + // }; + // + // var closeButtonClick = ; + // + // var closeButton = document.getElementById('button-close-tooltip'); + // closeButton.addEventListener('click', closeButtonClick); + graph.columns.map( function(column) { dataTable.addColumn(column.type, column.name); @@ -39,9 +193,38 @@ R3.Runtime.Graphics.Google.prototype.Table = function(runtimeObject) { dataTable.addRows(graph.rows); - var table = new google.visualization.Table(document.getElementById(graph.domElement.domElementId)); + var domTable = document.getElementById(graph.domElement.domElementId); - table.draw(dataTable, {showRowNumber: false, width: '100%', height: '100%'}); + var table = new google.visualization.Table(domTable); + + var tooltip = R3.Runtime.Graphics.Google.Tooltip( + domTable, + table, + graph + ); + + table.draw( + dataTable, + { + showRowNumber: false, + allowHtml : true, + cssClassNames: { + tableCell: 'fixed-row-height', + hoverTableRow : 'hover-row' + }, + width: '100%', + height: '100%', + page: 'enable', + pageSize: graph.pageSize, + sortColumn: graph.columns.length - 1, + sortAscending : false, + pagingSymbols: { + prev: 'prev', + next: 'next' + }, + pagingButtonsConfiguration: 'auto' + } + ); } }(runtimeObject) diff --git a/src/r3-system-input.js b/src/r3-system-input.js index b3c4b17..cd0fbdf 100644 --- a/src/r3-system-input.js +++ b/src/r3-system-input.js @@ -14,6 +14,7 @@ R3.System.Input = function() { R3.Event.Emit( R3.Event.GET_APPLICATION_MODE, + null, function(applicationMode) { this.applicationMode = applicationMode; }.bind(this) diff --git a/src/r3-system-query.js b/src/r3-system-query.js index a5c02e5..0bd5c29 100644 --- a/src/r3-system-query.js +++ b/src/r3-system-query.js @@ -21,10 +21,38 @@ R3.System.Query.prototype.start = function() { this.query ); + this.querySubscription = R3.Event.Subscribe( + R3.Event.QUERY, + this.query + ); + + this.intervalChangeSubscription = R3.Event.Subscribe( + R3.Event.QUERY_INTERVAL_CHANGE, + this.intervalChange.bind(this) + ); + R3.System.prototype.start.call(this); }; +R3.System.Query.prototype.intervalChange = function(data) { + + var graphs = R3.EntityManager.Instance.findComponentsByConstructor(R3.Graph); + + graphs.map( + function(graph) { + graph.query.start = 'now-' + data.interval; + graph.query.timeInterval = data.timeInterval; + R3.Event.Emit( + R3.Event.QUERY, + { + component : graph.query + } + ) + } + ); + +}; /** * Check for query instances - then run them @@ -81,6 +109,10 @@ R3.System.Query.prototype.query = function(data) { queryText = queryText.replace(new RegExp(R3.API.Query.QUERY_ACKNOWLEDGED, "g"), query.acknowledged); } + if (R3.Utils.Defined(query.timeInterval)) { + queryText = queryText.replace(new RegExp(R3.API.Query.QUERY_TIME_INTERVAL, "g"), query.timeInterval); + } + if (typeof XMLHttpRequest === 'undefined') { console.log('Implement server side query here'); return; @@ -123,6 +155,8 @@ R3.System.Query.prototype.stop = function() { this.querySubscription.remove(); + this.intervalChangeSubscription.remove(); + R3.System.prototype.stop.call(this); }; diff --git a/src/r3-system-storage.js b/src/r3-system-storage.js index b843bad..c66d478 100644 --- a/src/r3-system-storage.js +++ b/src/r3-system-storage.js @@ -642,7 +642,19 @@ R3.System.Storage.prototype.createRuntimeObject = function(responseText, clientE return runtimeComponent; }; -R3.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, includeDependencies, clientCallback, clientErrorCallback) { +/** + * Loads a component and its dependencies if specified + * @param urlData + * @param componentData + * @param clientCallback + * @param clientErrorCallback + */ +R3.System.Storage.prototype.loadComponent = function( + urlData, + componentData, + clientCallback, + clientErrorCallback +) { /** * TODO: ensure parents of this component are loaded first @@ -655,7 +667,8 @@ R3.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, includeD * We don't override runtime versions of the dependencies of the loading components - since they could be later. * But we do override runtime versions of the loading component since the user actually selected them and clicked 'load' */ - toProcess.map( + componentData.ids.map( + function(id) { R3.Utils.PushUnique(this.loading, id); @@ -665,15 +678,27 @@ R3.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, includeD if (component) { component.remove(); } + }.bind(this) + ); - toProcess.map( + componentData.ids.map( function(id) { var xhr = new XMLHttpRequest(); + xhr.open( + 'GET', + urlData.apiUrl + '/component/load/' + id + ); + + xhr.setRequestHeader("Accept", "application/json"); + xhr.setRequestHeader("Content-Type", "application/json"); + xhr.setRequestHeader("x-api-authorization", urlData.apiAuthorization); + xhr.setRequestHeader('x-api-user-token', urlData.apiUserToken); + xhr.onload = function(__system) { return function() { @@ -844,12 +869,6 @@ R3.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, includeD }.bind(this); }(id); - xhr.open( - 'GET', - apiUrl + '/component/load/' + id - ); - - xhr.send(); }.bind(this) @@ -862,34 +881,36 @@ R3.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, includeD /** * 'Loads' data from a url */ -R3.System.Storage.prototype.load = function(data, clientCallback, clientErrorCallback) { +R3.System.Storage.prototype.load = function(componentData, clientCallback, clientErrorCallback) { - this.emit( - R3.Event.GET_API_URL, + + if (typeof XMLHttpRequest === 'undefined') { + throw new Error('Implement server side save here'); + } + + if (R3.Utils.UndefinedOrNull(componentData.ids) || componentData.ids.length < 1) { + throw new Error('No components defined for loading'); + } + + var event = R3.Event.GET_API_URL; + + if (componentData.remote) { + event = R3.Event.GET_REMOTE_API_URL + } + + R3.Event.Emit( + event, null, function(urlData) { - if (typeof XMLHttpRequest === 'undefined') { - console.log('Implement server side load here'); - return; - } - - if (data.ids && data.ids.length > 0) { - this.loadComponent( - urlData.apiUrl, - data.ids, - data.includeDependencies, - clientCallback, - clientErrorCallback - ); - } else { - console.log('No components selected'); - } + this.loadComponent( + urlData, + componentData, + clientCallback, + clientErrorCallback + ); }.bind(this), - function(error) { - console.error(error.message); - throw new Error(error.message); - } - ); + console.error + ) }; diff --git a/src/r3-vector3.js b/src/r3-vector3.js index bc8a7ab..61340d5 100644 --- a/src/r3-vector3.js +++ b/src/r3-vector3.js @@ -27,6 +27,30 @@ R3.Vector3.prototype.constructor = R3.Vector3; */ R3.Vector3.prototype.createInstance = function() { + /** + * We have a dependency on our parent which could still need to call 'createInstance' + */ + + // if (typeof this.parent === 'string') { + // + // if (R3.Utils.UndefinedOrNull(this.instanceLoaded)) { + // + // this.instanceLoaded = R3.Event.Subscribe( + // R3.Event.INSTANCE_LOADED, + // function (data) { + // if (data.component.id === this.parent) { + // this.parent = data.component; + // this.createInstance(); + // this.instanceLoaded.remove(); + // } + // }.bind(this) + // ); + // + // } + // + // return; + // } + var runtime = R3.Component.GetComponentRuntime(this.parent); switch (runtime) {