Browse Source

some style changes

Michael Mead 8 years ago
parent
commit
76acbb7bd6

+ 46 - 47
src/api/index.py

@@ -1,7 +1,7 @@
 """
 	This is a RESTful interface implemented using Flask micro framework.
 	The API is driven by configuration that is organized in terms of the monitoring classes
-	
+
 	The API is both restful and websocket/socketio enabled.
 
 	We designed the classes to be reusable (and powered by labels):
@@ -47,7 +47,7 @@ factory = DataSourceFactory()
 
 atexit.register(ThreadManager.stop)
 @app.route('/get/<id>')
-def procs(id):	
+def procs(id):
 	try:
 		gReader = factory.instance(type=class_read,args=p)
 		data =  gReader.read()
@@ -67,14 +67,14 @@ def procs(id):
 				# Let us determine if this is a normal operation or not
 				# We will update the status of the information ...
 				#
-				
-				for row in r[label] :	
-					index = r[label].index(row)			
+
+				for row in r[label] :
+					index = r[label].index(row)
 					if row['label'] in learn:
 						id = row['label']
 						px = ahandler.predict([row],learn[id])
 						if px :
-							
+
 							# row['anomaly'] = px[1]==1
 							print ""
 							print label,' *** ',index
@@ -83,12 +83,12 @@ def procs(id):
 							#
 							# @TODO:
 							# Compile a report here that will be sent to the mailing list
-							# 
-					
+							#
+
 	except Exception, e:
 		print e
 		r = []
-	
+
 	return json.dumps(r)
 
 """
@@ -98,7 +98,7 @@ def procs(id):
 @app.route('/sandbox')
 def sandbox():
 	global CONFIG
-	
+
 	if 'sandbox' in CONFIG: #CONFIG['monitor']:
 		#handler = HANDLERS['sandbox']['class']
 		#conf = HANDLERS['sandbox']['config']
@@ -106,7 +106,7 @@ def sandbox():
 		# p = Factory.instance('sandbox',CONFIG)
 		handler = monitor.Sandbox()
 		conf	= CONFIG['sandbox']
-		
+
 		for id in conf:
 			try:
 				handler.init(conf[id])
@@ -114,27 +114,27 @@ def sandbox():
 			except Exception,e:
 				pass
 	else:
-		
+
 		r = []
 
 
 	return json.dumps(r)
-@app.route('/trends') 
+@app.route('/trends')
 def trends ():
 	id = request.args.get('id')
 	app = request.args.get('app').strip()
 	p = CONFIG['store']['args']
 	class_read = CONFIG['store']['class']['read']
 
-	
-	gReader = factory.instance(type=class_read,args=p)	
+
+	gReader = factory.instance(type=class_read,args=p)
 	r = gReader.read()
 	if id in r:
 		r = r[id] #--matrix
 		series = []
 
 		for row in r:
-			
+
 			series += [item for item in row if str(item['label'])== app]
 		if len(series) > 12 :
 			beg = len(series) - 8
@@ -162,17 +162,18 @@ def dashboard():
 	This function is designed to trigger learning for anomaly detection
 	@TODO: forward this to a socket i.e non-blocking socket
 """
+
 @app.route('/anomalies/get')
 def learn():
 	global CONFIG
 	p = CONFIG['store']['args']
-	class_read = CONFIG['store']['class']['read']	
+	class_read = CONFIG['store']['class']['read']
 	gReader = factory.instance(type=class_read,args=p)
 	d =  gReader.read()
-	
+
 	if 'learn' in d :
 		info = d['learn']
-		
+
 		del d['learn']
 	else :
 		info = []
@@ -182,44 +183,44 @@ def learn():
 		d = d[id]
 		params = {}
 		for item in info:
-			
+
 			label = item['label']
 			params[label] = item
-		
+
 		#apps = list(set(ML.Extract(['label'],d)))
 		r = []
 		if params :
 			#
-			# If we have parameters available 
+			# If we have parameters available
 			p = AnomalyDetection()
-			apps = params.keys()			
+			apps = params.keys()
 			for name in apps :
 				if name not in params:
 					continue
-				_info	= params[name]		
+				_info	= params[name]
 				try:
-					xo 	= ML.Filter('label',name,d)	
+					xo 	= ML.Filter('label',name,d)
 				except Exception,e:
 					xo = []
 					#print name,e
-				if len(xo) == 0:					
-					continue	
+				if len(xo) == 0:
+					continue
 				xo 	= [xo[ len(xo) -1]]
-				
+
 				value	= p.predict(xo,_info)[0]
-				
+
 				if len(value):
 					report = dict(_info,**{'predicton':value})
 					r.append(report)
-				
-				
-				
+
+
+
 			#print app,value
 			#if value is not None:
 			#	r.append(value)
-	
+
 	return json.dumps(r)
-		
+
 
 """
 	This function returns anomalies for a given context or group of processes
@@ -229,12 +230,12 @@ def learn():
 def anomalies_status():
 	global CONFIG
 	p = CONFIG['store']['args']
-	class_read = CONFIG['store']['class']['read']	
+	class_read = CONFIG['store']['class']['read']
 	gReader = factory.instance(type=class_read,args=p)
 	d =  gReader.read()
 	if 'learn' in d :
 		info = d['learn']
-		
+
 		del d['learn']
 	else :
 		info = []
@@ -248,7 +249,7 @@ def anomalies_status():
 def get_folders():
 	global CONFIG
 	p = CONFIG['store']['args']
-	class_read = CONFIG['store']['class']['read']	
+	class_read = CONFIG['store']['class']['read']
 	gReader = factory.instance(type=class_read,args=p)
 	d =  gReader.read()
 	if 'folders' in d:
@@ -256,7 +257,7 @@ def get_folders():
 		hosts = set([row[0]['id'] for row in d])
 		m = {}
 		for id in hosts:
-			for row in d:				
+			for row in d:
 				if id == row[0]['id'] :
 					m[id] = row
 		d = m.values()
@@ -264,11 +265,11 @@ def get_folders():
 			print row[0]['id']
 		# index = len(d) - 1
 		# d = d[index]
-		
-			
+
+
 		# m = {}
 		# for row in d :
-			
+
 		# 	key = row.keys()[0]
 
 		# 	row = row[key]
