source: trunk/web2/addons/job_monarch/js/jobgrid.js @ 563

Last change on this file since 563 was 563, checked in by ramonb, 15 years ago

web2/addons/job_monarch/image.php:

  • added query search option for node filtering

web2/addons/job_monarch/jobstore.php:

  • also search nodes and jobid with query

web2/addons/job_monarch/js/jobgrid.js:

  • added load event to datastore to trigger clusterimage reload and include any searchfield query

web2/addons/job_monarch/libtoga.php:

  • added query filter for clusterimage node filtering
File size: 14.2 KB
Line 
1var JobsDataStore;
2var JobsColumnModel;
3var JobListingEditorGrid;
4var JobListingWindow;
5var JobProxy;
6var myfilters = { };
7var myparams = { };
8var mylimit = 15;
9var ClusterImageArgs = { };
10
11var filterfields = [ "jid", "queue", "name", "owner" ];
12
13Ext.namespace('Ext.ux');
14
15Ext.ux.PageSizePlugin = function() {
16    Ext.ux.PageSizePlugin.superclass.constructor.call(this, {
17        store: new Ext.data.SimpleStore({
18            fields: ['text', 'value'],
19            data: [['10', 10], ['15', 15], ['20', 20], ['30', 30], ['50', 50], ['100', 100], ['max', 'max' ]]
20        }),
21        mode: 'local',
22        displayField: 'text',
23        valueField: 'value',
24        editable: false,
25        allowBlank: false,
26        triggerAction: 'all',
27        width: 40
28    });
29};
30
31Ext.extend(Ext.ux.PageSizePlugin, Ext.form.ComboBox, {
32    init: function(paging) {
33        paging.on('render', this.onInitView, this);
34    },
35   
36    onInitView: function(paging) {
37        paging.add('-',
38            this,
39            'jobs per page'
40        );
41        this.setValue(paging.pageSize);
42        this.on('select', this.onPageSizeChanged, paging);
43    },
44   
45    onPageSizeChanged: function(combo) {
46        if ( combo.getValue() == 'max' )
47          mylimit = JobsDataStore.getTotalCount();
48        else
49          mylimit = parseInt(combo.getValue());
50        this.pageSize = mylimit;
51        this.doLoad(0);
52    }
53});
54
55Ext.namespace( 'Ext' );
56
57function makeArrayURL( somearr )
58{
59  filter_url = '';
60  filter_sep = '';
61
62  for( filtername in somearr )
63  {
64    filter_url = filter_url + filter_sep + filtername + '=' + somearr[filtername];
65    filter_sep = '&';
66  }
67
68  return filter_url;
69}
70
71
72function isset( somevar )
73{
74  try
75  {
76    if( eval( somevar ) ) { }
77  }
78  catch( err )
79  {
80    return false;
81  }
82  return true;
83}
84
85function inMyArray( arr, someval )
86{
87  for( arval in arr )
88  {
89    if( arval == someval )
90    {
91      return true;
92    }
93  }
94  return false;
95}
96
97function inMyArrayValues( arr, someval )
98{
99  for( arkey in arr )
100  {
101    if( arr[arkey] == someval )
102    {
103      return true;
104    }
105  }
106  return false;
107}
108
109function inMyArrayKeys( arr, someval )
110{
111  for( arkey in arr )
112  {
113    if( arkey == someval )
114    {
115      return true;
116    }
117  }
118  return false;
119}
120
121function joinMyArray( arr1, arr2 )
122{
123  for( arkey in arr2 )
124  {
125    arr1[arkey] = arr2[arkey];
126  }
127
128  return arr1;
129}
130
131function ClusterImageSelectHost( somehost )
132{
133
134  if( !inMyArrayKeys( myfilters, 'host' ) )
135  {
136    myfilters['host'] = somehost;
137  }
138  else
139  {
140    delete myfilters['host'];
141    delete myparams['host'];
142  }
143
144  reloadClusterImage();
145  reloadJobStore();
146
147  return false;
148}
149
150function reloadJobStore()
151{
152  // Respect any other parameters that may have been set outside filters
153  //
154  myparams = joinMyArray( myparams, myfilters );
155
156  // Can't be sure if there are enough pages for new filter: reset to page 1
157  //
158  myparams = joinMyArray( myparams, { start: 0, limit: mylimit } );
159
160  JobsDataStore.reload( { params: myparams } );
161}
162
163function addListener(element, type, expression, bubbling)
164{
165  bubbling = bubbling || false;
166  if(window.addEventListener)
167  { // Standard
168    element.addEventListener(type, expression, bubbling);
169    return true;
170  } 
171  else if(window.attachEvent) 
172  { // IE
173    element.attachEvent('on' + type, expression);
174    return true;
175  } 
176  else 
177    return false;
178}
179
180var ImageLoader = function( id, url )
181{
182  this.url = url;
183  this.image = document.getElementById( id );
184  this.loadEvent = null;
185};
186
187ImageLoader.prototype = 
188{
189  load:function()
190  {
191    var url = this.url;
192    var image = this.image;
193    var loadEvent = this.loadEvent;
194    addListener( this.image, 'load', function(e)
195    {
196      if( loadEvent != null )
197      {
198        loadEvent( url, image );
199      }
200    }, false);
201    this.image.src = this.url;
202  },
203  getImage: function()
204  {
205    return this.image;
206  }
207};
208
209function achorJobListing()
210{
211  JobListingWindow.anchorTo( "ClusterImageWindow", "tr-br", [ 0, 10 ] );
212}
213
214function setClusterImagePosition()
215{
216  ci_x = (window.innerWidth - ClusterImageWindow.getSize()['width'] - 20); 
217  ClusterImageWindow.setPosition( ci_x, 10 );
218}
219
220function reloadClusterImage()
221{
222  ClusterImageArgs['view'] = 'big-clusterimage';
223
224  filt_url = makeArrayURL( myfilters );
225  imag_url = makeArrayURL( ClusterImageArgs );
226  img_url = './image.php?' + filt_url + '&' + imag_url;
227
228  var newClusterImage = new ImageLoader( 'clusterimage', img_url );
229  newClusterImage.loadEvent = function( url, image ) 
230    {
231      ClusterImageWindow.getBottomToolbar().clearStatus( { useDefaults:true } );
232      setTimeout( "resizeClusterImage()", 250 );
233      setTimeout( "setClusterImagePosition()", 500 );
234      setTimeout( "achorJobListing()", 1000 );
235    }
236
237  ClusterImageWindow.getBottomToolbar().showBusy();
238  newClusterImage.load();
239}
240
241function resizeClusterImage()
242{
243  var ci_height = document.getElementById( "clusterimage" ).height + ClusterImageWindow.getFrameHeight();
244  var ci_width = document.getElementById( "clusterimage" ).width + ClusterImageWindow.getFrameWidth();
245
246  ClusterImageWindow.setSize( ci_width, ci_height );
247}
248
249Ext.apply(Ext.form.VTypes, {
250        num: function(val, field) {
251
252                if (val) {
253                   var strValidChars = "0123456789";
254                   var blnResult = true;
255
256                   if (val.length == 0) return false;
257
258                   //  test strString consists of valid characters listed above
259                   for (i = 0; i < val.length && blnResult == true; i++)
260                      {
261                      strChar = val.charAt(i);
262                      if (strValidChars.indexOf(strChar) == -1)
263                         {
264                         blnResult = false;
265                         }
266                      }
267                   return blnResult;
268
269                }
270                },
271        numText: 'Must be numeric'
272});
273
274function initJobGrid() {
275
276  Ext.QuickTips.init();
277
278  function jobCellClick(grid, rowIndex, columnIndex, e)
279  {
280    var record = grid.getStore().getAt(rowIndex);  // Get the Record
281    var fieldName = grid.getColumnModel().getDataIndex(columnIndex);
282    var data = record.get(fieldName);
283    var view = grid.getView();
284    var cell = view.getCell( rowIndex, columnIndex );
285
286    if( fieldName == 'owner' || fieldName == 'jid' || fieldName == 'status' || fieldName == 'queue' )
287    {
288      if( inMyArrayKeys( myfilters, fieldName ) )
289      {
290        Ext.fly(cell).removeClass( 'filterenabled' );
291        Ext.fly(cell).addClass( 'filter' );
292
293        // Remove this filter
294        //
295        delete myfilters[fieldName];
296        delete myparams[fieldName];
297
298        reloadJobStore();
299        reloadClusterImage();
300      }
301      else
302      {
303        Ext.fly(cell).removeClass( 'filter' );
304        Ext.fly(cell).addClass( 'filterenabled' );
305
306        // Set filter for selected column to selected cell value
307        //
308        myfilters[fieldName] = data;
309
310        reloadJobStore();
311        reloadClusterImage();
312      }
313    }
314  }
315
316  function jobCellRender( value, metadata, record, rowindex, colindex, store )
317  {
318    var fieldName = JobsColumnModel.getColumnById( colindex ).dataIndex;
319
320    if( fieldName == 'owner' || fieldName == 'jid' || fieldName == 'status' || fieldName == 'queue' )
321    {
322      if( myfilters[fieldName] != null )
323      {
324        metadata.css = 'filterenabled';
325      }
326      else
327      {
328        metadata.css = 'filter';
329      }
330    }
331    return value;
332  }
333
334  JobProxy = new Ext.data.HttpProxy({
335                url: 'jobstore.php',
336                method: 'POST'
337            });
338
339  var SearchField;
340
341  JobsDataStore = new Ext.data.Store({
342      id: 'JobsDataStore',
343      proxy: JobProxy,
344      baseParams: { task: "LISTING" },
345      reader: new Ext.data.JsonReader({
346        root: 'results',
347        totalProperty: 'total',
348        id: 'id'
349      },[
350        {name: 'jid', type: 'int', mapping: 'jid'},
351        {name: 'status', type: 'string', mapping: 'status'},
352        {name: 'owner', type: 'string', mapping: 'owner'},
353        {name: 'queue', type: 'string', mapping: 'queue'},
354        {name: 'name', type: 'string', mapping: 'name'},
355        {name: 'requested_time', type: 'string', mapping: 'requested_time'},
356        {name: 'requested_memory', type: 'string', mapping: 'requested_memory'},
357        {name: 'ppn', type: 'int', mapping: 'ppn'},
358        {name: 'nodect', type: 'int', mapping: 'nodect'},
359        {name: 'nodes', type: 'string', mapping: 'nodes'},
360        {name: 'queued_timestamp', type: 'string', mapping: 'queued_timestamp'},
361        {name: 'start_timestamp', type: 'string', mapping: 'start_timestamp'},
362        {name: 'runningtime', type: 'string', mapping: 'runningtime'}
363      ]),
364      sortInfo: { field: 'jid', direction: "DESC" },
365      remoteSort: true,
366      listeners: { 'load': {
367                        scope: this,
368                        fn: function() {
369                                        if( SearchField ) {
370                                                search_value = SearchField.getEl().dom.value;
371
372                                                if( search_value != '' )
373                                                {
374                                                        myfilters['query']      = search_value;
375                                                }
376
377                                                reloadClusterImage();
378
379                                                if( search_value != '' )
380                                                {
381                                                        delete myfilters['query'];
382                                                }
383                                        }
384                                }
385                        }
386                }
387    });
388   
389  var CheckJobs = new Ext.grid.CheckboxSelectionModel();
390
391  JobsColumnModel = new Ext.grid.ColumnModel(
392    [ CheckJobs,
393    {
394        header: '#',
395        tooltip: 'Job id',
396        readOnly: true,
397        dataIndex: 'jid',
398        width: 50,
399        hidden: false,
400        renderer: jobCellRender
401      },{
402        header: 'S',
403        tooltip: 'Job status',
404        readOnly: true,
405        dataIndex: 'status',
406        width: 20,
407        hidden: false,
408        renderer: jobCellRender
409      },{
410        header: 'User',
411        tooltip: 'Owner of job',
412        readOnly: true,
413        dataIndex: 'owner',
414        width: 60,
415        hidden: false,
416        renderer: jobCellRender
417      },{
418        header: 'Queue',
419        tooltip: 'In which queue does this job reside',
420        readOnly: true,
421        dataIndex: 'queue',
422        width: 60,
423        hidden: false,
424        renderer: jobCellRender
425      },{
426        header: 'Name',
427        tooltip: 'Name of job',
428        readOnly: true,
429        dataIndex: 'name',
430        width: 100,
431        hidden: false
432      },{
433        header: 'Requested Time',
434        tooltip: 'Amount of requested time (wallclock)',
435        readOnly: true,
436        dataIndex: 'requested_time',
437        width: 100,
438        hidden: false
439      },{
440        header: 'Requested Memory',
441        tooltip: 'Amount of requested memory',
442        readOnly: true,
443        dataIndex: 'requested_memory',
444        width: 100,
445        hidden: true
446      },{
447        header: 'P',
448        tooltip: 'Number of processors per node (PPN)',
449        readOnly: true,
450        dataIndex: 'ppn',
451        width: 25,
452        hidden: false
453      },{
454        header: 'N',
455        tooltip: 'Number of nodes (hosts)',
456        readOnly: true,
457        dataIndex: 'nodect',
458        width: 25,
459        hidden: false
460      },{
461        header: 'Nodes',
462        readOnly: true,
463        dataIndex: 'nodes',
464        width: 100,
465        hidden: true
466      },{
467        header: 'Queued',
468        tooltip: 'At what time did this job enter the queue',
469        readOnly: true,
470        dataIndex: 'queued_timestamp',
471        width: 120,
472        hidden: false
473      },{
474        header: 'Started',
475        tooltip: 'At what time did this job enter the running status',
476        readOnly: true,
477        dataIndex: 'start_timestamp',
478        width: 120,
479        hidden: false
480      },{
481        header: 'Runningtime',
482        tooltip: 'How long has this job been in the running status',
483        readOnly: true,
484        dataIndex: 'runningtime',
485        width: 140,
486        hidden: false
487      }]
488    );
489    JobsColumnModel.defaultSortable= true;
490
491  var win;
492
493  SearchField   = new Ext.app.SearchField({
494                                store: JobsDataStore,
495                                params: {start: 0, limit: mylimit},
496                                width: 200
497                    });
498
499  JobListingEditorGrid =  new Ext.grid.EditorGridPanel({
500      id: 'JobListingEditorGrid',
501      store: JobsDataStore,
502      cm: JobsColumnModel,
503      enableColLock:false,
504      clicksToEdit:1,
505      loadMask: true,
506      selModel: new Ext.grid.RowSelectionModel({singleSelect:false}),
507      stripeRows: true,
508      sm: CheckJobs,
509      bbar: new Ext.PagingToolbar({
510                pageSize: 15,
511                store: JobsDataStore,
512                displayInfo: true,
513                displayMsg: 'Displaying jobs {0} - {1} out of {2} jobs total found.',
514                emptyMsg: 'No jobs found to display',
515                plugins: [new Ext.ux.PageSizePlugin()]
516            }),
517      tbar: [ SearchField,
518                new Ext.Button({
519                                text: 'Show nodes',
520                                tooltip: 'Show nodes for selected jobs',
521                                iconCls: 'option',
522                                listeners: {
523                                        'click': {
524                                                scope: this,
525                                                fn: function() {
526                                                        if(!win){
527                                                                    win = new Ext.Window({
528                                                                        width       : 500,
529                                                                        height      : 300,
530                                                                        closeAction :'hide',
531                                                                    });
532                                                        }
533                                                        win.show( this );
534                                                        alert( CheckJobs.getSelections() );
535                                                }
536                                        }
537                                }
538                        }) ]
539    });
540
541  ClusterImageWindow = new Ext.Window({
542      id: 'ClusterImageWindow',
543      title: 'Nodes',
544      closable: true,
545      collapsible: true,
546      animCollapse: true,
547      width: 1,
548      height: 1,
549      y: 15,
550      plain: true,
551      shadow: true,
552      resizable: false,
553      shadowOffset: 10,
554      layout: 'fit',
555      bbar: new Ext.StatusBar({
556                defaultText: 'Ready.',
557                id: 'basic-statusbar',
558                defaultIconCls: ''
559        })
560    });
561
562  GraphSummaryWindow = new Ext.Window({
563      id: 'GraphSummaryWindow',
564      title: 'Graph Summary',
565      closable: true,
566      collapsible: true,
567      animCollapse: true,
568      width: 300,
569      height: 500,
570      x: 10,
571      y: 10,
572      plain: true,
573      shadow: true,
574      resizable: true,
575      shadowOffset: 10,
576      layout: 'table',
577      layoutConfig: {
578                columns: 2
579        },
580      defaults:{border: false},
581      items: [{
582        id: 'monarchlogo',
583        cls: 'monarch',
584        bodyStyle: 'background: transparent',
585        html: '<A HREF="https://subtrac.sara.nl/oss/jobmonarch/" TARGET="_blank"><IMG SRC="./jobmonarch.gif" ALT="Job Monarch" BORDER="0"></A>'
586        //colspan: 2
587       },{
588        id: 'summarycount'
589       },{
590        id: 'rjqjgraph'
591       },{
592        id: 'pie',
593        colspan: 2
594       }],
595      bbar: new Ext.StatusBar({
596                defaultText: 'Ready.',
597                id: 'basic-statusbar',
598                defaultIconCls: ''
599        })
600    });
601
602  JobListingWindow = new Ext.Window({
603      id: 'JobListingWindow',
604      title: 'Cluster Jobs Overview',
605      closable:true,
606      collapsible: true,
607      animCollapse: true,
608      maximizable: true,
609      y: 375,
610      width:860,
611      height:427,
612      plain:true,
613      shadow: true,
614      shadowOffset: 10,
615      layout: 'fit',
616      items: JobListingEditorGrid
617    });
618
619  JobListingEditorGrid.addListener( 'cellclick', jobCellClick );
620}
Note: See TracBrowser for help on using the repository browser.