// http://www.apache.org/licenses/LICENSE-2.0 /
/////////////////////////////////////////////////////////////////////////////////////////
import { Mongo } from 'meteor/mongo';
+import * as R from 'ramda';
export const NodeHoverAttr = new Mongo.Collection(
'attributes_for_hover_on_data', { idGeneration: 'MONGO' });
+
+export const calcAttrsForItem = function (node, attrsDefsRec) {
+ if (R.isNil(attrsDefsRec)) {
+ return [];
+ }
+
+ let attrsDefs = attrsDefsRec.attributes;
+
+ return R.reduce((acc, attrDef) => {
+ if (R.is(Array, attrDef)) {
+ let value = R.path(attrDef, node);
+ if (R.isNil(value)) { return acc; }
+ let name = R.join('.', attrDef);
+ return R.append(R.assoc(name, value, {}), acc);
+
+ } else {
+ return R.ifElse(R.isNil,
+ R.always(acc),
+ (attrVal) => R.append(R.assoc(attrDef, attrVal, {}), acc)
+ )(R.prop(attrDef, node));
+ }
+ }, [], attrsDefs);
+};
'focal_point_type',
'link_types',
'name', ],
- cliqueType), {
- environment,
- focal_point_type,
- link_types,
- name,
- });
+ cliqueType), {
+ environment,
+ focal_point_type,
+ link_types,
+ name,
+ });
CliqueTypes.update({ _id: _id }, { $set: cliqueType });
}
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) and others /
+// /
+// All rights reserved. This program and the accompanying materials /
+// are made available under the terms of the Apache License, Version 2.0 /
+// which accompanies this distribution, and is available at /
+// http://www.apache.org/licenses/LICENSE-2.0 /
+/////////////////////////////////////////////////////////////////////////////////////////
+import { Mongo } from 'meteor/mongo';
+import { SimpleSchema } from 'meteor/aldeed:simple-schema';
+//import * as R from 'ramda';
+
+export const Configurations = new Mongo.Collection('configurations', { idGeneration: 'MONGO' });
+
+let schema = {
+ _id: { type: { _str: { type: String, regEx: SimpleSchema.RegEx.Id } } },
+ user_id: {
+ type: String,
+ },
+ messages_view_backward_delta: {
+ type: Number,
+ minCount: 1,
+ defaultValue: '1209600000', // 2 weeks
+ }
+};
+
+let simpleSchema = new SimpleSchema(schema);
+Configurations.schema = simpleSchema;
+Configurations.attachSchema(Configurations.schema);
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) and others /
+// /
+// All rights reserved. This program and the accompanying materials /
+// are made available under the terms of the Apache License, Version 2.0 /
+// which accompanies this distribution, and is available at /
+// http://www.apache.org/licenses/LICENSE-2.0 /
+/////////////////////////////////////////////////////////////////////////////////////////
+import { ValidatedMethod } from 'meteor/mdg:validated-method';
+import { Configurations } from '/imports/api/configurations/configurations';
+import * as R from 'ramda';
+
+export const save = new ValidatedMethod({
+ name: 'configurations.save',
+ validate: Configurations.simpleSchema()
+ .pick([
+ 'messages_view_backward_delta'
+ ]).validator({ clean: true, filter: false }),
+ run({
+ messages_view_backward_delta
+ }) {
+
+ let userId = this.userId;
+ let conf = Configurations.findOne({ user_id: userId });
+
+ if (conf) {
+ Configurations.update({ _id: conf._id}, { $set: {
+ messages_view_backward_delta: messages_view_backward_delta
+ }});
+ } else {
+ let item = Configurations.schema.clean({});
+ item = R.merge(item, {
+ user_id: userId,
+ messages_view_backward_delta: messages_view_backward_delta
+ });
+ Configurations.insert(item);
+ }
+ }
+});
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) and others /
+// /
+// All rights reserved. This program and the accompanying materials /
+// are made available under the terms of the Apache License, Version 2.0 /
+// which accompanies this distribution, and is available at /
+// http://www.apache.org/licenses/LICENSE-2.0 /
+/////////////////////////////////////////////////////////////////////////////////////////
+import { Meteor } from 'meteor/meteor';
+
+import { Configurations } from '../configurations.js';
+
+Meteor.publish('configurations?user', function () {
+ console.log('server subscribtion: configurations?user');
+
+ let userId = this.userId;
+
+ let query = { user_id: userId };
+ console.log('-query: ', query);
+ return Configurations.find(query);
+});
];
export const optionalConfGroups = [
- // 'NFV_provider',
+ // 'NFV_provider',
'AMQP',
'Monitoring',
'ACI',
return CLISchema;
case 'AMQP':
return AMQPSchema;
-// case 'NFV_provider':
-// return NfvProviderSchema;
+ // case 'NFV_provider':
+ // return NfvProviderSchema;
case 'ACI':
return AciSchema;
case 'Monitoring':
import { Inventory } from '../inventories';
import { Environments } from '/imports/api/environments/environments';
import { regexEscape } from '/imports/lib/regex-utils';
-import { NodeHoverAttr } from '/imports/api/attributes_for_hover_on_data/attributes_for_hover_on_data';
+import { NodeHoverAttr, calcAttrsForItem } from '/imports/api/attributes_for_hover_on_data/attributes_for_hover_on_data';
+
const AUTO_COMPLETE_RESULTS_LIMIT = 15;
Meteor.methods({
let query = { _id: nodeId };
let node = Inventory.findOne(query);
let attrsDefs = NodeHoverAttr.findOne({ 'type': node.type });
- let attributes = calcAttrsForNode(node, attrsDefs);
+ let attributes = calcAttrsForItem(node, attrsDefs);
return {
node: node,
};
},
});
-
-function calcAttrsForNode(node, attrsDefsRec) {
- if (R.isNil(attrsDefsRec)) {
- return [];
- }
-
- let attrsDefs = attrsDefsRec.attributes;
-
- return R.reduce((acc, attrDef) => {
- if (R.is(Array, attrDef)) {
- let value = R.path(attrDef, node);
- if (R.isNil(value)) { return acc; }
- let name = R.join('.', attrDef);
- return R.append(R.assoc(name, value, {}), acc);
-
- } else {
- return R.ifElse(R.isNil,
- R.always(acc),
- (attrVal) => R.append(R.assoc(attrDef, attrVal, {}), acc)
- )(R.prop(attrDef, node));
- }
- }, [], attrsDefs);
-}
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2017 Koren Lev (Cisco Systems), Yaron Yogev (Cisco Systems) and others /
+// /
+// All rights reserved. This program and the accompanying materials /
+// are made available under the terms of the Apache License, Version 2.0 /
+// which accompanies this distribution, and is available at /
+// http://www.apache.org/licenses/LICENSE-2.0 /
+/////////////////////////////////////////////////////////////////////////////////////////
+
+import { Links } from '../links';
+import { NodeHoverAttr, calcAttrsForItem } from '/imports/api/attributes_for_hover_on_data/attributes_for_hover_on_data';
+import * as R from 'ramda';
+
+Meteor.methods({
+ 'linksFind?DataAndAttrs': function (id) {
+ console.log(`method server: linksFind?DataAndAttrs. ${R.toString(id)}`);
+ //check(nodeId, ObjectId);
+ this.unblock();
+
+ let query = { _id: id };
+ let link = Links.findOne(query);
+ let attrsDefs = NodeHoverAttr.findOne({ 'type': 'link' });
+ let attributes = calcAttrsForItem(link, attrsDefs);
+
+ return {
+ link: link,
+ linkName: link.link_name,
+ attributes: attributes
+ };
+ },
+});
Meteor.methods({
'messages/get?level&env&page&amountPerPage&sortField&sortDirection': function (
- level, env, page, amountPerPage, sortField, sortDirection) {
+ level, env, page, amountPerPage, sortField, sortDirection) {
logMethodCall('messages/get?level&env&page&amountPerPage&sortField&sortDirection',
{level, env, page, amountPerPage});
query = R.ifElse(R.isNil, R.always(query),R.assoc('level', R.__, query))(level);
sortParams = R.ifElse(R.isNil, R.always(sortParams),
- R.assoc(R.__, sortDirection, sortParams))(sortField);
+ R.assoc(R.__, sortDirection, sortParams))(sortField);
console.log('sort params:', sortParams);
return new Counter(counterName, Messages.find({ level: level }));
});
+Meteor.publish('messages/count?backDelta&level', function (backDelta, level) {
+ const counterName = `messages/count?backDelta=${backDelta}&level=${level}`;
+ console.log(`subscribe - counter: ${counterName}`);
+
+ let begining = moment().subtract(backDelta);
+ let query = {
+ level: level,
+ timestamp: { $gte: begining.toDate() }
+ };
+
+ console.log(`query: ${R.toString(query)}`);
+
+ return new Counter(counterName, Messages.find(query));
+});
+
Meteor.publish('messages/count?level&env', function (level, env) {
const counterName = `messages/count?level=${level}&env=${env}`;
console.log(`subscribe - counter: ${counterName}`);
let query = { level: level };
query = R.ifElse(R.isNil, R.always(query), R.assoc('environment', R.__, query))(env);
+ console.log(`query: ${R.toString(query)}`);
- return new Counter(counterName, Messages.find(query)); });
+ return new Counter(counterName, Messages.find(query));
+});
export let imagesForNodeType = {
- 'instance': 'ic_computer_black_48dp_2x.png',
- 'pnic': 'ic_dns_black_48dp_2x.png',
- 'vconnector': 'ic_settings_input_composite_black_48dp_2x.png',
+ 'instance': {
+ default: 'ic_computer_black_48dp_2x.png',
+ ok: 'ic_computer_black_48dp_2x-green.png',
+ warning: 'ic_computer_black_48dp_2x-orange.png',
+ error: 'ic_computer_black_48dp_2x-red.png',
+ },
+ 'pnic': {
+ default: 'ic_dns_black_48dp_2x.png',
+ ok: 'ic_dns_black_48dp_2x-green.png',
+ warning: 'ic_dns_black_48dp_2x-orange.png',
+ error: 'ic_dns_black_48dp_2x-red.png',
+ },
+ 'vconnector': {
+ default: 'ic_settings_input_composite_black_48dp_2x.png',
+ ok: 'ic_settings_input_composite_black_48dp_2x-green.png',
+ warning: 'ic_settings_input_composite_black_48dp_2x-orange.png',
+ error: 'ic_settings_input_composite_black_48dp_2x-red.png',
+ },
// 'network': 'ic_cloud_queue_black_48dp_2x.png',
- 'network': 'ic_cloud_queue_black_48dp_2x.png',
- 'vedge': 'ic_gamepad_black_48dp_2x.png',
- 'vservice': 'ic_storage_black_48dp_2x.png',
- 'vnic': 'ic_settings_input_hdmi_black_48dp_2x.png',
- 'otep':'ic_keyboard_return_black_48dp_2x.png',
+ 'network': {
+ default: 'ic_cloud_queue_black_48dp_2x.png',
+ ok: 'ic_cloud_queue_black_48dp_2x-green.png',
+ warning: 'ic_cloud_queue_black_48dp_2x-orange.png',
+ error: 'ic_cloud_queue_black_48dp_2x-red.png',
+ },
+ 'vedge': {
+ default: 'ic_gamepad_black_48dp_2x.png',
+ ok: 'ic_gamepad_black_48dp_2x-green.png',
+ warning: 'ic_gamepad_black_48dp_2x-orange.png',
+ error: 'ic_gamepad_black_48dp_2x-red.png',
+ },
+ 'vservice': {
+ default: 'ic_storage_black_48dp_2x.png',
+ ok: 'ic_storage_black_48dp_2x-green.png',
+ warning: 'ic_storage_black_48dp_2x-orange.png',
+ error: 'ic_storage_black_48dp_2x-red.png',
+ },
+ 'vnic': {
+ default: 'ic_settings_input_hdmi_black_48dp_2x.png',
+ ok: 'ic_settings_input_hdmi_black_48dp_2x-green.png',
+ warning: 'ic_settings_input_hdmi_black_48dp_2x-orange.png',
+ error: 'ic_settings_input_hdmi_black_48dp_2x-red.png',
+ },
+ 'otep': {
+ default: 'ic_keyboard_return_black_48dp_2x.png',
+ ok: 'ic_keyboard_return_black_48dp_2x-green.png',
+ warning: 'ic_keyboard_return_black_48dp_2x-orange.png',
+ error: 'ic_keyboard_return_black_48dp_2x-red.png',
+ },
};
-export let defaultNodeTypeImage = 'ic_lens_black_48dp_2x.png';
+export let defaultNodeTypeImage = {
+ default: 'ic_lens_black_48dp_2x.png',
+ ok: 'ic_lens_black_48dp_2x-green.png',
+ warning: 'ic_lens_black_48dp_2x-orange.png',
+ error: 'ic_lens_black_48dp_2x-red.png',
+};
import '/imports/ui/components/message/message';
import '/imports/ui/components/dashboard/dashboard';
import '/imports/ui/components/new-scanning/new-scanning';
+import '/imports/ui/components/configuration/configuration';
import '../../api/links/server/publications';
import '../../api/links/methods.js';
+import '../../api/links/server/methods';
import '../../api/statistics/server/publications';
import '../../api/statistics/methods.js';
import '../../api/supported_environments/server/publications';
import '../../api/supported_environments/methods';
+import '../../api/configurations/server/publications';
+import '../../api/configurations/methods';
+
import '../../api/migrations/migrations';
<div class="dropdown">
<div class="material-icons mdl-badge mdl-badge--overlap dropdown-toggle"
- data-badge="{{countOf 'messages/count?level=info'}}"
+ data-badge="{{ countOf (msgCounterName 'info') }}"
type="button"
id="dropdownMenu1"
data-toggle="modal"
data-target="#messagesModalGlobal"
data-message-level="info"
+ title="Info messages"
>notifications</div>
</div>
<div class="dropdown">
<div class="material-icons mdl-badge mdl-badge--overlap dropdown-toggle"
- data-badge="{{countOf 'messages/count?level=warning'}}"
+ data-badge="{{ countOf (msgCounterName 'warning') }}"
type="button"
id="dropdownMenu1"
data-toggle="modal"
data-target="#messagesModalGlobal"
data-message-level="warning"
+ title="Warning messages"
>warning</div>
</div>
<div class="dropdown">
<div class="material-icons mdl-badge mdl-badge--overlap dropdown-toggle"
- data-badge="{{countOf 'messages/count?level=error'}}"
+ data-badge="{{ countOf (msgCounterName 'error') }}"
type="button"
id="dropdownMenu1"
data-toggle="modal"
data-target="#messagesModalGlobal"
data-message-level="error"
+ title="Error messages"
>error</div>
</div>
<a href="{{pathFor route='user-list' query=''}}">Users</a>
</li>
{{/if }}
+
+ <li class="dropdown-header">
+ <a href="{{pathFor route='configuration' query=''}}" >Configuration</a>
+ </li>
</ul>
</div>
import '/imports/ui/components/breadcrumb/breadcrumb';
import { Messages } from '/imports/api/messages/messages';
import { Roles } from 'meteor/alanning:roles';
+import { ReactiveDict } from 'meteor/reactive-dict';
+
+import { Configurations } from '/imports/api/configurations/configurations';
import './alarm-icons.html';
Template.alarmIcons.onCreated(function () {
let instance = this;
+ instance.state = new ReactiveDict();
+ instance.state.setDefault({
+ msgsViewBackDelta: 1
+ });
+
instance.autorun(function () {
- instance.subscribe('messages/count?level', 'info');
- instance.subscribe('messages/count?level', 'warning');
- instance.subscribe('messages/count?level', 'error');
+ instance.subscribe('configurations?user');
+ Configurations.find({user_id: Meteor.userId()}).forEach((conf) => {
+ instance.state.set('msgsViewBackDelta', conf.messages_view_backward_delta);
+ });
+ });
+
+ instance.autorun(function () {
+ let msgsViewBackDelta = instance.state.get('msgsViewBackDelta');
+
+ instance.subscribe('messages/count?backDelta&level', msgsViewBackDelta, 'info');
+ instance.subscribe('messages/count?backDelta&level', msgsViewBackDelta, 'warning');
+ instance.subscribe('messages/count?backDelta&level', msgsViewBackDelta, 'error');
});
});
errorsCount: function(){
return Messages.find({level:'error'}).count();
},
+
+ msgCounterName: function (level) {
+ let instance = Template.instance();
+ let msgsViewBackDelta = instance.state.get('msgsViewBackDelta');
+ let counterName = `messages/count?backDelta=${msgsViewBackDelta}&level=${level}`;
+
+ return counterName;
+ }
});
objectTypesList: function () {
return R.ifElse(R.isNil, R.always([]), R.prop('data')
- )(Constants.findOne({ name: 'object_types_for_links' }));
+ )(Constants.findOne({ name: 'object_types_for_links' }));
},
linkTypesList: function () {
focal_point_type,
link_types,
name
- ) {
+) {
let action = instance.state.get('action');
break;
default:
- // todo
+ // todo
break;
}
}
--- /dev/null
+<template name="Configuration">
+<div class="os-configuration cards white">
+ <h3>Configurations</h3>
+ <form>
+ <div class="cl-field-group">
+ <label class="cl-field-label">Message view backward delta</label>
+ <input name="msgsViewBackDelta"
+ value="{{ getModelField 'messages_view_backward_delta' }}"
+ class="cl-msgs-view-back-delta cl-input"
+ type="number"
+ placeholder="" />
+ <div class="cl-field-desc">Backward duration of {{ durationHumanize (getModelField 'messages_view_backward_delta') }} from current date (miliseconds)</div>
+ </div>
+
+ <button type="button"
+ class="js-submit-button mdl-button mdl-js-button mdl-button--raised
+ mdl-js-ripple-effect mdl-button--colored"
+ >Save</button>
+ </form>
+
+ {{#if (getState 'message') }}
+ <div class="js-message-panel alert
+ {{#if isActionError}}alert-danger{{/if}}
+ {{#if isActionSuccess}}alert-success{{/if}}"
+ role="alert">
+ {{ getState 'message' }}
+ </div>
+ {{/if }}
+
+</div>
+</template>
--- /dev/null
+/*
+ * Template Component: Configuration
+ */
+
+//import { Meteor } from 'meteor/meteor';
+import { Template } from 'meteor/templating';
+import { ReactiveDict } from 'meteor/reactive-dict';
+//import { SimpleSchema } from 'meteor/aldeed:simple-schema';
+import * as R from 'ramda';
+
+import { save } from '/imports/api/configurations/methods';
+import { Configurations } from '/imports/api/configurations/configurations';
+
+import './configuration.html';
+
+/*
+ * Lifecycles
+ */
+
+Template.Configuration.onCreated(function() {
+ let instance = this;
+ instance.state = new ReactiveDict();
+ instance.state.setDefault({
+ model: Configurations.schema.clean({}),
+ actionResult: 'none',
+ message: null,
+ });
+
+ /*
+ instance.autorun(function () {
+ let data = Template.currentData();
+
+ new SimpleSchema({
+ }).validate(data);
+ });
+ */
+
+ instance.autorun(function () {
+ instance.subscribe('configurations?user');
+ Configurations.find({user_id: Meteor.userId()}).forEach((conf) => {
+ instance.state.set('model', conf);
+ });
+ });
+});
+
+/*
+Template.Configuration.rendered = function() {
+};
+*/
+
+/*
+ * Events
+ */
+
+Template.Configuration.events({
+ 'click .js-submit-button': function (event, instance) {
+ event.preventDefault();
+ let msgsViewBackDelta = instance.$('.cl-msgs-view-back-delta')[0].value;
+ saveForm(instance, msgsViewBackDelta);
+ }
+});
+
+/*
+ * Helpers
+ */
+
+Template.Configuration.helpers({
+ getModelField: function (fieldName) {
+ let instance = Template.instance();
+ return R.path([fieldName], instance.state.get('model'));
+ },
+
+ getState: function (key) {
+ let instance = Template.instance();
+ return instance.state.get(key);
+ },
+
+ isActionError: function () {
+ let instance = Template.instance();
+ return instance.state.get('actionResult') === 'error';
+ },
+
+ isActionSuccess: function () {
+ let instance = Template.instance();
+ return instance.state.get('actionResult') === 'success';
+ },
+
+ durationHumanize: function (duration) {
+ return moment.duration(duration).humanize();
+ }
+}); // end: helpers
+
+function saveForm(instance, msgsViewBackDelta) {
+ instance.state.set('actionResult', 'none');
+ instance.state.set('message', null);
+
+ save.call({
+ messages_view_backward_delta: msgsViewBackDelta
+ }, (error) => {
+ if (error) {
+ instance.state.set('actionResult', 'error');
+ if (typeof error === 'string') {
+ instance.state.set('message', error);
+ } else {
+ instance.state.set('message', error.message);
+ }
+
+ return;
+ }
+
+ instance.state.set('actionResult', 'success');
+ instance.state.set('message', 'record has been updated succesfuly');
+ });
+}
--- /dev/null
+/* Set the component style here */
+// "Configuration"
+.os-configuration
+ display: flex;
+ flex-flow: column nowrap;
+ margin: 20px;
+
+ .cl-field-group
+ display: flex;
+ flex-flow: row nowrap;
+ align-items: center;
+ padding: 5px 0;
+
+ .cl-field-label
+ width: 120px;
+ margin: 0 5px;
+
+ >.cl-input
+ display: block;
+ width: 100%;
+ min-height: 34px;
+ padding: 6px 12px;
+ font-size: 14px;
+ line-height: 1.42857143;
+ color: #555;
+ background-color: #fff;
+ background-image: none;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ width: 400px;
+ margin: 0 5px;
+
+ .cl-field-desc
+ margin: 0 5px;
+
+ .js-message-panel
+ margin-top: 20px;
//import * as R from 'ramda';
import * as _ from 'lodash';
import { Environments } from '/imports/api/environments/environments';
-import { //Messages,
- calcIconForMessageLevel, lastMessageTimestamp, calcColorClassForMessagesInfoBox
+import { //Messages,
+ calcIconForMessageLevel, lastMessageTimestamp, calcColorClassForMessagesInfoBox
} from '/imports/api/messages/messages';
import { Template } from 'meteor/templating';
import { Inventory } from '/imports/api/inventories/inventories';
import '/imports/ui/components/messages-info-box/messages-info-box';
import '/imports/ui/components/environment-box/environment-box';
-import './dashboard.html';
+import './dashboard.html';
/*
* Lifecycle methods
icon: calcIconForMessageLevel(boxDef.level),
colorClass: calcColorClassForMessagesInfoBox(boxDef.level),
onMoreDetailsReq: function () {
- $('#messagesModalGlobal').modal('show', {
+ $('#messagesModalGlobal').modal('show', {
dataset: {
messageLevel: boxDef.level,
- }
+ }
});
}
};
argsEnvBox: function (
environmentName,
- regionsCount,
- regions,
- projectsCount,
- projects,
+ regionsCount,
+ regions,
+ projectsCount,
+ projects,
instancesCount,
vservicesCount,
vconnectorsCount,
import { Counts } from 'meteor/tmeasday:publish-counts';
import { Roles } from 'meteor/alanning:roles';
//import { idToStr } from '/imports/lib/utilities';
+import { Counter } from 'meteor/natestrauser:publish-performant-counts';
import '/imports/ui/components/data-cubic/data-cubic';
import '/imports/ui/components/icon/icon';
instance.subscribe('inventory?env+type', env.name, 'vconnector');
instance.subscribe('inventory?env+type', env.name, 'project');
instance.subscribe('inventory?env+type', env.name, 'region');
- instance.subscribe('messages?env+level', env.name, 'info');
- instance.subscribe('messages?env+level', env.name, 'warning');
- instance.subscribe('messages?env+level', env.name, 'error');
+
+ instance.subscribe('messages/count?level&env', 'info', env.name);
+ instance.subscribe('messages/count?level&env', 'warning', env.name);
+ instance.subscribe('messages/count?level&env', 'error', env.name);
let vConnectorCounterName = 'inventory?env+type!counter?env=' +
env.name + '&type=' + 'vconnector';
};
}
- let count = Counts.get('messages?env+level!counter?env=' +
- envName + '&level=' + boxDef.level);
+ let counterName = `messages/count?level=${boxDef.level}&env=${envName}`;
+ let count = Counter.get(counterName);
+
+ //let count = Counts.get('messages?env+level!counter?env=' +
+ // envName + '&level=' + boxDef.level);
let title = _.capitalize(boxDef.level);
new SimpleSchema({
_id: _idFieldDef,
selectedNodeId: R.assoc('optional', true, _idFieldDef),
+ refresh: { type: String, optional: true },
}).validate(data);
store.dispatch(setEnvEnvId(data._id));
########################################################################################
-->
<template name="GraphTooltipWindow">
- <div class="os-graph-tooltip-window {{#if show}}cl-visible{{/if}}"
- style="top: {{ top }}px; left: {{ left }}px;">
+<div class="os-graph-tooltip-window {{#if show}}cl-visible{{/if}}"
+ style="top: {{ top }}px; left: {{ left }}px;">
<div class="sm-label"><u>{{ label }}</u></div>
<div class="sm-title">{{{ title }}}</div>
</div>
import { Template } from 'meteor/templating';
//import { ReactiveDict } from 'meteor/reactive-dict';
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
+import { store } from '/imports/ui/store/store';
+import { closeGraphTooltipWindow } from '/imports/ui/actions/graph-tooltip-window.actions';
import './graph-tooltip-window.html';
*/
Template.GraphTooltipWindow.events({
+ 'mouseout .os-graph-tooltip-window': function(_e, _instance) {
+ /*
+ if (!instance.data.show) { return; }
+
+ e.preventDefault();
+ e.stopPropagation();
+ store.dispatch(closeGraphTooltipWindow());
+ */
+ },
+
+ 'click .os-graph-tooltip-window': function(e, instance) {
+ if (!instance.data.show) { return; }
+
+ e.preventDefault();
+ e.stopPropagation();
+ store.dispatch(closeGraphTooltipWindow());
+ },
});
/*
.os-graph-tooltip-window
visibility: hidden;
+ max-height: 300px;
+ overflow: auto;
position: absolute;
text-align: left;
opacity: 0
- font: normal 18px sans-serif !important;
+ font: normal 16px sans-serif;
/* width: 60px; */
/* height: 28px; */
padding: 20px;
- font: 16px sans-serif;
background: dk-gray1;
color white
border: 2px solid stark-blue
- pointer-events: none;
+ // pointer-events: none;
transition: visibility 0.5s, opacity 0.5s linear
+ .sm-label
+ font-weight: bold;
+
.os-graph-tooltip-window.cl-visible
visibility: visible
opacity: 0.9
transition: visibility 0.2s, opacity 0.2s linear
-
@import 'network-graph-manager/*';
@import 'network-graph/*';
@import 'environment-box/*';
+@import 'configuration/*';
// http://www.apache.org/licenses/LICENSE-2.0 /
/////////////////////////////////////////////////////////////////////////////////////////
/*
- * Template Component: MessagesModal
+ * Template Component: MessagesModal
*/
-
-//import { Meteor } from 'meteor/meteor';
+
+//import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { ReactiveDict } from 'meteor/reactive-dict';
import { Counter } from 'meteor/natestrauser:publish-performant-counts';
//import { Messages } from '/imports/api/messages/messages';
import { Environments } from '/imports/api/environments/environments';
import { idToStr } from '/imports/lib/utilities';
-
+
import '/imports/ui/components/pager/pager';
-import './messages-modal.html';
-
-/*
+import './messages-modal.html';
+
+/*
* Lifecycles
- */
-
+ */
+
Template.MessagesModal.onCreated(function() {
let instance = this;
instance.state = new ReactiveDict();
});
instance.autorun(function () {
-
+
//let amountPerPage = instance.state.get('amountPerPage');
//let page = instance.state.get('page');
let envName = instance.state.get('envName');
instance.state.set('messages', res);
});
});
-});
+});
/*
Template.MessagesModal.rendered = function() {
-};
+};
*/
/*
], {
wait: false
}, function (err, resp) {
- if (err) {
+ if (err) {
console.error(R.toString(err));
- return;
+ return;
}
if (R.isNil(resp.node)) {
return;
}
- Router.go('environment', {
- _id: idToStr(environment._id)
- }, {
+ Router.go('environment', {
+ _id: idToStr(environment._id)
+ }, {
query: {
selectedNodeId: idToStr(resp.node._id)
- }
+ }
});
instance.$('#messagesModalGlobal').modal('hide');
}
});
-
-/*
+
+/*
* Helpers
*/
-Template.MessagesModal.helpers({
+Template.MessagesModal.helpers({
iconType: function () {
let instance = Template.instance();
return instance.state.get('iconType');
return {
disableNext: currentPage * amountPerPage > totalMessages,
disablePrev: currentPage == 1,
- totalPages: totalPages,
+ totalPages: totalPages,
currentPage: currentPage,
onReqNext: function () {
console.log('next');
let page = (currentPage * amountPerPage > totalMessages) ? currentPage : currentPage + 1;
- instance.state.set('page', page);
+ instance.state.set('page', page);
},
onReqPrev: function () {
console.log('prev');
let page = (currentPage == 1) ? currentPage : currentPage - 1;
- instance.state.set('page', page);
+ instance.state.set('page', page);
},
onReqFirst: function () {
console.log('req first');
onReqPage: function (pageNumber) {
console.log('req page');
let page;
- if (pageNumber <= 1) {
- page = 1;
- } else if (pageNumber > Math.ceil(totalMessages / amountPerPage)) {
+ if (pageNumber <= 1) {
+ page = 1;
+ } else if (pageNumber > Math.ceil(totalMessages / amountPerPage)) {
page = totalPages;
} else {
page = pageNumber;
links: [],
nodes: [],
groups: [],
- }
+ },
+ itemOfInterest: null
};
instance.autorun(function () {
return;
}
+ if (instance.simpleState.itemOfInterest === nodeId) {
+ instance.simpleState.itemOfInterest = null;
+ return;
+ }
+
+ instance.simpleState.itemOfInterest = nodeId;
+
Meteor.apply('inventoryFindNode?DataAndAttrs', [ nodeId ],
{ wait: false }, function (err, res) {
if (err) {
}
store.dispatch(
- activateGraphTooltipWindow(res.nodeName, res.attributes, x, y));
+ activateGraphTooltipWindow(res.nodeName, res.attributes, x - 30, y - 10));
});
},
onNodeOut: function (_nodeId) {
- store.dispatch(closeGraphTooltipWindow());
+ //store.dispatch(closeGraphTooltipWindow());
},
onNodeClick: function (_nodeId) {
},
onDragEnd: function () {
isDragging = false;
},
+ onGroupOver: function () {
+ instance.simpleState.itemOfInterest = null;
+ store.dispatch(closeGraphTooltipWindow());
+ },
+ onLinkOver: function (linkId, x, y) {
+ if (isDragging) {
+ return;
+ }
+
+ if (instance.simpleState.itemOfInterest === linkId) {
+ instance.simpleState.itemOfInterest = null;
+ return;
+ }
+
+ instance.simpleState.itemOfInterest = linkId;
+
+ Meteor.apply('linksFind?DataAndAttrs', [ linkId ],
+ { wait: false }, function (err, res) {
+ if (err) {
+ console.error(`error fetching attrs for link for showing: ${R.toString(err)}`);
+ return;
+ }
+
+ store.dispatch(
+ activateGraphTooltipWindow(res.linkName, res.attributes, x - 30, y - 10));
+ });
+ },
};
},
sourceId: link.source,
targetId: link.target,
label: link.link_name,
- _osid: link._id
+ _osid: link._id,
+ _osmeta: {
+ status: link.status,
+ linkId: link._id
+ }
};
let links = R.unionWith(R.eqBy(R.prop('_osid')), graphData.links, [newLink]);
_osmeta: {
type: node.type,
nodeId: node._id,
+ status: node.status,
},
width: 60,
height: 40,
import * as R from 'ramda';
import * as cola from 'webcola';
import { imagesForNodeType, defaultNodeTypeImage } from '/imports/lib/images-for-node-type';
+import * as _ from 'lodash';
import './network-graph.html';
onNodeClick: { type: Function, optional: true },
onDragStart: { type: Function, optional: true },
onDragEnd: { type: Function, optional: true },
+ onGroupOver: { type: Function, optional: true },
+ onLinkOver: { type: Function, optional: true },
}).validate(data);
instance.simpleState.graphData = data.graphData;
instance.onNodeClick = R.defaultTo(() => {}, data.onNodeClick);
instance.onDragStart = R.defaultTo(() => {}, data.onDragStart);
instance.onDragEnd = R.defaultTo(() => {}, data.onDragEnd);
+ instance.onGroupOver = R.defaultTo(() => {}, data.onGroupOver);
+ instance.onLinkOver = R.defaultTo(() => {}, data.onLinkOver);
});
});
instance.onNodeOut,
instance.onNodeClick,
instance.onDragStart,
- instance.onDragEnd
+ instance.onDragEnd,
+ instance.onGroupOver,
+ instance.onLinkOver
);
});
};
onNodeOut,
onNodeClick,
onDragStart,
- onDragEnd
+ onDragEnd,
+ onGroupOver,
+ onLinkOver
) {
let force = genForceCola(cola, d3, w, h);
nodesEl,
linksEl,
drag, zoom, config,
- onNodeOver, onNodeOut, onNodeClick);
+ onNodeOver,
+ onNodeOut,
+ onNodeClick,
+ onGroupOver,
+ onLinkOver
+ );
}
- // d3.select(window).on('resize', resize);
+// d3.select(window).on('resize', resize);
function genSvg(d3, mainElement) {
let svg = d3.select(mainElement).append('svg');
return svg;
}
-function genSvgLinks(g, links, nominal_stroke, default_link_color, initialLinkLabelsFontSize) {
+function genSvgLinks(
+ g,
+ links,
+ nominal_stroke,
+ default_link_color,
+ initialLinkLabelsFontSize,
+ onLinkOver
+) {
let svgLinks = g.selectAll('.link-group')
.data(links, (d) => d._osid);
let svgLinksEnter = svgLinks
.enter()
- .append('g')
- .attr('class', 'link-group')
- .attr('data-link-id', function (d) {
- return d._osid;
- })
+ .append('g')
+ .attr('class', 'link-group')
+ .attr('data-link-id', function (d) {
+ return d._osid;
+ })
;
//let svgLinksExit =
.attr('class', 'link-line')
.style('stroke-width', nominal_stroke)
.style('stroke',
- function(_d) {
- return default_link_color;
- });
+ function(d) {
+ let status = R.defaultTo('', R.path(['_osmeta', 'status'], d));
+ status = _.toLower(status);
+ switch(status) {
+ case 'ok':
+ return 'green';
+ case 'warning':
+ return 'orange';
+ case 'error':
+ return 'red';
+ default:
+ return default_link_color;
+ }
+ })
+ .on('mouseover', function (d) {
+ onLinkOver(d._osmeta.linkId, d3.event.pageX, d3.event.pageY);
+ })
+ ;
let svgLinkLabels = svgLinksEnter
.append('text')
let svgNodesEnter = svgNodes
.enter()
.append('g')
- .attr('class', 'node')
- .attr('data-node-id', (d) => d._osid)
- .call(drag);
+ .attr('class', 'node')
+ .attr('data-node-id', (d) => d._osid)
+ .call(drag);
//let svgNodesExit =
svgNodes
let svgImages = svgNodesEnter.append('image')
.attr('class', 'node-image')
.attr('xlink:href', function(d) {
- return `/${calcImageForNodeType(d._osmeta.type)}`;
+ let status = R.defaultTo('', R.path(['_osmeta', 'status'], d));
+ status = _.toLower(status);
+ return `/${calcImageForNodeType(d._osmeta.type, status)}`;
})
.attr('x', -(Math.floor(imageLength / 2)))
.attr('y', -(Math.floor(imageLength / 2)))
//return [svgNodes];
}
-function calcImageForNodeType(nodeType) {
- return R.defaultTo(defaultNodeTypeImage, R.prop(nodeType, imagesForNodeType));
+function calcImageForNodeType(nodeType, status) {
+ let image = R.defaultTo(defaultNodeTypeImage, R.prop(nodeType, imagesForNodeType));
+ if (typeof image === 'object') {
+ image = R.defaultTo(image.default, image[status]);
+ }
+
+ return image;
}
function genZoomBehavior(d3, config) {
function genForceCola(cola, d3, w, h) {
let force = cola.d3adaptor(d3)
.convergenceThreshold(0.1)
- // .convergenceThreshold(1e-9)
+ //.convergenceThreshold(1e-9)
.linkDistance(120)
.size([w,h]);
.handleDisconnected(true)
.avoidOverlaps(true)
.start(50, 100, 200);
- //.start();
+ //.start();
}
/*
config,
onNodeOver,
onNodeOut,
- onNodeClick) {
+ onNodeClick,
+ onGroupOver,
+ onLinkOver
+) {
state.viewGraph = calcViewGraph(state.graph, state.viewGraph);
zoom.on('zoom', zoomFn);
- genSvgGroups(groupsEl, state.viewGraph.groups, drag, onRenderViewReq);
+ genSvgGroups(groupsEl, state.viewGraph.groups, drag, onRenderViewReq, onGroupOver);
genSvgLinks(
linksEl, state.viewGraph.links,
config.nominal_stroke,
config.default_link_color,
- config.initialLinkLabelsFontSize
+ config.initialLinkLabelsFontSize,
+ onLinkOver
);
genSvgNodes(
state.viewGraph = renderView(force, state,
mainEl, groupsEl, nodesEl, linksEl,
drag, zoom, config,
- onNodeOver, onNodeOut, onNodeClick);
+ onNodeOver, onNodeOut, onNodeClick, onGroupOver, onLinkOver);
});
force.on('tick', tickFn);
state.viewGraph = renderView(force, state,
mainEl, groupsEl, nodesEl, linksEl,
drag, zoom, config,
- onNodeOver, onNodeOut, onNodeClick);
+ onNodeOver, onNodeOut, onNodeClick, onGroupOver, onLinkOver);
}
function tickFn() {
return state.viewGraph;
}
-function genSvgGroups(g, groups, drag, onRenderViewReq) {
+function genSvgGroups(g, groups, drag, onRenderViewReq, onGroupOver) {
let svgGroups = g.selectAll('.group')
- .data(groups, (d) => d._osid);
+ .data(groups, (d) => d._osid);
let enterGroups = svgGroups.enter();
let groupsContainers =
enterGroups
.append('g')
- .attr('class', 'group')
- .attr('data-group-id', (d) => d._osid)
- .call(drag)
- .on('click', function (d) {
- console.log('click', d);
- d.isExpanded = !d.isExpanded;
- onRenderViewReq();
- });
+ .attr('class', 'group')
+ .attr('data-group-id', (d) => d._osid)
+ .call(drag)
+ .on('mouseover', function (_d) {
+ onGroupOver();
+ })
+ .on('click', function (d) {
+ console.log('click', d);
+ d.isExpanded = !d.isExpanded;
+ onRenderViewReq();
+ });
groupsContainers
.append('rect')
- .attr('class', 'group-shape')
- .attr('rx', 8)
- .attr('ry', 8)
- .style('fill', function (_d, _i) { return 'lightblue'; })
+ .attr('class', 'group-shape')
+ .attr('rx', 8)
+ .attr('ry', 8)
+ .style('fill', function (_d, _i) { return 'lightblue'; })
;
groupsContainers
<th>Scan Only Iventory</th>
<th>Scan Only Links</th>
<th>Scan Only Cliques</th>
- <th>Scan Completed</th>
<th>
<a class="sm-table-header"
data-is-sortable="true"
<td>{{ scan.scan_only_inventory }}</td>
<td>{{ scan.scan_only_links }}</td>
<td>{{ scan.scan_only_cliques }}</td>
- <td>{{ scan.scan_completed }}</td>
<td>{{ scan.submit_timestamp }}</td>
<td>{{ scan.start_timestamp }}</td>
<td>{{ scan.end_timestamp }}</td>
return {
selectedEnvironment: selectedEnvironment,
onEnvSelected: function (env) {
- Router.go('environment', { _id: idToStr(env._id) }, { });
+ Router.go('environment', { _id: idToStr(env._id) }, { query: `r=${Date.now()}` });
}
};
}
if (this.ready())
this.layout('landing');
else
- this.render('loading');
+ this.render('loading');
}
});
}
*/
- // if the sub handle returned from waitOn ready() method returns
- // true then we're ready to go ahead and render the page.
+ // if the sub handle returned from waitOn ready() method returns
+ // true then we're ready to go ahead and render the page.
this.render('home');
}
this.render('MessagesList');
}, { });
+Router.route('/configuration', function () {
+ this.render('Configuration');
+}, { });
+
Router.route('/message', function () {
let that = this;
let params = that.params;
data = R.assoc('selectedNodeId', selectedNodeId, data);
}
+ let refresh = that.params.query.r;
+ if (! R.isNil(refresh)) {
+ data = R.assoc('refresh', refresh, data);
+ }
+
return data;
}
});
# run meteor with different mongo
MONGO_URL=mongodb://localhost:27017/osdna meteor run
+# MONGO_URL=mongodb://calipso:calipso_default@64.103.124.119:27017/calipso meteor run