@@ -281,15 +282,13 @@ def get_folders():
 		# d = r
 	else:
 		d = []
-	
+
 	return json.dumps(d)
-	
+
 if __name__== '__main__':
-	
-#	ThreadManager.start(CONFIG)	
+
+#	ThreadManager.start(CONFIG)
 	if 'port' not in SYS_ARGS.PARAMS :
 		SYS_ARGS.PARAMS['port'] = 8484
 	PORT = int(SYS_ARGS.PARAMS['port'])
 	app.run(host='0.0.0.0' ,port=PORT,debug=True,threaded=True)
-
-	

+ 219 - 10
src/api/static/css/default.css

@@ -3,7 +3,7 @@ body, .default {
 	font-family:sans-serif;
 	font-weight:lighter;
 	padding:10px;
-	
+
 }
 .jsgrid-grid-header{
 	background: #f9f9f9;
@@ -40,7 +40,7 @@ body, .default {
 	height:30px;
 	font-family:sans-serif;
 	font-weight:lighter;
-	
+
 }
 .button {
 	padding:8px;
@@ -53,7 +53,7 @@ body, .default {
 .button:hover{
 	background-color:#4682B4 ;
 	color:#ffffff;
-	
+
 }
 .no-border{ border:1px solid transparent}
 .border { border:1px solid #CAD5E0}
@@ -64,7 +64,7 @@ body, .default {
 .grid {
 	font-family:sans-serif;
 	font-weight:lighter;
-	
+
 	margin:4px;
 	padding:4px;
 }
@@ -78,7 +78,7 @@ body, .default {
 .grid .fa-times {color:maroon; }
 
 .menu {
-	margin:4px;
+	margin:5px;
 	padding:4px;
 }
 .menu .fa-chevron-right {color:transparent; margin:4px; }
@@ -104,11 +104,11 @@ input[type=text]:focus{
 .padding-2x{padding:4px;}
 .margin-2x {margin:4px;}
 .info {
-	
+
 	margin:4px;
 	width:43%;
-	
-	
+
+
 }
 .height-quarter{height:24%;}
 .height-half{height:47%}
@@ -121,7 +121,7 @@ input[type=text]:focus{
 .fa-warning, .warning{color:orange}
 .number {font-size:42px; font-weight:lighter; padding:2px; margin:2px;}
 
-.action {cursor:pointer; padding:2px; margin:2px; border:1px solid transparent}
+.action {cursor:pointer; padding:1px; margin:1px; border:1px solid transparent}
 .action:hover { border-bottom-color:#4682B4}
 .shadow{box-shadow: 7px 7px 5px #888888;}
 .gradient {
@@ -142,5 +142,214 @@ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0,
 background-image: -webkit-linear-gradient(top, #CAD5E0 0%, #F3F3F3 40%);
 
 background-image: linear-gradient(to bottom, #CAD5E0 0%, #F3F3F3 40%);
-	
+
+}
+
+/* ----------- Non-Retina Screens ----------- */
+@media screen
+  and (min-device-width: 1200px)
+  and (max-device-width: 1600px)
+  and (-webkit-min-device-pixel-ratio: 1) {
+}
+
+/* ----------- Retina Screens ----------- */
+@media screen
+  and (min-device-width: 1200px)
+  and (max-device-width: 1600px)
+  and (-webkit-min-device-pixel-ratio: 2)
+  and (min-resolution: 192dpi) {
+}
+
+/* ----------- iPad mini ----------- */
+
+/* Portrait and Landscape */
+@media only screen
+  and (min-device-width: 768px)
+  and (max-device-width: 1024px)
+  and (-webkit-min-device-pixel-ratio: 1) {
+      }
+
+}
+
+/* Portrait */
+@media only screen
+  and (min-device-width: 768px)
+  and (max-device-width: 1024px)
+  and (orientation: portrait)
+  and (-webkit-min-device-pixel-ratio: 1) {
+
+}
+
+/* Landscape */
+@media only screen
+  and (min-device-width: 768px)
+  and (max-device-width: 1024px)
+  and (orientation: landscape)
+  and (-webkit-min-device-pixel-ratio: 1) {
+
+}
+
+/* ----------- iPad 1 and 2 ----------- */
+/* Portrait and Landscape */
+@media only screen
+  and (min-device-width: 768px)
+  and (max-device-width: 1024px)
+  and (-webkit-min-device-pixel-ratio: 1) {
+      .block {display: inline-block;}
+
+}
+
+/* Portrait */
+@media only screen
+  and (min-device-width: 768px)
+  and (max-device-width: 1024px)
+  and (orientation: portrait)
+  and (-webkit-min-device-pixel-ratio: 1) {
+
+}
+
+/* Landscape */
+@media only screen
+  and (min-device-width: 768px)
+  and (max-device-width: 1024px)
+  and (orientation: landscape)
+  and (-webkit-min-device-pixel-ratio: 1) {
+
+}
+
+/* ----------- iPad 3 and 4 ----------- */
+/* Portrait and Landscape */
+@media only screen
+  and (min-device-width: 768px)
+  and (max-device-width: 1024px)
+  and (-webkit-min-device-pixel-ratio: 2) {
+
+}
+
+/* Portrait */
+@media only screen
+  and (min-device-width: 768px)
+  and (max-device-width: 1024px)
+  and (orientation: portrait)
+  and (-webkit-min-device-pixel-ratio: 2) {
+
+}
+
+/* Landscape  ////////////////////////////////////////////////////////////////////////////////////////////////////// */
+@media only screen
+  and (min-device-width: 768px)
+  and (max-device-width: 1024px)
+  and (orientation: landscape)
+  and (-webkit-min-device-pixel-ratio: 2) {
+
+}
+
+/* ----------- iPhone 4 and 4S ----------- */
+
+/* Portrait and Landscape */
+@media only screen
+  and (min-device-width: 320px)
+  and (max-device-width: 480px)
+  and (-webkit-min-device-pixel-ratio: 2) {
+
+}
+
+/* Portrait */
+@media only screen
+  and (min-device-width: 320px)
+  and (max-device-width: 480px)
+  and (-webkit-min-device-pixel-ratio: 2)
+  and (orientation: portrait) {
+}
+
+/* Landscape */
+@media only screen
+  and (min-device-width: 320px)
+  and (max-device-width: 480px)
+  and (-webkit-min-device-pixel-ratio: 2)
+  and (orientation: landscape) {
+
+}
+
+/* ----------- iPhone 5 and 5S ----------- */
+
+/* Portrait and Landscape */
+@media only screen
+  and (min-device-width: 320px)
+  and (max-device-width: 568px)
+  and (-webkit-min-device-pixel-ratio: 2) {
+
+}
+
+/* Portrait */
+@media only screen
+  and (min-device-width: 320px)
+  and (max-device-width: 568px)
+  and (-webkit-min-device-pixel-ratio: 2)
+  and (orientation: portrait) {
+}
+
+/* Landscape */
+@media only screen
+  and (min-device-width: 320px)
+  and (max-device-width: 568px)
+  and (-webkit-min-device-pixel-ratio: 2)
+  and (orientation: landscape) {
+
+}
+
+/* ----------- iPhone 6 ----------- */
+
+/* Portrait and Landscape */
+@media only screen
+  and (min-device-width: 375px)
+  and (max-device-width: 667px)
+  and (-webkit-min-device-pixel-ratio: 2) {
+
+}
+
+/* Portrait */
+@media only screen
+  and (min-device-width: 375px)
+  and (max-device-width: 667px)
+  and (-webkit-min-device-pixel-ratio: 2)
+  and (orientation: portrait) {
+
+}
+
+/* Landscape */
+@media only screen
+  and (min-device-width: 375px)
+  and (max-device-width: 667px)
+  and (-webkit-min-device-pixel-ratio: 2)
+  and (orientation: landscape) {
+
+}
+
+/* ----------- iPhone 6+ ----------- */
+
+/* Portrait and Landscape */
+@media only screen
+  and (min-device-width: 414px)
+  and (max-device-width: 736px)
+  and (-webkit-min-device-pixel-ratio: 3) {
+
+}
+
+/* Portrait */
+@media only screen
+  and (min-device-width: 414px)
+  and (max-device-width: 736px)
+  and (-webkit-min-device-pixel-ratio: 3)
+  and (orientation: portrait) {
+
+}
+
+/* Landscape */
+@media only screen
+  and (min-device-width: 414px)
+  and (max-device-width: 736px)
+  and (-webkit-min-device-pixel-ratio: 3)
+  and (orientation: landscape) {
+
 }

+ 14 - 0
src/api/static/css/reflect.css

@@ -0,0 +1,14 @@
+.block {
+    border: 2px solid black;
+    display: inline-block;
+}
+
+.jsgrid-cell { overflow:hidden; }
+
+
+/* ----------- working media query (laptop) ----------- */
+
+@media screen
+    and (max-device-width: 900px) {
+
+    }

+ 88 - 88
src/api/static/js/dashboard.js

@@ -3,38 +3,38 @@ var monitor = {}
 monitor.utils = {}
 monitor.utils.get = {}
 monitor.utils.get.time = function (item) {
-	// date = ([item.day + '-' + MONTHS[item.month] + '-' + item.year, hour + ':' + item.minute]).join(' ')	
+	// date = ([item.day + '-' + MONTHS[item.month] + '-' + item.year, hour + ':' + item.minute]).join(' ')
 	var hour = item.hour > 9 ? item.hour : ('0' + item.hour)
 	if (hour > 12) {
 		var units = 'PM'
 	} else {
 		var units = 'AM'
 	}
-	return ([hour+':'+item.minute,units]).join(' ')	
+	return ([hour+':'+item.minute,units]).join(' ')
 }
 monitor.utils.get.dateTime = function (item) {
 	var time = monitor.utils.get.time(item)
-	return ([item.day+'-'+MONTHS[item.month]+'-'+item.year,time]).join(' ')	
-} 
+	return ([item.day+'-'+MONTHS[item.month]+'-'+item.year,time]).join(' ')
+}
 monitor.processes = {}
 monitor.processes.fetch = function(){
 	var httpclient = HttpClient.instance()
 	httpclient.get(HTTP_CONTEXT+'/get/processes',monitor.processes.init);
-	
+
 }
 
 monitor.processes.init = function (x) {
-	
+
 	var r = JSON.parse(x.responseText)
-	monitor.processes.summary.init(r) 
-	var keys = jx.utils.keys(r)	
+	monitor.processes.summary.init(r)
+	var keys = jx.utils.keys(r)
 	jx.dom.set.value('menu','')
 	jx.utils.patterns.visitor(keys,function(label){
 		var div = jx.dom.get.instance('DIV')
 		var frame= jx.dom.get.instance('DIV')
 		var i	= jx.dom.get.instance('I')
 		i.className = 'fa fa-chevron-right left'
-		
+
 		div.innerHTML	= label
 		frame.data	= r[label]
 		frame.label	= label
@@ -49,13 +49,13 @@ monitor.processes.init = function (x) {
 		jx.dom.append('menu',frame)
 	})
 	//
-	// Auto start the first item in the menu 
+	// Auto start the first item in the menu
 	// This is designed not to let the user wander or wonder what is going on
 	//
 	var nodes = jx.dom.get.children('menu')
 	if (nodes.length > 0) {
 		nodes[0].click()
-	} else { 
+	} else {
 		//
 		// We should hide the panes for this
 		//
@@ -73,19 +73,19 @@ monitor.processes.init = function (x) {
 monitor.processes.render = function(label,data) {
 
 	data = jx.utils.patterns.visitor(data,function(row){
-		var status = {"idle":'<i class="fa fa-ellipsis-h" title="IDLE"></i>',"running":'<i class="fa fa-check" title="RUNNING"></i>',"crash":'<i class="fa fa-times" title="CRASHED"></i>'}	
+		var status = {"idle":'<i class="fa fa-ellipsis-h" title="IDLE"></i>',"running":'<i class="fa fa-check" title="RUNNING"></i>',"crash":'<i class="fa fa-times" title="CRASHED"></i>'}
 		if (!row.status.match(/class/)) {
 			row.status_id = row.status
-			row.status = status[row.status]		
-			
+			row.status = status[row.status]
+
 		}
 		return row
 	})
 	jx.dom.set.value('latest_processes','') ;
 	jx.dom.set.value('latest_processes_label', label)
-	
+
 	var options = {
-		width: $('#latest_processes').width(), height:'auto'
+		width: "90%", height:'auto', autoload:true
 	}
 	options.paging = true
 	options.pageSize = 4
@@ -95,10 +95,10 @@ monitor.processes.render = function(label,data) {
     	options.pagerFormat= "{prev} Page {pageIndex} of {pageCount} {next}"
     	options.pagePrevText= '<i class="fa fa-chevron-left"></i>'
     	options.pageNextText= "<i class='fa fa-chevron-right small' title='Next'> </i>"
-	
+
 	options.data = data
 	options.rowClass = function (item, index,evt) {
-		
+
 		return 'small'
 	}
 	options.rowClick = function(args){
@@ -106,19 +106,19 @@ monitor.processes.render = function(label,data) {
 		var id 	= jx.dom.get.value('latest_processes_label')
 		var app = item.label
 		monitor.processes.trend.init(id, app)
-		
+
 		if (item.anomaly == true) {
 			jx.dom.show('has_anomaly')
 		} else {
 			jx.dom.hide('has_anomaly')
 		}
 		// var hour = item.hour < 10? ('0'+item.hour): item.hour
-		// date = ([item.day + '-' + MONTHS[item.month] + '-' + item.year, hour + ':' + item.minute]).join(' ')	
-		
+		// date = ([item.day + '-' + MONTHS[item.month] + '-' + item.year, hour + ':' + item.minute]).join(' ')
+
 		jx.dom.set.value('node_last_lookup',monitor.utils.get.dateTime(item))
 
 	}
-	
+
 	options.autoload  = true
 	options.fields = [
 		{ name: 'label', type: 'text', title: "Process", headercss: "small bold", css: "small"},
@@ -141,7 +141,7 @@ monitor.processes.trend.init = function (label,app) {
 		var logs = JSON.parse(x.responseText)
 		var dom = jx.dom.get.instance('trend_info');
 		dom.logs = logs
-		jx.dom.set.value('trend_info',app.trim()) 
+		jx.dom.set.value('trend_info',app.trim())
 		// jx.dom.set.attribute(label,'logs',logs)
 		monitor.processes.trend.render(logs,null,app)
 	})
@@ -151,7 +151,7 @@ monitor.processes.trend.render = function (logs, key,label) {
 	// 	key = 'memory_usage'
 	// }
 	// if (logs == null || label == null){
-		
+
 	// 	logs = jx.dom.get.instance('trend_info').logs
 	// 	label= jx.dom.get.value('trend_info') ;
 	// }
@@ -165,21 +165,21 @@ monitor.processes.trend.render = function (logs, key,label) {
 	conf.data = {}
 	conf.options = { legend: { position: 'bottom' } }
 	conf.options.scales = {}
-	conf.options.scales.yAxes = [  
+	conf.options.scales.yAxes = [
 		{id:'0',scaleLabel:{display:true,labelString:'CPU & MEMORY %'},ticks:{min:0,max:100,beginAtZero:true},gridLines: {display:false}}
 		// {id:'1',position:'right',scaleLabel:{display:true,labelString:'PROCESS COUNT'},ticks:{min:0,stepSize:1,beginAtZero:true},gridLines: {display:false}}
 	]
 	conf.options.scales.xAxes = [
 		{
-			
+
 			gridLines: {display:false},
-			
+
 			time: {
 				format:'HH:mm'
 			}
-			
+
 		}
-		
+
 	]
 	conf.data.datasets = [	]
 	var x_axis = []
@@ -199,26 +199,26 @@ monitor.processes.trend.render = function (logs, key,label) {
 		if (_x[x] == null ){//||(_x[x] == null && _y[y] == null)) {
 			_x[x] = 1
 			// _y[y] = 1
-			x_axis.push(x)	
+			x_axis.push(x)
 			cpu.data.push({ x: x, y: item.cpu_usage })
 			mem.data.push({x:x,y:item.memory_usage})
 			// proc.data.push({x:x,y:item.proc_count})
 			// return {x:x,y:y}
-			
+
 		}
-		
+
 	})
-	
+
 	var item = logs[logs.length - 1]
 	jx.dom.set.value('trend_last_lookup',monitor.utils.get.dateTime(item))
-	
+
 	conf.data.datasets = [cpu,mem]
 	x_axis = jx.utils.unique(x_axis)
 	conf.data.labels = x_axis
 	// console.log(conf)
 	jx.dom.append('trends_chart',context)
 	var chart = new Chart(context,conf)
-	
+
 }
 
 monitor.processes.summary = {}
@@ -236,10 +236,10 @@ monitor.processes.summary.init = function(logs){
 	for( label in logs ){
 		var rows = logs[label]
 		series[label] = {data:[0,0,0],label:label}
-		
+
 		jx.utils.patterns.visitor(rows,function(item){
 			if (date == null) {
-				
+
 				// date = new Date(item.year,item.month-1,item.day,item.hour,item.minute)
 				// date = ([item.day + '-' + MONTHS[item.month] + '-' + item.year, item.hour + ':' + item.minute]).join(' ')
 				date = monitor.utils.get.dateTime(item)
@@ -252,7 +252,7 @@ monitor.processes.summary.init = function(logs){
 				xc += 1
 			}
 		})
-		
+
 	}
 	var data = {labels:['Running','Crash','Idle'],datasets:[{data:[xr,xc,xi],backgroundColor:[RUNNING_COLOR,CRASH_COLOR,IDLE_COLOR/**COLORS[11],COLORS[2],COLORS[100]*/]}]}
 	var context = jx.dom.get.instance('CANVAS')
@@ -261,22 +261,22 @@ monitor.processes.summary.init = function(logs){
 	jx.dom.set.value('total-crash', xc)
 	jx.dom.set.value('total-idle', xi)
 	// jx.dom.set.value('total-apps', xr + xi + xc)
-	
-	
+
+
 	jx.dom.set.value('app-summary-date', date)
 	jx.dom.set.value('summary_chart','')
 	jx.dom.append('summary_chart', context)
 	$("#doughnut").attr('width', 50)
 	$("#doughnut").attr('height', 50)
-	
+
 	var conf = {}//width:100,height:100}//width:'auto',height:$('#process_summary').height}
-	
+
 	conf.type = 'doughnut'
 	conf.responsive = true
 	conf.data = data
 	conf.options = { legend: { position: 'right' }, repsonsive: true }
 	var _chart = new Chart(context,conf)
-	
+
 	$('#summary_chart').click(function (evt) {
 		console.log(_chart)
 		console.log($(_chart))
@@ -286,17 +286,17 @@ monitor.processes.summary.init = function(logs){
 	jx.dom.set.value('summary_ranking','')
 	context = jx.dom.get.instance('CANVAS')
 	jx.dom.append('summary_ranking',context)
-	
+
 	conf = { type: 'bar', responsive: true }
-	
+
 	conf.options={scales:{xAxes:[{gridLines: {display:false}}],yAxes:[{gridLines: {display:false},scaleLabel:{display:true,labelString:'PROCESS COUNTS'} }] }}
 	conf.options.legend ={position:'right'}
 	/*
 	conf.data = {labels:['Running','Idle','Crash']}
 	var labels = jx.utils.keys(series)
-	
+
 	var i = 0
-	conf.data.datasets = jx.utils.patterns.visitor(labels,function(id){ 
+	conf.data.datasets = jx.utils.patterns.visitor(labels,function(id){
 		series[id].backgroundColor = COLORS[i++]
 		return series[id]})
 	chart = new Chart(context,conf);
@@ -305,7 +305,7 @@ monitor.processes.summary.init = function(logs){
 	conf.data = { labels: labels, backgroundColor:colors }
 	var xr = [], xi = [], xc = [],xr_bg = [],xc_bg = [],xi_bg = []
 	jx.utils.patterns.visitor(labels, function (id) {
-		
+
 		var rows = logs[id]
 		var index = xr.length
 		xr_bg[index] = RUNNING_COLOR
@@ -316,25 +316,25 @@ monitor.processes.summary.init = function(logs){
 			xc[index] = 0
 			xi[index] = 0
 		}
-		
+
 		jx.utils.patterns.visitor(logs[id], function (row) {
-			
+
 			if (row.status.match(/running/i)) {
 				xr[index] += 1
-				
+
 			} else if (row.status.match(/idle/i)) {
 				xi[index] += 1
-				
+
 			} else {
 				xc[index] += 1
-				
+
 			}
 		})
 	})
-	
+
 	conf.data.datasets = [{ label: 'Running', data:xr,backgroundColor:xr_bg},{label:'Crash',data:xc,backgroundColor:xc_bg},{label:'Idle',data:xi,backgroundColor:xi_bg} ]
 	chart = new Chart(context, conf)
-	
+
 }
 
 monitor.sandbox = {}
@@ -342,9 +342,9 @@ monitor.sandbox.init = function () {
 	jx.dom.hide('inspect_sandbox')
 	var httpclient = HttpClient.instance()
 	httpclient.get(HTTP_CONTEXT+'/sandbox', function (x) {
-		
+
 		var r = JSON.parse(x.responseText)
-		
+
 		if (r.length > 0) {
 			jx.dom.show('sandbox')
 			monitor.sandbox.render(r);
@@ -355,19 +355,19 @@ monitor.sandbox.init = function () {
 }
 monitor.sandbox.render = function (logs) {
 	// months = { 1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr', 5: 'May', 6: 'Jun', 7: 'Jul', 8: 'Aug', 9: 'Sep', 10: 'Oct', 11: 'Nov', 12: 'Dec' }
-	
+
 	// var d = ([logs[0].day, '-', MONTHS[logs[0].month], '-', logs[0].year, ' ', logs[0].hour, ':', logs[0].minute]).join('')
 	var item = logs[logs.length -1]
 	jx.dom.set.value('sandbox_date', monitor.utils.get.dateTime(item))
-	
+
 	var options = { width: $('#sandbox_status').width()-8, height: 'auto' }
-	options.data = jx.utils.patterns.visitor(logs, function (item) { 
+	options.data = jx.utils.patterns.visitor(logs, function (item) {
 		if (item.value == 100) {
 			item.status = '<i class="fa fa-check" style="color:green"></i>'
 		} else {
 			item.status = '<i class="fa fa-download" style="color:black"></i>'
 		}
-		return item		
+		return item
 	})
 	options.paging = true
 	options.pageSize = 4
@@ -378,7 +378,7 @@ monitor.sandbox.render = function (logs) {
 	options.pagePrevText = '<i class="fa fa-chevron-left"></i>'
 	options.pageNextText = "<i class='fa fa-chevron-right small' title='Next'> </i>";
 	options.rowClass = function (item) {
-		
+
 		if (item.value < 70) {
 			return 'bad'
 		} else if (item.value < 100) {
@@ -395,7 +395,7 @@ monitor.sandbox.render = function (logs) {
 			dom.type = 'hidden'
 			dom.name = 'missing'
 			dom.value = JSON.stringify(item.missing)
-			
+
 			form.action 	= HTTP_CONTEXT+'/download'
 			form.method = 'POST'
 			form.appendChild(dom)
@@ -407,11 +407,11 @@ monitor.sandbox.render = function (logs) {
 		{name:"status",title:"",width:20},
 		{ name: 'label',title:'Virtual Environment Label',type:'text',css:'small',headercss:'small bold' },
 		{ name: 'value', title:'Completeness %',type: 'number', css: 'small', headercss: 'small bold' }
-		
+
 	]
 	var grid = $('#sandbox_status').jsGrid(options)
 	jx.dom.show('inspect_sandbox')
-	
+
 }
 
 
@@ -427,7 +427,7 @@ monitor.folders.init = function () {
 			// item.id = id
 			data = data.concat(item)
 		}
-		
+
 		monitor.folders.render.init(data)
 	})
 }
@@ -436,20 +436,20 @@ monitor.folders.search.reset = function () {
 	jx.dom.set.value('folder_search', '')
 	var data = jx.dom.get.attribute('folder_search', 'data')
 	monitor.folders.render.summary(data)
-	
+
 }
 monitor.folders.search.init = function(){
 	var term = jx.dom.get.value('folder_search')
 	var data = jx.dom.get.attribute('folder_search', 'data')
-	
+
 	term = term.replace(/ /g,'')
 	if (term.length == 0) {
 		monitor.folders.render.summary(data)
 	} else if (term.length > 0) {
-		
+
 		data = jx.utils.patterns.visitor(data, function (row) {
 			pattern = "(.*" + term + ".*)"
-			
+
 			if (row.id.match(pattern)) {
 				return row
 			}
@@ -473,7 +473,7 @@ monitor.folders.show.grid = function () {
 		$('#folder_plan').slideUp(function () {
 			$('#folder_summary').slideDown()
 		})
-	
+
 }
 /***
  * This function is designed to establish a folder clean up strategy i.e  :
@@ -491,7 +491,7 @@ monitor.folders.render.details = function (folder,data) {
 		var xy = r[i]
 		var mode = jx.math.mode(jx.utils.vector('x', xy))
 		var yvalues = jx.utils.patterns.visitor(xy, function (row) {
-			if (row.x == mode) { 
+			if (row.x == mode) {
 				return row.y
 			}
 		})
@@ -514,7 +514,7 @@ monitor.folders.render.details = function (folder,data) {
 			prefix = 'size'
 			var mean = jx.math.sum(yvalues)
 			var max = 0// (mean + (1.5 * sd))
-			if (mean > 1000) { 
+			if (mean > 1000) {
 				divide_by = 1000
 				units = 'GB'
 			} else {
@@ -541,15 +541,15 @@ monitor.folders.render.details = function (folder,data) {
 		monitor.folders.show.plan()
 
 	}
-	
+
 	jx.dom.set.value('folder_name', folder)
-	
-	
-	
-	
+
+
+
+
 }
 monitor.folders.render.summary = function (data) {
-	
+
 	jx.dom.set.value('gridfolders', '')
 	var options = {
 		width: $('#gfolderframe').width()-8, height:'auto'
@@ -562,15 +562,15 @@ monitor.folders.render.summary = function (data) {
     	options.pagerFormat= "{prev} Page {pageIndex} of {pageCount} {next}"
     	options.pagePrevText= '<i class="fa fa-chevron-left"></i>'
     	options.pageNextText= "<i class='fa fa-chevron-right small' title='Next'> </i>"
-	
+
 	options.data = data
 	options.rowClass = function (item, index,evt) {
-		
+
 		return 'small'
 	}
 	options.rowClick = function(args){
 		// var item = args.item
-		
+
 		// age = jx.utils.patterns.visitor(item.details.age, function (row) {
 		// 	return {y:row[0],x:row[1]}
 		// })
@@ -586,26 +586,26 @@ monitor.folders.render.summary = function (data) {
 	options.fields = [
 		{ name: 'id', type: 'text', title: "Host", headercss: "small bold", css: "small"},
 		{ name: 'name', type: 'text', title: "Folder Name", headercss: "small bold", css: "small"},
-		
+
 		{ name: "size", type: "number", title: "Folder Size", type: "number", headercss: "small bold" },
 		{ name: "count", type: "number", title: "File Count", type: "number", headercss: "small bold" }
 	]
 	var grid = $('#gridfolders').jsGrid(options) ;
-	
+
 }
 monitor.menu = {}
 monitor.menu.event = {}
 monitor.menu.event.toggle = function () {
 	var dom = jx.dom.get.instance('menuframe')
 	var value = dom.style.marginLeft.trim()
-	
+
 	if (value==0 || value == "0px" || value == "") {
-		var width = -$(dom).width() - 10
-		$('#menuframe').animate({marginLeft:"-12%"})
+		var width = -$(dom).width() - 20
+		$('#menuframe').animate({marginLeft:"-20%"})
 	} else {
 		$('#menuframe').animate({marginLeft:"0"})
 	}
-	
+
 }
 /**
  * Socket handler, check for learning status

+ 154 - 134
src/api/templates/dashboard.html

@@ -4,8 +4,11 @@
 <link type="text/css" rel="stylesheet" href="{{ context }}/static/js/jsgrid/jsgrid.min.css" >
 <link type="text/css" rel="stylesheet" href="{{ context }}/static/js/jsgrid/jsgrid-theme.min.css" >
 <link href="{{context}}/static/css/default.css" rel="stylesheet" type="text/css">
+<link href="{{context}}/static/css/reflect.css" rel="stylesheet" type="text/css">
 <link href="{{context}}/static/css/fa/css/font-awesome.min.css" rel="stylesheet" type="text/css">
 <link rel="icon" href="data:;base64,iVBORw0KGgo=">
+<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
+
 
 <script src="{{ context }}/static/js/jquery/jquery.min.js"></script>
 <script src="{{context}}/static/js/chart.js/chart.bundle.js"></script>
@@ -31,146 +34,163 @@
 		<div class="">{{title}}</div>
 		<div class="small" style="margin:4px">The Phi Technology LLC</div>
 	</div>
-	<i class="fa fa-reorder default left action" onclick="monitor.menu.event.toggle()"></i>
-	<div id="menuframe" class="left small " style="width:10%; height:90%">
+
+	<i class="fa fa-reorder default left action" onclick="monitor.menu.event.toggle()"></i>  <!-- TODO: MOVE MORE LEFT -->
+	<div id="menuframe" class="left small" style="width:10%; height:100%">
 		 <div id="menu" class="menu"></div>
 	</div>
 
-	<div class="left info ">
-		<div class=" border-right" style="margin:4px; margin-top:2%">
-			<div class="" style="height:28px; ">
-				<div class=" bold">Monitoring
-					<span id="latest_processes_label" class="default bold"></span>
-				</div>
-				<div class="small">Last Lookup <span id="node_last_lookup"></span></div>
-
-			</div>
-
-			<div class = "" style="padding:2px; margin:4px; height:170px">
-				<div id="latest_processes" class="grid" ></div>
-			</div>
-			<div style="height:22px; padding:2px" class="small">
-				<div id="latest_process_pager" align="center"></div>
-			</div>
-		</div>
-		<div id="process_summary" class="  grid border-right" style="margin:4px; margin-top:2%">
-			<div style="margin:4px; padding:2px; margin-bottom:4px; height:28px">
-				<div class="bold" style="color:#4682B4">Application Summary By Status</div>
-				<div  class="small">Latest Lookup <span id="app-summary-date"></span></div>
-			</div>
-
-			<div class=""  style="padding:2px; height:250px; margin:4px; margin-top:10px">
-				<div class=" " style="height:100%">
-					<div class="small left" style="margin-left:2%; margin-top:1%">
-						<div class="bold">Total Applications that have:</div>
-						<br>
-							<div style="margin:0px; margin-left:20px; padding:4px; height:12px"><div class="left width-half"><i class="fa fa-check"></i> Running</div> <span id="total-running" class="right"></span></div>
-							<div style="margin:0px; margin-left:20px; padding:4px; height:12px"><div class="left width-half"><i class="fa fa-times"></i> Crash</div> <span id="total-crash" class="right"></span></div>
-							<div style="margin:0px; margin-left:20px; padding:4px; height:12px"><div class="left width-half"><i class="fa fa-ellipsis-h"></i> Idle</div> <span id="total-idle" class="right"></span></div>
-
-
-					</div>
-					<div id="summary_chart" class="right width-half"></div>
-				</div>
-
-			</div>
-			<div id="summary_details" class="right"></div>
-		</div>
-
-		<div class="   grid border-right" style="margin:4px; margin-top:10px;">
-			<div style="height:28px">
-				<div class="bold" style="margin:4px; padding:4px; color:#4682B4;">Application Summary By Groups</div>
-			</div>
-			<div class="width" id="summary_ranking" style=" margin:4px; padding:2px; text-transform:capitalize"></div>
-		</div>
-	</div>
 	<div class="left info">
-		<div class="" style="padding:4px; margin-top:2%">
-			<div class="" style="height:28px">
-				<div class="small bold">CPU & Memory Usage Trend for <i class="fa fa-quote-left"></i> <span id="trend_info" class="default bold"></span> <i class="fa fa-quote-right"></i></div>
-				<div class="small">Last Lookup <span id="trend_last_lookup"></span> <i id="has_anomaly" class="fa fa-warning right" ></i></div>
-
-
-			</div>
-
-			<div  style="height:270px; margin-top:4px">
-				<div id="trends_chart" class="small grid" style="height:250px"></div>
-			</div>
-		</div>
-		<div id="sandbox" class="border-top" style="padding:4px; margin-top:10px">
-			<div style="height:28px">
-				<div id="inspect_sandbox" class="right button border" style="display:none" onclick="monitor.sandbox.init()">Inspect</div>
-				<div class="bold">Python Virtual Environment Analysis</div>
-
-				<div class="small">Last Lookup <span id="sandbox_date"></span></div>
-			</div>
-
-			<div class=" " style="margin-top:10px; height:135px">
-				<div id="sandbox_status" class="">
-				</div>
-				<div id="sandbox_pager"></div>
-			</div>
-		</div>
-		<div style="margin-top:2%">
-			<div id="folder_summary" class="">
-				<div style="height:28px">
-
-					<div class="bold">Folder Analysis/Monitoring</div>
-					<div class="small">Powered By Machine Learning</div>
-				</div>
-				<div class="">
-					<div class=" border-top" style="margin-top:4px; padding:2px; height:34px">
-						<i class="fa fa-search left" style="margin:4px; padding:4px; ; color:gray;"></i>
-						<input id="folder_search" type="text" class="small left" placeholder="hostname" style="width:87%; padding-left:4px;" onkeyup="monitor.folders.search.init()"/>
-						<i class="fa fa-trash right action right" style="margin:4px; padding:4px; color:maroon" onclick="monitor.folders.search.reset()"></i>
-					</div>
-					<div id="gfolderframe" style="margin-top:10px; height:170px; width:100%">
-						<div style="height:130px">
-							<div id="gridfolders" style=""></div>
-						</div>
-						<div id="folderspager" class="small" style="height:22px; margin:4px;"></div>
-					</div>
-				</div>
-			</div>
-
-			<div id="folder_plan" style="display:none">
-				<div class="border-bottom" style="height:32px">
-					<div class="bold">Deletion/Archiving Plan
-						<i class="fa fa-quote-left"></i> <span id="folder_name"></span> <i class="fa fa-quote-right"></i>
-						<i class="fa fa-angle-up action right bold" style="font-size:16px; margin:4px;" onclick="monitor.folders.show.grid()"></i>
-					</div>
-					<div class="small left">Powered By Machine Learning</div>
-
-				</div>
-
-				<div id="delete_age" class="left width-half border-right" style="margin:2px; padding:2px;">
-					<div class="small" align="left">By Age</div>
-					<div class="number" style="height:42px">
-
-						<div id="age_count"  align="right" class="left width-75" style="margin-right:4px">00</div>
-						<div class="small" class="left" style="height:100%; padding-top:15px">Files</div>
-
-
-					</div>
-					<div class="small border-top" align="center" style="padding-top:4px">
-						Approximately <span id="age_value">00</span> <span id="age_units"></span>
-					</div>
-
-				</div>
-				<div id="delete_size" class="right width-half" class="number" style="margin:2px; padding:2px">
-					<div class="small" align="left">By Size</div>
-
-					<div  class=" number" style="height:42px">
-
-						<div id="size_count" align="right" class="left width-75" style="margin-right:4px">00</div>
-						<div class="small" class="left" style="height:100%; padding-top:15px">Files</div>
-					</div>
-					<div class="small border-top"align="center" style="padding-top:4px">
-						Approximately <span id="size_value">00</span> <span id="size_units"></span>
-					</div>
+        <div class="block">
+    		<div style="margin:4px; margin-top:2%">
+    			<div class="" style="height:28px; ">
+    				<div class=" bold">Monitoring
+    					<span id="latest_processes_label" class="default bold"></span>
+    				</div>
+    				<div class="small">Last Lookup <span id="node_last_lookup"></span></div>
+    			</div>
+    			<div class = "" style="height:170px, width:100%;">
+    				<div id="latest_processes" class="grid" ></div>
+    			</div>
+    			<div style="height:22px; padding:2px" class="small">
+    				<div id="latest_process_pager" align="center"></div>
+    			</div>
+    		</div>
+        </div>
+
+        <div class="block">
+    		<div id="process_summary" class="  grid " style="margin:4px; margin-top:2%">
+    			<div style="margin:4px; padding:2px; margin-bottom:4px; height:28px">
+    				<div class="bold" style="color:#4682B4">Application Summary By Status</div>
+    				<div  class="small">Latest Lookup <span id="app-summary-date"></span></div>
+    			</div>
+
+    			<div class=""  style="padding:2px; height:250px; margin:4px; margin-top:10px">
+    				<div class=" " style="height:100%">
+    					<div class="small left" style="margin-left:2%; margin-top:1%">
+    						<div class="bold">Total Applications that have:</div>
+    						<br>
+    							<div style="margin:0px; margin-left:20px; padding:4px; height:12px"><div class="left width-half"><i class="fa fa-check"></i> Running</div> <span id="total-running" class="right"></span></div>
+    							<div style="margin:0px; margin-left:20px; padding:4px; height:12px"><div class="left width-half"><i class="fa fa-times"></i> Crash</div> <span id="total-crash" class="right"></span></div>
+    							<div style="margin:0px; margin-left:20px; padding:4px; height:12px"><div class="left width-half"><i class="fa fa-ellipsis-h"></i> Idle</div> <span id="total-idle" class="right"></span></div>
+
+
+    					</div>
+    					<div id="summary_chart" class="right width-half"></div>
+    				</div>
+
+    			</div>
+    			<div id="summary_details" class="right"></div>
+    		</div>
+        </div>
+
+        <div class="block">
+    		<div class="grid " style="margin:4px; margin-top:10px;">
+    			<div style="height:28px">
+    				<div class="bold" style="margin:4px; padding:4px; color:#4682B4;">Application Summary By Groups</div>
+    			</div>
+    			<div class="width" id="summary_ranking" style=" margin:4px; padding:2px; text-transform:capitalize"></div>
+    		</div>
+        </div>
 
+	</div>
 
-				</div>
+	<div class="left info">
+        <div class="block">
+    		<div class="" style="padding:20px; margin-top:5%; margin-bottom:1rem;">
+    			<div class="" style="height:28px">
+    				<div class="small bold">CPU & Memory Usage Trend for <i class="fa fa-quote-left"></i> <span id="trend_info" class="default bold"></span> <i class="fa fa-quote-right"></i></div>
+    				<div class="small">Last Lookup <span id="trend_last_lookup"></span> <i id="has_anomaly" class="fa fa-warning right" ></i></div>
+
+
+    			</div>
+
+    			<!-- <div  style="height:270px; margin-top:10px"> -->
+    				<div id="trends_chart" class="small grid" style="height:250px; margin:2rem;"></div>
+    			<!-- </div> -->
+    		</div>
+        </div>
+        <div class="block">
+    		<div id="sandbox" class="border-top" style="padding:4px; margin-top:10px">
+    			<div style="height:28px">
+    				<div id="inspect_sandbox" class="right button border" style="display:none" onclick="monitor.sandbox.init()">Inspect</div>
+    				<div class="bold">Python Virtual Environment Analysis</div>
+
+    				<div class="small">Last Lookup <span id="sandbox_date"></span></div>
+    			</div>
+
+    			<div class=" " style="margin-top:10px; height:135px">
+    				<div id="sandbox_status" class="">
+    				</div>
+    				<div id="sandbox_pager"></div>
+    			</div>
+    		</div>
+        </div>
+
+		<div style="margin-top:5%">
+            <div class="block">
+                <div id="folder_summary" class="">
+    				<div style="height:28px">
+
+    					<div class="bold">Folder Analysis/Monitoring</div>
+    					<div class="small">Powered By Machine Learning</div>
+    				</div>
+    				<div class="">
+    					<div class=" border-top" style="margin-top:4px; padding:2px; height:34px">
+    						<i class="fa fa-search left" style="margin:4px; padding:4px; ; color:gray;"></i>
+    						<input id="folder_search" type="text" class="small left" placeholder="hostname" style="width:87%; padding-left:4px;" onkeyup="monitor.folders.search.init()"/>
+    						<i class="fa fa-trash right action right" style="margin:4px; padding:4px; color:maroon" onclick="monitor.folders.search.reset()"></i>
+    					</div>
+    					<div id="gfolderframe" style="margin-top:10px; height:170px; width:100%">
+    						<div style="height:130px">
+    							<div id="gridfolders" style=""></div>
+    						</div>
+    						<div id="folderspager" class="small" style="height:22px; margin:4px;"></div>
+    					</div>
+    				</div>
+    			</div>
+            </div>
+
+            <div class="block">
+    			<div id="folder_plan" style="display:none">
+    				<div class="border-bottom" style="height:32px">
+    					<div class="bold">Deletion/Archiving Plan
+    						<i class="fa fa-quote-left"></i> <span id="folder_name"></span> <i class="fa fa-quote-right"></i>
+    						<i class="fa fa-angle-up action right bold" style="font-size:16px; margin:4px;" onclick="monitor.folders.show.grid()"></i>
+    					</div>
+    					<div class="small left">Powered By Machine Learning</div>
+
+    				</div>
+
+    				<div id="delete_age" class="left width-half " style="margin:2px; padding:2px;">
+    					<div class="small" align="left">By Age</div>
+    					<div class="number" style="height:42px">
+
+    						<div id="age_count"  align="right" class="left width-75" style="margin-right:4px">00</div>
+    						<div class="small" class="left" style="height:100%; padding-top:15px">Files</div>
+
+
+    					</div>
+    					<div class="small border-top" align="center" style="padding-top:4px">
+    						Approximately <span id="age_value">00</span> <span id="age_units"></span>
+    					</div>
+
+    				</div>
+    				<div id="delete_size" class="right width-half" class="number" style="margin:2px; padding:2px">
+    					<div class="small" align="left">By Size</div>
+
+    					<div  class=" number" style="height:42px">
+
+    						<div id="size_count" align="right" class="left width-75" style="margin-right:4px">00</div>
+    						<div class="small" class="left" style="height:100%; padding-top:15px">Files</div>
+    					</div>
+    					<div class="small border-top"align="center" style="padding-top:4px">
+    						Approximately <span id="size_value">00</span> <span id="size_units"></span>
+    					</div>
+
+
+    				</div>
+                </div>
 			</div>
 			<div id="chartfolder" ></div>
 		</div>