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
RevLine 
[532]1var JobsDataStore;
2var JobsColumnModel;
3var JobListingEditorGrid;
4var JobListingWindow;
[535]5var JobProxy;
[546]6var myfilters = { };
7var myparams = { };
[558]8var mylimit = 15;
[549]9var ClusterImageArgs = { };
[532]10
[546]11var filterfields = [ "jid", "queue", "name", "owner" ];
12
[558]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'],
[561]19            data: [['10', 10], ['15', 15], ['20', 20], ['30', 30], ['50', 50], ['100', 100], ['max', 'max' ]]
[558]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) {
[561]46        if ( combo.getValue() == 'max' )
47          mylimit = JobsDataStore.getTotalCount();
48        else
49          mylimit = parseInt(combo.getValue());
[560]50        this.pageSize = mylimit;
[558]51        this.doLoad(0);
52    }
53});
54
55Ext.namespace( 'Ext' );
56
[549]57function makeArrayURL( somearr )
[547]58{
[549]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;
[547]69}
70
[549]71
[546]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
[549]131function ClusterImageSelectHost( somehost )
132{
133
134  if( !inMyArrayKeys( myfilters, 'host' ) )
135  {
136    myfilters['host'] = somehost;
137  }
138  else
139  {
140    delete myfilters['host'];
[550]141    delete myparams['host'];
[549]142  }
143
[550]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  //
[558]158  myparams = joinMyArray( myparams, { start: 0, limit: mylimit } );
[550]159
160  JobsDataStore.reload( { params: myparams } );
161}
162
[551]163function addListener(element, type, expression, bubbling)
164{
165  bubbling = bubbling || false;
[553]166  if(window.addEventListener)
167  { // Standard
[551]168    element.addEventListener(type, expression, bubbling);
169    return true;
[553]170  } 
171  else if(window.attachEvent) 
172  { // IE
[551]173    element.attachEvent('on' + type, expression);
174    return true;
[553]175  } 
176  else 
177    return false;
[551]178}
179
180var ImageLoader = function( id, url )
181{
182  this.url = url;
183  this.image = document.getElementById( id );
184  this.loadEvent = null;
185};
186
[553]187ImageLoader.prototype = 
188{
189  load:function()
190  {
[551]191    var url = this.url;
192    var image = this.image;
193    var loadEvent = this.loadEvent;
[553]194    addListener( this.image, 'load', function(e)
195    {
196      if( loadEvent != null )
197      {
198        loadEvent( url, image );
[551]199      }
200    }, false);
201    this.image.src = this.url;
202  },
[553]203  getImage: function()
204  {
[551]205    return this.image;
206  }
207};
208
[556]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
[550]220function reloadClusterImage()
221{
[549]222  ClusterImageArgs['view'] = 'big-clusterimage';
223
224  filt_url = makeArrayURL( myfilters );
225  imag_url = makeArrayURL( ClusterImageArgs );
[551]226  img_url = './image.php?' + filt_url + '&' + imag_url;
[549]227
[551]228  var newClusterImage = new ImageLoader( 'clusterimage', img_url );
[553]229  newClusterImage.loadEvent = function( url, image ) 
230    {
231      ClusterImageWindow.getBottomToolbar().clearStatus( { useDefaults:true } );
[556]232      setTimeout( "resizeClusterImage()", 250 );
233      setTimeout( "setClusterImagePosition()", 500 );
234      setTimeout( "achorJobListing()", 1000 );
[553]235    }
[551]236
237  ClusterImageWindow.getBottomToolbar().showBusy();
238  newClusterImage.load();
[549]239}
240
[555]241function resizeClusterImage()
242{
[556]243  var ci_height = document.getElementById( "clusterimage" ).height + ClusterImageWindow.getFrameHeight();
244  var ci_width = document.getElementById( "clusterimage" ).width + ClusterImageWindow.getFrameWidth();
[555]245
246  ClusterImageWindow.setSize( ci_width, ci_height );
247}
248
[558]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
[536]274function initJobGrid() {
275
[532]276  Ext.QuickTips.init();
277
[541]278  function jobCellClick(grid, rowIndex, columnIndex, e)
279  {
[543]280    var record = grid.getStore().getAt(rowIndex);  // Get the Record
[541]281    var fieldName = grid.getColumnModel().getDataIndex(columnIndex);
[543]282    var data = record.get(fieldName);
[541]283    var view = grid.getView();
284    var cell = view.getCell( rowIndex, columnIndex );
285
[542]286    if( fieldName == 'owner' || fieldName == 'jid' || fieldName == 'status' || fieldName == 'queue' )
[541]287    {
[550]288      if( inMyArrayKeys( myfilters, fieldName ) )
[543]289      {
290        Ext.fly(cell).removeClass( 'filterenabled' );
291        Ext.fly(cell).addClass( 'filter' );
292
[546]293        // Remove this filter
294        //
[543]295        delete myfilters[fieldName];
[546]296        delete myparams[fieldName];
[543]297
[550]298        reloadJobStore();
299        reloadClusterImage();
[543]300      }
301      else
302      {
303        Ext.fly(cell).removeClass( 'filter' );
304        Ext.fly(cell).addClass( 'filterenabled' );
305
[546]306        // Set filter for selected column to selected cell value
307        //
[543]308        myfilters[fieldName] = data;
309
[550]310        reloadJobStore();
311        reloadClusterImage();
[543]312      }
[541]313    }
314  }
315
316  function jobCellRender( value, metadata, record, rowindex, colindex, store )
317  {
318    var fieldName = JobsColumnModel.getColumnById( colindex ).dataIndex;
319
[542]320    if( fieldName == 'owner' || fieldName == 'jid' || fieldName == 'status' || fieldName == 'queue' )
[541]321    {
[543]322      if( myfilters[fieldName] != null )
323      {
324        metadata.css = 'filterenabled';
325      }
326      else
327      {
328        metadata.css = 'filter';
329      }
[541]330    }
331    return value;
332  }
333
[532]334  JobProxy = new Ext.data.HttpProxy({
[536]335                url: 'jobstore.php',
[532]336                method: 'POST'
337            });
338
[563]339  var SearchField;
340
[532]341  JobsDataStore = new Ext.data.Store({
342      id: 'JobsDataStore',
343      proxy: JobProxy,
[553]344      baseParams: { task: "LISTING" },
[532]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'},
[553]356        {name: 'requested_memory', type: 'string', mapping: 'requested_memory'},
[532]357        {name: 'ppn', type: 'int', mapping: 'ppn'},
[535]358        {name: 'nodect', type: 'int', mapping: 'nodect'},
[532]359        {name: 'nodes', type: 'string', mapping: 'nodes'},
360        {name: 'queued_timestamp', type: 'string', mapping: 'queued_timestamp'},
[535]361        {name: 'start_timestamp', type: 'string', mapping: 'start_timestamp'},
362        {name: 'runningtime', type: 'string', mapping: 'runningtime'}
[532]363      ]),
[553]364      sortInfo: { field: 'jid', direction: "DESC" },
[563]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                }
[532]387    });
[560]388   
389  var CheckJobs = new Ext.grid.CheckboxSelectionModel();
390
[532]391  JobsColumnModel = new Ext.grid.ColumnModel(
[560]392    [ CheckJobs,
393    {
[532]394        header: '#',
[535]395        tooltip: 'Job id',
[532]396        readOnly: true,
397        dataIndex: 'jid',
398        width: 50,
[541]399        hidden: false,
400        renderer: jobCellRender
[532]401      },{
402        header: 'S',
[535]403        tooltip: 'Job status',
[532]404        readOnly: true,
405        dataIndex: 'status',
406        width: 20,
[541]407        hidden: false,
408        renderer: jobCellRender
[532]409      },{
410        header: 'User',
[535]411        tooltip: 'Owner of job',
[532]412        readOnly: true,
413        dataIndex: 'owner',
414        width: 60,
[541]415        hidden: false,
416        renderer: jobCellRender
[532]417      },{
418        header: 'Queue',
[535]419        tooltip: 'In which queue does this job reside',
[532]420        readOnly: true,
421        dataIndex: 'queue',
422        width: 60,
[541]423        hidden: false,
424        renderer: jobCellRender
[532]425      },{
426        header: 'Name',
[535]427        tooltip: 'Name of job',
[532]428        readOnly: true,
429        dataIndex: 'name',
430        width: 100,
431        hidden: false
432      },{
[534]433        header: 'Requested Time',
[535]434        tooltip: 'Amount of requested time (wallclock)',
[532]435        readOnly: true,
436        dataIndex: 'requested_time',
437        width: 100,
438        hidden: false
439      },{
440        header: 'Requested Memory',
[535]441        tooltip: 'Amount of requested memory',
[532]442        readOnly: true,
443        dataIndex: 'requested_memory',
444        width: 100,
445        hidden: true
446      },{
[535]447        header: 'P',
448        tooltip: 'Number of processors per node (PPN)',
[532]449        readOnly: true,
450        dataIndex: 'ppn',
451        width: 25,
452        hidden: false
453      },{
[535]454        header: 'N',
455        tooltip: 'Number of nodes (hosts)',
[532]456        readOnly: true,
[535]457        dataIndex: 'nodect',
[532]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',
[535]468        tooltip: 'At what time did this job enter the queue',
[532]469        readOnly: true,
470        dataIndex: 'queued_timestamp',
[552]471        width: 120,
[532]472        hidden: false
473      },{
474        header: 'Started',
[535]475        tooltip: 'At what time did this job enter the running status',
[532]476        readOnly: true,
477        dataIndex: 'start_timestamp',
[552]478        width: 120,
[532]479        hidden: false
[535]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
[532]487      }]
488    );
489    JobsColumnModel.defaultSortable= true;
490
[560]491  var win;
492
[563]493  SearchField   = new Ext.app.SearchField({
494                                store: JobsDataStore,
495                                params: {start: 0, limit: mylimit},
496                                width: 200
497                    });
498
[532]499  JobListingEditorGrid =  new Ext.grid.EditorGridPanel({
500      id: 'JobListingEditorGrid',
501      store: JobsDataStore,
502      cm: JobsColumnModel,
503      enableColLock:false,
504      clicksToEdit:1,
[544]505      loadMask: true,
[537]506      selModel: new Ext.grid.RowSelectionModel({singleSelect:false}),
[547]507      stripeRows: true,
[560]508      sm: CheckJobs,
[537]509      bbar: new Ext.PagingToolbar({
[558]510                pageSize: 15,
[537]511                store: JobsDataStore,
[539]512                displayInfo: true,
513                displayMsg: 'Displaying jobs {0} - {1} out of {2} jobs total found.',
[558]514                emptyMsg: 'No jobs found to display',
515                plugins: [new Ext.ux.PageSizePlugin()]
[538]516            }),
[563]517      tbar: [ SearchField,
[560]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 );
[562]534                                                        alert( CheckJobs.getSelections() );
[560]535                                                }
536                                        }
537                                }
[563]538                        }) ]
[532]539    });
540
[547]541  ClusterImageWindow = new Ext.Window({
542      id: 'ClusterImageWindow',
[554]543      title: 'Nodes',
544      closable: true,
[547]545      collapsible: true,
546      animCollapse: true,
[555]547      width: 1,
548      height: 1,
[552]549      y: 15,
[554]550      plain: true,
[547]551      shadow: true,
[556]552      resizable: false,
[547]553      shadowOffset: 10,
[551]554      layout: 'fit',
555      bbar: new Ext.StatusBar({
556                defaultText: 'Ready.',
557                id: 'basic-statusbar',
[559]558                defaultIconCls: ''
[551]559        })
[547]560    });
561
[554]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,
[556]570      x: 10,
571      y: 10,
[554]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
[532]602  JobListingWindow = new Ext.Window({
603      id: 'JobListingWindow',
604      title: 'Cluster Jobs Overview',
605      closable:true,
[540]606      collapsible: true,
607      animCollapse: true,
608      maximizable: true,
[552]609      y: 375,
610      width:860,
[559]611      height:427,
[532]612      plain:true,
[540]613      shadow: true,
614      shadowOffset: 10,
[532]615      layout: 'fit',
616      items: JobListingEditorGrid
617    });
[541]618
619  JobListingEditorGrid.addListener( 'cellclick', jobCellClick );
[536]620}
Note: See TracBrowser for help on using the repository browser.