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

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

web2/addons/job_monarch/libtoga.php:

  • once and for all REALLY fixed hostname FQDN detection
  • fixed owner filtering of nodes when multiple jobs present with different owners

web2/addons/job_monarch/jobstore.php:

  • removed domain/hostname FQDN handling: is now all done in libtoga

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

  • test alert
File size: 13.8 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  JobsDataStore = new Ext.data.Store({
340      id: 'JobsDataStore',
341      proxy: JobProxy,
342      baseParams: { task: "LISTING" },
343      reader: new Ext.data.JsonReader({
344        root: 'results',
345        totalProperty: 'total',
346        id: 'id'
347      },[
348        {name: 'jid', type: 'int', mapping: 'jid'},
349        {name: 'status', type: 'string', mapping: 'status'},
350        {name: 'owner', type: 'string', mapping: 'owner'},
351        {name: 'queue', type: 'string', mapping: 'queue'},
352        {name: 'name', type: 'string', mapping: 'name'},
353        {name: 'requested_time', type: 'string', mapping: 'requested_time'},
354        {name: 'requested_memory', type: 'string', mapping: 'requested_memory'},
355        {name: 'ppn', type: 'int', mapping: 'ppn'},
356        {name: 'nodect', type: 'int', mapping: 'nodect'},
357        {name: 'nodes', type: 'string', mapping: 'nodes'},
358        {name: 'queued_timestamp', type: 'string', mapping: 'queued_timestamp'},
359        {name: 'start_timestamp', type: 'string', mapping: 'start_timestamp'},
360        {name: 'runningtime', type: 'string', mapping: 'runningtime'}
361      ]),
362      sortInfo: { field: 'jid', direction: "DESC" },
363      remoteSort: true
364    });
365   
366  var CheckJobs = new Ext.grid.CheckboxSelectionModel();
367
368  JobsColumnModel = new Ext.grid.ColumnModel(
369    [ CheckJobs,
370    {
371        header: '#',
372        tooltip: 'Job id',
373        readOnly: true,
374        dataIndex: 'jid',
375        width: 50,
376        hidden: false,
377        renderer: jobCellRender
378      },{
379        header: 'S',
380        tooltip: 'Job status',
381        readOnly: true,
382        dataIndex: 'status',
383        width: 20,
384        hidden: false,
385        renderer: jobCellRender
386      },{
387        header: 'User',
388        tooltip: 'Owner of job',
389        readOnly: true,
390        dataIndex: 'owner',
391        width: 60,
392        hidden: false,
393        renderer: jobCellRender
394      },{
395        header: 'Queue',
396        tooltip: 'In which queue does this job reside',
397        readOnly: true,
398        dataIndex: 'queue',
399        width: 60,
400        hidden: false,
401        renderer: jobCellRender
402      },{
403        header: 'Name',
404        tooltip: 'Name of job',
405        readOnly: true,
406        dataIndex: 'name',
407        width: 100,
408        hidden: false
409      },{
410        header: 'Requested Time',
411        tooltip: 'Amount of requested time (wallclock)',
412        readOnly: true,
413        dataIndex: 'requested_time',
414        width: 100,
415        hidden: false
416      },{
417        header: 'Requested Memory',
418        tooltip: 'Amount of requested memory',
419        readOnly: true,
420        dataIndex: 'requested_memory',
421        width: 100,
422        hidden: true
423      },{
424        header: 'P',
425        tooltip: 'Number of processors per node (PPN)',
426        readOnly: true,
427        dataIndex: 'ppn',
428        width: 25,
429        hidden: false
430      },{
431        header: 'N',
432        tooltip: 'Number of nodes (hosts)',
433        readOnly: true,
434        dataIndex: 'nodect',
435        width: 25,
436        hidden: false
437      },{
438        header: 'Nodes',
439        readOnly: true,
440        dataIndex: 'nodes',
441        width: 100,
442        hidden: true
443      },{
444        header: 'Queued',
445        tooltip: 'At what time did this job enter the queue',
446        readOnly: true,
447        dataIndex: 'queued_timestamp',
448        width: 120,
449        hidden: false
450      },{
451        header: 'Started',
452        tooltip: 'At what time did this job enter the running status',
453        readOnly: true,
454        dataIndex: 'start_timestamp',
455        width: 120,
456        hidden: false
457      },{
458        header: 'Runningtime',
459        tooltip: 'How long has this job been in the running status',
460        readOnly: true,
461        dataIndex: 'runningtime',
462        width: 140,
463        hidden: false
464      }]
465    );
466    JobsColumnModel.defaultSortable= true;
467
468  var win;
469
470  JobListingEditorGrid =  new Ext.grid.EditorGridPanel({
471      id: 'JobListingEditorGrid',
472      store: JobsDataStore,
473      cm: JobsColumnModel,
474      enableColLock:false,
475      clicksToEdit:1,
476      loadMask: true,
477      selModel: new Ext.grid.RowSelectionModel({singleSelect:false}),
478      stripeRows: true,
479      sm: CheckJobs,
480      bbar: new Ext.PagingToolbar({
481                pageSize: 15,
482                store: JobsDataStore,
483                displayInfo: true,
484                displayMsg: 'Displaying jobs {0} - {1} out of {2} jobs total found.',
485                emptyMsg: 'No jobs found to display',
486                plugins: [new Ext.ux.PageSizePlugin()]
487            }),
488      tbar: [ new Ext.app.SearchField({
489                                store: JobsDataStore,
490                                params: {start: 0, limit: mylimit},
491                                width: 200
492                    }),
493                new Ext.Button({
494                                text: 'Show nodes',
495                                tooltip: 'Show nodes for selected jobs',
496                                iconCls: 'option',
497                                listeners: {
498                                        'click': {
499                                                scope: this,
500                                                fn: function() {
501                                                        if(!win){
502                                                                    win = new Ext.Window({
503                                                                        width       : 500,
504                                                                        height      : 300,
505                                                                        closeAction :'hide',
506                                                                    });
507                                                        }
508                                                        win.show( this );
509                                                        alert( CheckJobs.getSelections() );
510                                                }
511                                        }
512                                }
513                        })
514      ]
515    });
516
517  ClusterImageWindow = new Ext.Window({
518      id: 'ClusterImageWindow',
519      title: 'Nodes',
520      closable: true,
521      collapsible: true,
522      animCollapse: true,
523      width: 1,
524      height: 1,
525      y: 15,
526      plain: true,
527      shadow: true,
528      resizable: false,
529      shadowOffset: 10,
530      layout: 'fit',
531      bbar: new Ext.StatusBar({
532                defaultText: 'Ready.',
533                id: 'basic-statusbar',
534                defaultIconCls: ''
535        })
536    });
537
538  GraphSummaryWindow = new Ext.Window({
539      id: 'GraphSummaryWindow',
540      title: 'Graph Summary',
541      closable: true,
542      collapsible: true,
543      animCollapse: true,
544      width: 300,
545      height: 500,
546      x: 10,
547      y: 10,
548      plain: true,
549      shadow: true,
550      resizable: true,
551      shadowOffset: 10,
552      layout: 'table',
553      layoutConfig: {
554                columns: 2
555        },
556      defaults:{border: false},
557      items: [{
558        id: 'monarchlogo',
559        cls: 'monarch',
560        bodyStyle: 'background: transparent',
561        html: '<A HREF="https://subtrac.sara.nl/oss/jobmonarch/" TARGET="_blank"><IMG SRC="./jobmonarch.gif" ALT="Job Monarch" BORDER="0"></A>'
562        //colspan: 2
563       },{
564        id: 'summarycount'
565       },{
566        id: 'rjqjgraph'
567       },{
568        id: 'pie',
569        colspan: 2
570       }],
571      bbar: new Ext.StatusBar({
572                defaultText: 'Ready.',
573                id: 'basic-statusbar',
574                defaultIconCls: ''
575        })
576    });
577
578  JobListingWindow = new Ext.Window({
579      id: 'JobListingWindow',
580      title: 'Cluster Jobs Overview',
581      closable:true,
582      collapsible: true,
583      animCollapse: true,
584      maximizable: true,
585      y: 375,
586      width:860,
587      height:427,
588      plain:true,
589      shadow: true,
590      shadowOffset: 10,
591      layout: 'fit',
592      items: JobListingEditorGrid
593    });
594
595  JobListingEditorGrid.addListener( 'cellclick', jobCellClick );
596}
Note: See TracBrowser for help on using the repository browser.