dashboard.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. var 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' }
  2. var monitor = {}
  3. monitor.utils = {}
  4. monitor.utils.get = {}
  5. monitor.utils.get.time = function (item) {
  6. // date = ([item.day + '-' + MONTHS[item.month] + '-' + item.year, hour + ':' + item.minute]).join(' ')
  7. var hour = item.hour > 9 ? item.hour : ('0' + item.hour)
  8. if (hour > 12) {
  9. var units = 'PM'
  10. } else {
  11. var units = 'AM'
  12. }
  13. return ([hour+':'+item.minute,units]).join(' ')
  14. }
  15. monitor.utils.get.dateTime = function (item) {
  16. var time = monitor.utils.get.time(item)
  17. return ([item.day+'-'+MONTHS[item.month]+'-'+item.year,time]).join(' ')
  18. }
  19. monitor.processes = {}
  20. monitor.processes.fetch = function(){
  21. var httpclient = HttpClient.instance()
  22. httpclient.get(HTTP_CONTEXT+'/get/processes',monitor.processes.init);
  23. }
  24. monitor.processes.init = function (x) {
  25. var r = JSON.parse(x.responseText)
  26. monitor.processes.summary.init(r)
  27. var keys = jx.utils.keys(r)
  28. jx.dom.set.value('menu','')
  29. jx.utils.patterns.visitor(keys,function(label){
  30. var div = jx.dom.get.instance('DIV')
  31. var frame= jx.dom.get.instance('DIV')
  32. var i = jx.dom.get.instance('I')
  33. i.className = 'fa fa-chevron-right left'
  34. div.innerHTML = label
  35. frame.data = r[label]
  36. frame.label = label
  37. frame.appendChild(i)
  38. frame.appendChild(div)
  39. frame.className = 'menu-item'
  40. frame.onclick = function () {
  41. monitor.processes.render(this.label, this.data);
  42. jx.dom.set.value('trends_chart','')
  43. //monitor.processes.trend.init(this.label)
  44. }
  45. jx.dom.append('menu',frame)
  46. })
  47. //
  48. // Auto start the first item in the menu
  49. // This is designed not to let the user wander or wonder what is going on
  50. //
  51. var nodes = jx.dom.get.children('menu')
  52. if (nodes.length > 0) {
  53. nodes[0].click()
  54. } else {
  55. //
  56. // We should hide the panes for this
  57. //
  58. jx.dom.hide('apps')
  59. }
  60. monitor.sandbox.init()
  61. // setTimeout(monitor.sandbox.init,1000)
  62. }
  63. /**
  64. * This function renders the grid of processes being monitored,
  65. * @param label label the list of processes belongs to
  66. * @param data dataset of a selected set of processes (works a bit like top)
  67. */
  68. monitor.processes.render = function(label,data) {
  69. data = jx.utils.patterns.visitor(data,function(row){
  70. 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>'}
  71. if (!row.status.match(/class/)) {
  72. row.status_id = row.status
  73. row.status = status[row.status]
  74. }
  75. return row
  76. })
  77. jx.dom.set.value('latest_processes','') ;
  78. jx.dom.set.value('latest_processes_label', label)
  79. var options = {
  80. width: "90%", height:'auto', autoload:true
  81. }
  82. options.paging = true
  83. options.pageSize = 4
  84. options.pageIndex = 1
  85. options.pageButtonCount = 4
  86. options.pagerContainer = '#latest_process_pager'
  87. options.pagerFormat= "{prev} Page {pageIndex} of {pageCount} {next}"
  88. options.pagePrevText= '<i class="fa fa-chevron-left"></i>'
  89. options.pageNextText= "<i class='fa fa-chevron-right small' title='Next'> </i>"
  90. options.data = data
  91. options.rowClass = function (item, index,evt) {
  92. return 'small'
  93. }
  94. options.rowClick = function(args){
  95. var item = args.item
  96. var id = jx.dom.get.value('latest_processes_label')
  97. var app = item.label
  98. monitor.processes.trend.init(id, app)
  99. if (item.anomaly == true) {
  100. jx.dom.show('has_anomaly')
  101. } else {
  102. jx.dom.hide('has_anomaly')
  103. }
  104. // var hour = item.hour < 10? ('0'+item.hour): item.hour
  105. // date = ([item.day + '-' + MONTHS[item.month] + '-' + item.year, hour + ':' + item.minute]).join(' ')
  106. jx.dom.set.value('node_last_lookup',monitor.utils.get.dateTime(item))
  107. }
  108. options.autoload = true
  109. options.fields = [
  110. { name: 'label', type: 'text', title: "Process", headercss: "small bold", css: "small"},
  111. { name: "cpu_usage", type: "number", title: "CPU", headercss: "small bold" , width:'64px'},
  112. { name: "memory_usage", type: "text", title: "Mem. Used", type: "number", headercss: "small bold" },
  113. { name: "proc_count", type: "number", title: "Proc Count", headercss: "small bold" },
  114. {name:"status",type:"text",title:"Status",headercss:"small bold",align:"center", width:'64px'}
  115. ]
  116. var grid = $('#latest_processes').jsGrid(options) ;
  117. //
  118. // We need to auto click the first row
  119. $('#latest_processes').find('.jsgrid-row')[0].click()
  120. }
  121. monitor.processes.trend = {}
  122. monitor.processes.trend.init = function (label,app) {
  123. var httpclient = HttpClient.instance()
  124. var uri = HTTP_CONTEXT+'/trends?id='+label+'&app='+encodeURIComponent(app)
  125. httpclient.get(uri, function (x) {
  126. var logs = JSON.parse(x.responseText)
  127. var dom = jx.dom.get.instance('trend_info');
  128. dom.logs = logs
  129. jx.dom.set.value('trend_info',app.trim())
  130. // jx.dom.set.attribute(label,'logs',logs)
  131. monitor.processes.trend.render(logs,null,app)
  132. })
  133. }
  134. monitor.processes.trend.render = function (logs, key,label) {
  135. // if (key == null) {
  136. // key = 'memory_usage'
  137. // }
  138. // if (logs == null || label == null){
  139. // logs = jx.dom.get.instance('trend_info').logs
  140. // label= jx.dom.get.value('trend_info') ;
  141. // }
  142. var frame = $('#trends_chart')
  143. jx.dom.set.value('trends_chart','')
  144. var context = jx.dom.get.instance('CANVAS')
  145. context.width = $(frame).width()
  146. context.height= $(frame).height()
  147. var conf = { type: 'line',responsive:true }
  148. conf.data = {}
  149. conf.options = { legend: { position: 'bottom' } }
  150. conf.options.scales = {}
  151. conf.options.scales.yAxes = [
  152. {id:'0',scaleLabel:{display:true,labelString:'CPU & MEMORY %'},ticks:{min:0,max:100,beginAtZero:true},gridLines: {display:false}}
  153. // {id:'1',position:'right',scaleLabel:{display:true,labelString:'PROCESS COUNT'},ticks:{min:0,stepSize:1,beginAtZero:true},gridLines: {display:false}}
  154. ]
  155. conf.options.scales.xAxes = [
  156. {
  157. gridLines: {display:false},
  158. time: {
  159. format:'HH:mm'
  160. }
  161. }
  162. ]
  163. conf.data.datasets = [ ]
  164. var x_axis = []
  165. var _x = {}
  166. // var _y = {}
  167. var cpu = {label: 'CPU Usage (%)', data: [] ,backgroundColor:'transparent',borderColor:COLORS[187],fill:false,borderWidth:1}
  168. var mem = {label : 'Memory Usage(%)',data:[],backgroundColor:'transparent',borderColor:COLORS[32],fill:false,borderWidth:1}
  169. // var proc= {yAxisID:'1',label : 'Proc Count',data:[],backgroundColor:'transparent',borderColor:COLORS[542],fill:false,borderWidth:1}
  170. // var 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"}
  171. jx.utils.patterns.visitor(logs,function(item){
  172. //x = new Date(item.year,item.month-1,item.day,item.hour,item.minute)
  173. // day = item.day.length > 1? (['0',item.day]).join(''): item.day
  174. // month = months[item.month]
  175. // x = ([month, day, item.hour + ':' + item.minute]).join(' ')
  176. x = monitor.utils.get.time(item).replace(/AM|PM/g,'')
  177. y = item[key]
  178. if (_x[x] == null ){//||(_x[x] == null && _y[y] == null)) {
  179. _x[x] = 1
  180. // _y[y] = 1
  181. x_axis.push(x)
  182. cpu.data.push({ x: x, y: item.cpu_usage })
  183. mem.data.push({x:x,y:item.memory_usage})
  184. console.log(item.cpu_usage)
  185. console.log(item.memory_usage)
  186. // proc.data.push({x:x,y:item.proc_count})
  187. // return {x:x,y:y}
  188. }
  189. })
  190. var item = logs[logs.length - 1]
  191. jx.dom.set.value('trend_last_lookup',monitor.utils.get.dateTime(item))
  192. conf.data.datasets = [cpu,mem]
  193. x_axis = jx.utils.unique(x_axis)
  194. conf.data.labels = x_axis
  195. // console.log(conf)
  196. jx.dom.append('trends_chart',context)
  197. var chart = new Chart(context,conf)
  198. }
  199. monitor.processes.summary = {}
  200. monitor.processes.summary.init = function(logs){
  201. var xr = 0, xc = 0, xi = 0
  202. var series = {}
  203. //var colors = [COLORS[11], COLORS[1], COLORS[2]]
  204. COLORS = ["#00BFFF", "#b2beb5", "#ffa812"]
  205. colors = [COLORS[0], COLORS[2], COLORS[1]]
  206. RUNNING_COLOR = COLORS[0]
  207. // RUNNING_COLOR = #0072BB
  208. IDLE_COLOR = COLORS[1]
  209. CRASH_COLOR=COLORS[2]
  210. var i = 0;
  211. var date = null;
  212. for( label in logs ){
  213. var rows = logs[label]
  214. series[label] = {data:[0,0,0],label:label}
  215. jx.utils.patterns.visitor(rows,function(item){
  216. if (date == null) {
  217. // date = new Date(item.year,item.month-1,item.day,item.hour,item.minute)
  218. // date = ([item.day + '-' + MONTHS[item.month] + '-' + item.year, item.hour + ':' + item.minute]).join(' ')
  219. date = monitor.utils.get.dateTime(item)
  220. }
  221. if (item.status == 'running'){
  222. xr += 1
  223. }else if(item.status == 'idle'){
  224. xi += 1
  225. }else{
  226. xc += 1
  227. }
  228. })
  229. }
  230. var data = {labels:['Running','Crash','Idle'],datasets:[{data:[xr,xc,xi],backgroundColor:[RUNNING_COLOR,CRASH_COLOR,IDLE_COLOR/**COLORS[11],COLORS[2],COLORS[100]*/]}]}
  231. var context = jx.dom.get.instance('CANVAS')
  232. context.id = 'doughnut'
  233. jx.dom.set.value('total-running', xr)
  234. jx.dom.set.value('total-crash', xc)
  235. jx.dom.set.value('total-idle', xi)
  236. // jx.dom.set.value('total-apps', xr + xi + xc)
  237. jx.dom.set.value('app-summary-date', date)
  238. jx.dom.set.value('summary_chart','')
  239. jx.dom.append('summary_chart', context)
  240. $("#doughnut").attr('width', 50)
  241. $("#doughnut").attr('height', 50)
  242. var conf = {}//width:100,height:100}//width:'auto',height:$('#process_summary').height}
  243. conf.type = 'doughnut'
  244. conf.responsive = true
  245. conf.data = data
  246. conf.options = { legend: { position: 'right' }, repsonsive: true }
  247. var _chart = new Chart(context,conf)
  248. $('#summary_chart').click(function (evt) {
  249. console.log(_chart)
  250. console.log($(_chart))
  251. var activePoints = $(_chart).getSegmentsAtEvent(evt);
  252. console.log(activePoints)
  253. })
  254. jx.dom.set.value('summary_ranking','')
  255. context = jx.dom.get.instance('CANVAS')
  256. jx.dom.append('summary_ranking',context)
  257. conf = { type: 'bar', responsive: true }
  258. conf.options={scales:{xAxes:[{gridLines: {display:false}}],yAxes:[{gridLines: {display:false},scaleLabel:{display:true,labelString:'PROCESS COUNTS'} }] }}
  259. conf.options.legend ={position:'right'}
  260. /*
  261. conf.data = {labels:['Running','Idle','Crash']}
  262. var labels = jx.utils.keys(series)
  263. var i = 0
  264. conf.data.datasets = jx.utils.patterns.visitor(labels,function(id){
  265. series[id].backgroundColor = COLORS[i++]
  266. return series[id]})
  267. chart = new Chart(context,conf);
  268. */
  269. var labels = jx.utils.keys(logs)
  270. conf.data = { labels: labels, backgroundColor:colors }
  271. var xr = [], xi = [], xc = [],xr_bg = [],xc_bg = [],xi_bg = []
  272. jx.utils.patterns.visitor(labels, function (id) {
  273. var rows = logs[id]
  274. var index = xr.length
  275. xr_bg[index] = RUNNING_COLOR
  276. xi_bg[index] = IDLE_COLOR
  277. xc_bg[index] = CRASH_COLOR
  278. if (xr[index] == null) {
  279. xr[index] = 0
  280. xc[index] = 0
  281. xi[index] = 0
  282. }
  283. jx.utils.patterns.visitor(logs[id], function (row) {
  284. if (row.status.match(/running/i)) {
  285. xr[index] += 1
  286. } else if (row.status.match(/idle/i)) {
  287. xi[index] += 1
  288. } else {
  289. xc[index] += 1
  290. }
  291. })
  292. })
  293. conf.data.datasets = [{ label: 'Running', data:xr,backgroundColor:xr_bg},{label:'Crash',data:xc,backgroundColor:xc_bg},{label:'Idle',data:xi,backgroundColor:xi_bg} ]
  294. chart = new Chart(context, conf)
  295. }
  296. monitor.sandbox = {}
  297. monitor.sandbox.init = function () {
  298. jx.dom.hide('inspect_sandbox')
  299. var httpclient = HttpClient.instance()
  300. httpclient.get(HTTP_CONTEXT+'/sandbox', function (x) {
  301. var r = JSON.parse(x.responseText)
  302. if (r.length > 0) {
  303. jx.dom.show('sandbox')
  304. monitor.sandbox.render(r);
  305. } else {
  306. jx.dom.hide('sandbox')
  307. }
  308. })
  309. }
  310. monitor.sandbox.render = function (logs) {
  311. // 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' }
  312. // var d = ([logs[0].day, '-', MONTHS[logs[0].month], '-', logs[0].year, ' ', logs[0].hour, ':', logs[0].minute]).join('')
  313. var item = logs[logs.length -1]
  314. jx.dom.set.value('sandbox_date', monitor.utils.get.dateTime(item))
  315. var options = { width: $('#sandbox_status').width()-8, height: 'auto' }
  316. options.data = jx.utils.patterns.visitor(logs, function (item) {
  317. if (item.value == 100) {
  318. item.status = '<i class="fa fa-check" style="color:green"></i>'
  319. } else {
  320. item.status = '<i class="fa fa-download" style="color:black"></i>'
  321. }
  322. return item
  323. })
  324. options.paging = true
  325. options.pageSize = 4
  326. options.pageIndex = 1
  327. options.pageButtonCount = 4
  328. options.pagerContainer = '#folders_pager'
  329. options.pagerFormat = "{prev} Page {pageIndex} of {pageCount} {next}"
  330. options.pagePrevText = '<i class="fa fa-chevron-left"></i>'
  331. options.pageNextText = "<i class='fa fa-chevron-right small' title='Next'> </i>";
  332. options.rowClass = function (item) {
  333. if (item.value < 70) {
  334. return 'bad'
  335. } else if (item.value < 100) {
  336. return 'warning'
  337. } else {
  338. return 'good'
  339. }
  340. }
  341. options.rowClick = function (args) {
  342. var item = args.item;
  343. if (item.missing.length > 0) {
  344. var form = jx.dom.get.instance('FORM')
  345. var dom = jx.dom.get.instance('INPUT')
  346. dom.type = 'hidden'
  347. dom.name = 'missing'
  348. dom.value = JSON.stringify(item.missing)
  349. form.action = HTTP_CONTEXT+'/download'
  350. form.method = 'POST'
  351. form.appendChild(dom)
  352. form.submit()
  353. }
  354. }
  355. options.fields = [
  356. {name:"status",title:"",width:20},
  357. { name: 'label',title:'Virtual Environment Label',type:'text',css:'small',headercss:'small bold' },
  358. { name: 'value', title:'Completeness %',type: 'number', css: 'small', headercss: 'small bold' }
  359. ]
  360. var grid = $('#sandbox_status').jsGrid(options)
  361. jx.dom.show('inspect_sandbox')
  362. }
  363. monitor.folders = {}
  364. monitor.folders.init = function () {
  365. var httpclient = HttpClient.instance()
  366. httpclient.get(HTTP_CONTEXT+'/folders', function (x) {
  367. var r = JSON.parse(x.responseText)
  368. var data = []
  369. for (var id in r) {
  370. var item = r[id]
  371. // item.id = id
  372. data = data.concat(item)
  373. }
  374. monitor.folders.render.init(data)
  375. })
  376. }
  377. monitor.folders.search = {}
  378. monitor.folders.search.reset = function () {
  379. jx.dom.set.value('folder_search', '')
  380. var data = jx.dom.get.attribute('folder_search', 'data')
  381. monitor.folders.render.summary(data)
  382. }
  383. monitor.folders.search.init = function(){
  384. var term = jx.dom.get.value('folder_search')
  385. var data = jx.dom.get.attribute('folder_search', 'data')
  386. term = term.replace(/ /g,'')
  387. if (term.length == 0) {
  388. monitor.folders.render.summary(data)
  389. } else if (term.length > 0) {
  390. data = jx.utils.patterns.visitor(data, function (row) {
  391. pattern = "(.*" + term + ".*)"
  392. if (row.id.match(pattern)) {
  393. return row
  394. }
  395. })
  396. monitor.folders.render.summary(data)
  397. }
  398. }
  399. monitor.folders.render = {}
  400. monitor.folders.render.init = function (data) {
  401. jx.dom.set.attribute('folder_search','data',data)
  402. monitor.folders.render.summary(data)
  403. }
  404. monitor.folders.show = {}
  405. monitor.folders.show.plan = function () {
  406. $('#folder_summary').slideUp(function () {
  407. $('#folder_plan').slideDown()
  408. })
  409. }
  410. monitor.folders.show.grid = function () {
  411. $('#folder_plan').slideUp(function () {
  412. $('#folder_summary').slideDown()
  413. })
  414. }
  415. /***
  416. * This function is designed to establish a folder clean up strategy i.e :
  417. * - We will look for anomalies given age,file size
  418. * - We will also look for where most of the data is distributed (mode)
  419. */
  420. monitor.folders.render.details = function (folder,data) {
  421. //
  422. // We need to normalize the data at this point so as to be able to show it all in the same chart
  423. // jx.math.scale x: counts, y: measure ment
  424. //
  425. var r = [data.age, data.size]
  426. var plans = []
  427. for (var i in r) {
  428. var xy = r[i]
  429. var mode = jx.math.mode(jx.utils.vector('x', xy))
  430. var yvalues = jx.utils.patterns.visitor(xy, function (row) {
  431. if (row.x == mode) {
  432. return row.y
  433. }
  434. })
  435. var sd = jx.math.sd(yvalues)
  436. if (i == 0) {
  437. prefix = 'age'
  438. var mean = jx.math.mean(yvalues)
  439. var max = (mean + (1.5 * sd))
  440. if (mean > 30 && mean < 365) {
  441. divide_by = 30
  442. units = 'MONTHS'
  443. } else if (mean > 365) {
  444. divide_by=365
  445. units = 'YEARS'
  446. } else {
  447. divide_by = 1
  448. units = 'DAYS'
  449. }
  450. } else {
  451. prefix = 'size'
  452. var mean = jx.math.sum(yvalues)
  453. var max = 0// (mean + (1.5 * sd))
  454. if (mean > 1000) {
  455. divide_by = 1000
  456. units = 'GB'
  457. } else {
  458. divide_by = 1
  459. units = 'MB'
  460. }
  461. }
  462. if (isNaN(mean)) {
  463. mean = 0
  464. }
  465. //
  466. // We need to assess the outliars i.e too old, too large
  467. //
  468. y = jx.utils.vector('y', xy)
  469. var _mean = jx.math.mean(y)
  470. var _sd = jx.math.sd(y)
  471. var outlier = _mean < mean || max > (_mean + (1.5 * _sd))
  472. plans.push({ 'label': prefix, 'max': max, 'sd': sd, 'mean': mean, 'count': yvalues.length, 'outlier': outlier })
  473. jx.dom.set.value(prefix + '_count', yvalues.length)
  474. jx.dom.set.value(prefix + '_value', (mean/divide_by).toFixed(2))
  475. jx.dom.set.value(prefix+'_units',units)
  476. monitor.folders.show.plan()
  477. }
  478. jx.dom.set.value('folder_name', folder)
  479. }
  480. monitor.folders.render.summary = function (data) {
  481. jx.dom.set.value('gridfolders', '')
  482. var options = {
  483. width: $('#gfolderframe').width()-8, height:'auto'
  484. }
  485. options.paging = true
  486. options.pageSize = 4
  487. options.pageIndex = 1
  488. options.pageButtonCount = 4
  489. options.pagerContainer = '#folderspager'
  490. options.pagerFormat= "{prev} Page {pageIndex} of {pageCount} {next}"
  491. options.pagePrevText= '<i class="fa fa-chevron-left"></i>'
  492. options.pageNextText= "<i class='fa fa-chevron-right small' title='Next'> </i>"
  493. options.data = data
  494. options.rowClass = function (item, index,evt) {
  495. return 'small'
  496. }
  497. options.rowClick = function(args){
  498. // var item = args.item
  499. // age = jx.utils.patterns.visitor(item.details.age, function (row) {
  500. // return {y:row[0],x:row[1]}
  501. // })
  502. // size = jx.utils.patterns.visitor(item.details.size, function (row) {
  503. // return {y:row[0],x:row[1]}
  504. // })
  505. // monitor.folders.render.details(item.name,{age:age,size:size})
  506. }
  507. //
  508. // @TODO Add the units in days just in case
  509. options.autoload = true
  510. options.fields = [
  511. { name: 'id', type: 'text', title: "Host", headercss: "small bold", css: "small"},
  512. { name: 'name', type: 'text', title: "Folder Name", headercss: "small bold", css: "small"},
  513. { name: "size", type: "number", title: "Folder Size", type: "number", headercss: "small bold" },
  514. { name: "count", type: "number", title: "File Count", type: "number", headercss: "small bold" }
  515. ]
  516. var grid = $('#gridfolders').jsGrid(options) ;
  517. }
  518. monitor.menu = {}
  519. monitor.menu.event = {}
  520. monitor.menu.event.toggle = function () {
  521. var dom = jx.dom.get.instance('menuframe')
  522. var value = dom.style.marginLeft.trim()
  523. if (value==0 || value == "0px" || value == "") {
  524. var width = -$(dom).width() - 20
  525. $('#menuframe').animate({marginLeft:"-20%"})
  526. } else {
  527. $('#menuframe').animate({marginLeft:"0"})
  528. }
  529. }
  530. /**
  531. * Socket handler, check for learning status
  532. */