diff options
Diffstat (limited to 'ui/imports/ui/components/messages-list')
3 files changed, 431 insertions, 0 deletions
diff --git a/ui/imports/ui/components/messages-list/messages-list.html b/ui/imports/ui/components/messages-list/messages-list.html new file mode 100644 index 0000000..646b2e9 --- /dev/null +++ b/ui/imports/ui/components/messages-list/messages-list.html @@ -0,0 +1,103 @@ +<!-- +######################################################################################## +# 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 # +######################################################################################## + --> +<template name="MessagesList"> +<div class="os-messages-list cards white"> + <div class="sm-table-section"> + <h3>Messages</h3> + <table class="sm-messages-table table"> + <thead> + <tr> + <th><a class="sm-table-header" + data-is-sortable="true" + data-sort-field="environment" + >Environment<span><i class="{{ fieldSortClass 'environment' }}"></i></span></a></th> + <th><a class="sm-table-header" + data-is-sortable="true" + data-sort-field="viewed" + >Viewed<span><i class="{{ fieldSortClass 'viewed' }}"></i></span></a></th> + <th><a class="sm-table-header">Display Context</a></th> + <th><a class="sm-table-header">Message</a></th> + <th><a class="sm-table-header" + data-is-sortable="true" + data-sort-field="source_system" + >Source System<span><i class="{{ fieldSortClass 'source_system' }}"></i></span></a></th> + <th><a class="sm-table-header" + data-is-sortable="true" + data-sort-field="level" + >Level<span><i class="{{ fieldSortClass 'level' }}"></i></span></a></th> + <th><a class="sm-table-header" + data-is-sortable="true" + data-sort-field="timestamp" + >Timestamp<span><i class="{{ fieldSortClass 'timestamp' }}"></i></span></a></th> + <th><a class="sm-table-header" + data-is-sortable="true" + data-sort-field="related_object_type" + >Related Object Type<span><i class="{{ fieldSortClass 'related_object_type' }}"></i></span></a></th> + <th><a class="sm-table-header">Related Object</a></th> + <th><a class="sm-table-header" + data-is-sortable="true" + data-sort-field="scan_id" + >Scan ID<span><i class="{{ fieldSortClass 'scan_id' }}"></i></span></a></th> + <th><a class="sm-table-header">Actions</a></th> + </tr> </thead> + <tbody> + {{#each message in messages }} + <tr> + <td>{{ message.environment }}</td> + <td>{{ message.viewed }}</td> + <td> + <a class="cl-link sm-display-context-link" + data-env-name="{{ message.environment }}" + data-item-id="{{ message.display_context }}">Link to node</a> + </td> + <td>{{ message.message }}</td> + <td>{{ message.source_system }}</td> + <td>{{ message.level }}</td> + <td>{{ message.timestamp }}</td> + <td>{{ message.related_object_type }}</td> + <td> + {{#if message.related_object }} + {{> InventoryPropertiesDisplay (argsInvPropDisplay message.environment message.related_object) }} + {{/if }} + </td> + <td> + <a class="cl-link sm-scan-id-link" + data-scan-id="{{ toIsoFormatStr message.scan_id }}" + >{{ message.scan_id }} + </a> + </td> + <td> + <div class="sm-action-bar"> + <a href="{{pathFor route='message' + query=(asHash id=(idToStr message._id) action='view') }}" + ><i class="cl-action-icon fa fa-eye" area-hidden="true"></i></a> + + <!--a href="{{pathFor route='message' + query=(asHash id=(idToStr message._id) action='update') }}" + ><i class="cl-action-icon fa fa-pencil" area-hidden="true"></i></a--> + + <!--a href="{{pathFor route='message' + query=(asHash id=(idToStr message._id) action='remove') }}" + ><i class="cl-action-icon fa fa-trash-o" area-hidden="true"></i></a--> + </div> + </td> + </tr> + {{/each }} + </tbody> + </table> + </div> + + <div class="sm-pager-section"> + {{> Pager (argsPager currentPage amountPerPage totalMessages) }} + </div> + +</div> +</template> diff --git a/ui/imports/ui/components/messages-list/messages-list.js b/ui/imports/ui/components/messages-list/messages-list.js new file mode 100644 index 0000000..d0f2730 --- /dev/null +++ b/ui/imports/ui/components/messages-list/messages-list.js @@ -0,0 +1,291 @@ +///////////////////////////////////////////////////////////////////////////////////////// +// 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 / +///////////////////////////////////////////////////////////////////////////////////////// +/* + * Template Component: MessagesList + */ + +//import { Meteor } from 'meteor/meteor'; +import * as R from 'ramda'; +import { Template } from 'meteor/templating'; +import { Counter } from 'meteor/natestrauser:publish-performant-counts'; +import { ReactiveDict } from 'meteor/reactive-dict'; +import { SimpleSchema } from 'meteor/aldeed:simple-schema'; +//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 '/imports/ui/components/inventory-properties-display/inventory-properties-display'; + +import './messages-list.html'; + +/* + * Lifecycles + */ + +Template.MessagesList.onCreated(function() { + var instance = this; + + instance.state = new ReactiveDict(); + instance.state.setDefault({ + env: null, + page: 1, + amountPerPage: 10, + sortField: null, + sortDirection: null, + messsages: [], + }); + + instance.autorun(function () { + //let data = Template.currentData(); + + var controller = Iron.controller(); + var params = controller.getParams(); + var query = params.query; + + new SimpleSchema({ + }).validate(query); + + instance.subscribe('environments_config'); + instance.subscribe('messages/count'); + }); + + instance.autorun(function () { + let amountPerPage = instance.state.get('amountPerPage'); + let page = instance.state.get('page'); + let sortField = instance.state.get('sortField'); + let sortDirection = instance.state.get('sortDirection'); + + Meteor.apply('messages/get?level&env&page&amountPerPage&sortField&sortDirection', [ + null, null, page, amountPerPage, sortField, sortDirection + ], { + wait: false + }, function (err, res) { + if (err) { + console.error(R.toString(err)); + return; + } + + instance.state.set('messages', res); + }); + }); +}); + +/* +Template.MessagesList.rendered = function() { +}; +*/ + +/* + * Events + */ + +Template.MessagesList.events({ + 'click .sm-display-context-link': function (event, _instance) { + event.preventDefault(); + let envName = event.target.dataset.envName; + let nodeId = event.target.dataset.itemId; + + let environment = Environments.findOne({ name: envName }); + + Meteor.apply('inventoryFindNode?env&id', [ + environment.name, + nodeId, + ], { + wait: false + }, function (err, resp) { + if (err) { + console.error(R.toString(err)); + return; + } + + if (R.isNil(resp.node)) { + console.error('error finding node related to message', R.toString(nodeId)); + return; + } + + Router.go('environment', { + _id: idToStr(environment._id) + }, { + query: { + selectedNodeId: idToStr(resp.node._id) + } + }); + + }); + + }, + + 'click .sm-scan-id-link': function (event, _instance) { + event.preventDefault(); + let scanStartTimeStamp = moment(event.target.dataset.scanId).toDate(); + + Meteor.apply('scansFind?start-timestamp-before', [ + scanStartTimeStamp + ], { + wait: false + }, function (err, resp) { + if (err) { + console.error(R.toString(err)); + return; + } + + if (R.isNil(resp.scan)) { + console.error('error finding scan related to message', R.toString(scanStartTimeStamp)); + return; + } + + Router.go('scanning-request', { + _id: idToStr(resp.scan._id) + }, { + query: { + env: idToStr(resp.environment._id), + id: idToStr(resp.scan._id), + action: 'view' + } + }); + + }); + }, + + 'click .sm-table-header': function (event, instance) { + event.preventDefault(); + let isSortable = event.target.dataset.isSortable; + if (! isSortable ) { return; } + + let sortField = event.target.dataset.sortField; + let currentSortField = instance.state.get('sortField'); + let currentSortDirection = instance.state.get('sortDirection'); + + if (sortField === currentSortField) { + let sortDirection = null; + if (currentSortDirection === null) { + sortDirection = -1; + } else if (currentSortDirection === -1) { + sortDirection = 1; + } else if (currentSortDirection === 1) { + sortField = null; + sortDirection = null; + } else { + sortField = null; + sortDirection = null; + } + + instance.state.set('sortField', sortField); + instance.state.set('sortDirection', sortDirection); + + } else { + instance.state.set('sortField', sortField); + instance.state.set('sortDirection', -1); + } + }, +}); + +/* + * Helpers + */ + +Template.MessagesList.helpers({ + messages: function () { + let instance = Template.instance(); + return instance.state.get('messages'); + }, + + currentPage: function () { + let instance = Template.instance(); + return instance.state.get('page'); + }, + + amountPerPage: function () { + let instance = Template.instance(); + return instance.state.get('amountPerPage'); + }, + + totalMessages: function () { + return Counter.get(`messages/count`); + }, + + toIsoFormatStr: function (date) { + if (R.isNil(date)) { + return ''; + } + + let str = moment(date).format(); + return str; + }, + + argsPager: function (currentPage, amountPerPage, totalMessages) { + let instance = Template.instance(); + let totalPages = Math.ceil(totalMessages / amountPerPage); + + return { + disableNext: currentPage * amountPerPage > totalMessages, + disablePrev: currentPage == 1, + totalPages: totalPages, + currentPage: currentPage, + onReqNext: function () { + console.log('next'); + let page = (currentPage * amountPerPage > totalMessages) ? currentPage : currentPage + 1; + instance.state.set('page', page); + }, + onReqPrev: function () { + console.log('prev'); + let page = (currentPage == 1) ? currentPage : currentPage - 1; + instance.state.set('page', page); + }, + onReqFirst: function () { + console.log('req first'); + instance.state.set('page', 1); + }, + onReqLast: function () { + console.log('req last'); + instance.state.set('page', totalPages); + }, + onReqPage: function (pageNumber) { + console.log('req page'); + let page; + if (pageNumber <= 1) { + page = 1; + } else if (pageNumber > Math.ceil(totalMessages / amountPerPage)) { + page = totalPages; + } else { + page = pageNumber; + } + + instance.state.set('page', page); + }, + }; + }, + + fieldSortClass: function (fieldName) { + let instance = Template.instance(); + let classes = 'fa fa-sort'; + if (fieldName === instance.state.get('sortField')) { + let sortDirection = instance.state.get('sortDirection'); + if (sortDirection === -1) { + classes = 'fa fa-sort-desc'; + } else if (sortDirection === 1) { + classes = 'fa fa-sort-asc'; + } + } + + return classes; + }, + + argsInvPropDisplay: function (env, nodeId) { + return { + env: env, + nodeId: nodeId, + displayFn: (node) => { + if (R.isNil(node)) { return ''; } + return `${node.object_name} - ${node.type}`; + } + }; + }, +}); // end: helpers diff --git a/ui/imports/ui/components/messages-list/messages-list.styl b/ui/imports/ui/components/messages-list/messages-list.styl new file mode 100644 index 0000000..adc9500 --- /dev/null +++ b/ui/imports/ui/components/messages-list/messages-list.styl @@ -0,0 +1,37 @@ +.os-messages-list + display: flex; + flex-flow: column nowrap; + margin: 20px; + + .cl-action-icon, + .card.fa.cl-action-icon + font-size: 16px !important; + + .sm-messages-table + th + color: spark-blue + + a + color: spark-blue; + cursor: pointer; + i.fa + padding: 0px 3px; + font-size: small; + + .sm-action-bar + display: flex; + + a + color: spark-blue; + margin: 0px 5px; + cursor: pointer; + + .cl-action-icon + color: gray + + .sm-pager-section + display: flex; + justify-content: center; + + .cl-link + cursor: pointer |