Browse Source

HPCC-7984 ECL Watch 4

Roll up of work to date:
Start work on browse DFU WU and Logical Files
Organized elements inside of filter area in WUQueryWidget, added tooltip specific styles for later use as well as styles for any icons used within this.
Enabled folding for XML
Added "browse ECL WUs" page.
Added dojo progress bar
Adding style changes for fields not visible
Added Spray & Despray fields working on disabling some fields Dependant on current
Sync install lists with actual files.
Remove files from being included in the generated project tree.
Comitting css fixes

Signed-off-by: Gordon Smith <gordon.smith@lexisnexis.com>
Gordon Smith 12 years ago
parent
commit
8fdf648e29

+ 1 - 65
esp/files/CMakeLists.txt

@@ -16,68 +16,4 @@
 
 project( web_files ) 
 
-add_subdirectory (css)
-source_group(css FILES ${CSS_FILES})
-add_subdirectory (html)
-source_group(html FILES ${HTML_FILES})
-add_subdirectory (img)
-source_group(img FILES ${IMG_FILES})
-add_subdirectory (logo)
-source_group(logo FILES ${LOGO_FILES})
-add_subdirectory (scripts)
-source_group(scripts FILES ${SCRIPTS_FILES})
-add_subdirectory (templates)
-source_group(templates FILES ${TEMPLATES_FILES})
-
-set ( MAIN_FILES 
-    base64.js
-    calendar.html
-    calendar_xs.js
-    components.xml
-    configmgr.html
-    default.css
-    empty.svg
-    esp_app.html
-    esp_app_tree.html
-    gen_form.css
-    gen_form.js
-    get_input.js
-    graph.js
-    GraphViewCtl.cab
-    groupadd.html
-    hashtable.js
-    hint.js
-    joblist.js
-    jobqueue.js
-    minus.gif
-    npGraphViewCtl.xpi
-    plus.gif
-    popup.js
-    qmalert.html
-    req_array.js
-    select.js
-    stack.js
-    stringbuffer.js
-    stub.htm
-    stub.js
-    submitNavForm.html
-    tabularForm.xslt
-    transformDlg.html
-    update.rdf
-    useradd.html
-    wsecl2_form.css
-)
-
-FOREACH( iFile ${MAIN_FILES} )
-    Install( FILES ${iFile} DESTINATION componentfiles/files COMPONENT Runtime )
-ENDFOREACH ( iFile )
-
-Install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/popup.js DESTINATION componentfiles/files/scripts COMPONENT Runtime )
-
-Install ( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/yui DESTINATION componentfiles/files COMPONENT Runtime USE_SOURCE_PERMISSIONS PATTERN ".svn" EXCLUDE )
-
-Install ( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/dojo DESTINATION componentfiles/files COMPONENT Runtime USE_SOURCE_PERMISSIONS PATTERN ".svn" EXCLUDE )
-Install ( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/dojox DESTINATION componentfiles/files COMPONENT Runtime USE_SOURCE_PERMISSIONS PATTERN ".svn" EXCLUDE )
-Install ( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/dijit DESTINATION componentfiles/files COMPONENT Runtime USE_SOURCE_PERMISSIONS PATTERN ".svn" EXCLUDE )
-Install ( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/CodeMirror2 DESTINATION componentfiles/files COMPONENT Runtime USE_SOURCE_PERMISSIONS PATTERN ".svn" EXCLUDE )
-Install ( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ecl DESTINATION componentfiles/files COMPONENT Runtime USE_SOURCE_PERMISSIONS PATTERN ".svn" EXCLUDE )
+Install ( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DESTINATION componentfiles COMPONENT Runtime USE_SOURCE_PERMISSIONS PATTERN "CMakeLists.txt" EXCLUDE )

+ 196 - 0
esp/files/CodeMirror2/lib/util/foldcode.js

@@ -0,0 +1,196 @@
+// the tagRangeFinder function is
+//   Copyright (C) 2011 by Daniel Glazman <daniel@glazman.org>
+// released under the MIT license (../../LICENSE) like the rest of CodeMirror
+CodeMirror.tagRangeFinder = function(cm, line, hideEnd) {
+  var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
+  var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
+  var xmlNAMERegExp = new RegExp("^[" + nameStartChar + "][" + nameChar + "]*");
+
+  var lineText = cm.getLine(line);
+  var found = false;
+  var tag = null;
+  var pos = 0;
+  while (!found) {
+    pos = lineText.indexOf("<", pos);
+    if (-1 == pos) // no tag on line
+      return;
+    if (pos + 1 < lineText.length && lineText[pos + 1] == "/") { // closing tag
+      pos++;
+      continue;
+    }
+    // ok we weem to have a start tag
+    if (!lineText.substr(pos + 1).match(xmlNAMERegExp)) { // not a tag name...
+      pos++;
+      continue;
+    }
+    var gtPos = lineText.indexOf(">", pos + 1);
+    if (-1 == gtPos) { // end of start tag not in line
+      var l = line + 1;
+      var foundGt = false;
+      var lastLine = cm.lineCount();
+      while (l < lastLine && !foundGt) {
+        var lt = cm.getLine(l);
+        var gt = lt.indexOf(">");
+        if (-1 != gt) { // found a >
+          foundGt = true;
+          var slash = lt.lastIndexOf("/", gt);
+          if (-1 != slash && slash < gt) {
+            var str = lineText.substr(slash, gt - slash + 1);
+            if (!str.match( /\/\s*\>/ )) { // yep, that's the end of empty tag
+              if (hideEnd === true) l++;
+              return l;
+            }
+          }
+        }
+        l++;
+      }
+      found = true;
+    }
+    else {
+      var slashPos = lineText.lastIndexOf("/", gtPos);
+      if (-1 == slashPos) { // cannot be empty tag
+        found = true;
+        // don't continue
+      }
+      else { // empty tag?
+        // check if really empty tag
+        var str = lineText.substr(slashPos, gtPos - slashPos + 1);
+        if (!str.match( /\/\s*\>/ )) { // finally not empty
+          found = true;
+          // don't continue
+        }
+      }
+    }
+    if (found) {
+      var subLine = lineText.substr(pos + 1);
+      tag = subLine.match(xmlNAMERegExp);
+      if (tag) {
+        // we have an element name, wooohooo !
+        tag = tag[0];
+        // do we have the close tag on same line ???
+        if (-1 != lineText.indexOf("</" + tag + ">", pos)) // yep
+        {
+          found = false;
+        }
+        // we don't, so we have a candidate...
+      }
+      else
+        found = false;
+    }
+    if (!found)
+      pos++;
+  }
+
+  if (found) {
+    var startTag = "(\\<\\/" + tag + "\\>)|(\\<" + tag + "\\>)|(\\<" + tag + "\\s)|(\\<" + tag + "$)";
+    var startTagRegExp = new RegExp(startTag, "g");
+    var endTag = "</" + tag + ">";
+    var depth = 1;
+    var l = line + 1;
+    var lastLine = cm.lineCount();
+    while (l < lastLine) {
+      lineText = cm.getLine(l);
+      var match = lineText.match(startTagRegExp);
+      if (match) {
+        for (var i = 0; i < match.length; i++) {
+          if (match[i] == endTag)
+            depth--;
+          else
+            depth++;
+          if (!depth) {
+            if (hideEnd === true) l++;
+            return l;
+          }
+        }
+      }
+      l++;
+    }
+    return;
+  }
+};
+
+CodeMirror.braceRangeFinder = function(cm, line, hideEnd) {
+  var lineText = cm.getLine(line), at = lineText.length, startChar, tokenType;
+  for (;;) {
+    var found = lineText.lastIndexOf("{", at);
+    if (found < 0) break;
+    tokenType = cm.getTokenAt({line: line, ch: found}).className;
+    if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; }
+    at = found - 1;
+  }
+  if (startChar == null || lineText.lastIndexOf("}") > startChar) return;
+  var count = 1, lastLine = cm.lineCount(), end;
+  outer: for (var i = line + 1; i < lastLine; ++i) {
+    var text = cm.getLine(i), pos = 0;
+    for (;;) {
+      var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos);
+      if (nextOpen < 0) nextOpen = text.length;
+      if (nextClose < 0) nextClose = text.length;
+      pos = Math.min(nextOpen, nextClose);
+      if (pos == text.length) break;
+      if (cm.getTokenAt({line: i, ch: pos + 1}).className == tokenType) {
+        if (pos == nextOpen) ++count;
+        else if (!--count) { end = i; break outer; }
+      }
+      ++pos;
+    }
+  }
+  if (end == null || end == line + 1) return;
+  if (hideEnd === true) end++;
+  return end;
+};
+
+CodeMirror.indentRangeFinder = function(cm, line) {
+  var tabSize = cm.getOption("tabSize");
+  var myIndent = cm.getLineHandle(line).indentation(tabSize), last;
+  for (var i = line + 1, end = cm.lineCount(); i < end; ++i) {
+    var handle = cm.getLineHandle(i);
+    if (!/^\s*$/.test(handle.text)) {
+      if (handle.indentation(tabSize) <= myIndent) break;
+      last = i;
+    }
+  }
+  if (!last) return null;
+  return last + 1;
+};
+
+CodeMirror.newFoldFunction = function(rangeFinder, markText, hideEnd) {
+  var folded = [];
+  if (markText == null) markText = '<div style="position: absolute; left: 2px; color:#600">&#x25bc;</div>%N%';
+
+  function isFolded(cm, n) {
+    for (var i = 0; i < folded.length; ++i) {
+      var start = cm.lineInfo(folded[i].start);
+      if (!start) folded.splice(i--, 1);
+      else if (start.line == n) return {pos: i, region: folded[i]};
+    }
+  }
+
+  function expand(cm, region) {
+    cm.clearMarker(region.start);
+    for (var i = 0; i < region.hidden.length; ++i)
+      cm.showLine(region.hidden[i]);
+  }
+
+  return function(cm, line) {
+    cm.operation(function() {
+      var known = isFolded(cm, line);
+      if (known) {
+        folded.splice(known.pos, 1);
+        expand(cm, known.region);
+      } else {
+        var end = rangeFinder(cm, line, hideEnd);
+        if (end == null) return;
+        var hidden = [];
+        for (var i = line + 1; i < end; ++i) {
+          var handle = cm.hideLine(i);
+          if (handle) hidden.push(handle);
+        }
+        var first = cm.setMarker(line, markText);
+        var region = {start: first, hidden: hidden};
+        cm.onDeleteLine(first, function() { expand(cm, region); });
+        folded.push(region);
+      }
+    });
+  };
+};

+ 83 - 73
esp/files/css/hpcc.css

@@ -1,4 +1,4 @@
-/*##############################################################################
+/*##############################################################################
 #    Copyright (C) 2011 HPCC Systems.
 #
 #    All rights reserved. This program is free software: you can redistribute it and/or modify
@@ -14,6 +14,8 @@
 #    You should have received a copy of the GNU Affero General Public License
 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ############################################################################## */
+
+/*ELEMENT STYLES***************/
 html, body {
     background: white;
     width: 100%;
@@ -22,13 +24,9 @@ html, body {
     color: rgb(51, 51, 51);
     font-family: Lucida Sans,Lucida Grande,Arial !important;
     font-size: 13px !important;
-    padding-top: 0px;
-    padding-right: 0px;
-    padding-bottom: 0px;
-    padding-left: 0px;
+    padding: 0;
 }
 
-
 button {
     background-position: top;
     padding: 2px 8px 4px;
@@ -52,21 +50,15 @@ h1 {
     font-size: 1.5em;
 }
 
-#myProgressBar{
-    width:200px;
-}
-
-
-.rounded{
-border-radius: 5px;
--moz-border-radius:10px;
--webkit-border-radius:10px;
--khtml-border-radius:10px;
-box-shadow: inset 0 2px 0 #fff;
-background:rgb(244,244,244);
-padding:10px;
-margin:10px 0;
-border:solid 1px rgb(214,214,214); ;
+/*Use this when creating a small popup form*/
+.smallForm label{
+  float: left;
+    width: 26%;
+    margin: 0 15px 0 0;
+    text-align: left;
+    padding-top: 4px;
+    font-weight:bold;
+    height:20px;
 }
 
 form {
@@ -75,17 +67,6 @@ form {
     width:100%;
 }
 
-#longList label{
-    float: left;
-    width: 14%;
-    margin: 0 15px 0 0;
-    text-align: right;
-    padding-top: 4px;
-    font-weight:bold;
-    height:20px;
-
-}
-
 form label{
     float: left;
     width: 14%;
@@ -104,7 +85,6 @@ form textarea{
     float:left;
 }
 
-
 form ul{
     list-style:none;
     margin:0;
@@ -127,6 +107,12 @@ form h2{
     padding:5px 0;
 }
 
+/*IDs************************/
+
+#myProgressBar{
+    width:200px;
+}
+
 #borderContainer {
     width:100%;
     height:100%;
@@ -137,53 +123,86 @@ form h2{
     height:12px;
 }
 
-
 #appLayout {
     height: 100%;
 }
 
-.pageOverlay {
-    left: 0px;
-    top: 0px;
-    width: 100%;
-    height: 100%;
-    display: block;
-    position: absolute;
-    z-index: 1001;
+#longList label{
+    float: left;
+    width: 14%;
+    margin: 0 15px 0 0;
+    text-align: right;
+    padding-top: 4px;
+    font-weight:bold;
+    height:20px;
 }
 
 #loadingOverlay {
     background: url("/esp/files/img/loadingAnimation.gif") no-repeat 10px 23px rgb(255, 255, 255);
 }
 
-    #loadingOverlay .loadingMessage {
+#loadingOverlay .loadingMessage {
         padding: 25px 40px;
         color: rgb(153, 153, 153);
     }
 
 #timings, #properties {
-    padding: 0px;
+    padding: 0;
     overflow: hidden;
 }
 
-/*start styles for WUDetails*/
-    #container{
-        width:960px;
-        
+#container{
+    width:960px;
+}
 
-    }
+#mainMenu{
+    margin-bottom:10px;
+}
 
-    #mainMenu{
-        margin-bottom:10px;
-    }
+#widgetWUInfoResponse{
+    padding-left:10px;
+}
 
-    #widgetWUInfoResponse{
-        padding-left:10px;
-    }
+/*CLASSES******************/
+.hidden{
+    color:rgb(214, 214, 214);
+    display: none !important;
+}
+
+.toolTip{
+width:500px;
+}
+
+.toolTip img{
+vertical-align: middle;
+margin-left:-20px;
+}
+
+.rounded{
+    border-radius: 5px;
+    -moz-border-radius:10px;
+    -webkit-border-radius:10px;
+    -khtml-border-radius:10px;
+    box-shadow: inset 0 2px 0 #fff;
+    background:rgb(244,244,244);
+    padding:10px;
+    margin:10px 0;
+    border:solid 1px rgb(214,214,214); 
+}
+
+.pageOverlay{
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    display: block;
+    position: absolute;
+    z-index: 1001;
+}
 
-   
 .CodeMirror {
 }
+
 .CodeMirror-scroll {
     position: absolute;
     height: 100%;
@@ -201,11 +220,13 @@ form h2{
     background-color: rgb(208, 233, 252);
 }
 
-
-.dijitValidationTextBoxLabel, .dijitInputField {
+.dijitValidationTextBoxLabel {
     width:170px;
     text-align: left;
+}
 
+.smallForm .dijitValidationTextBoxLabel {
+    width: auto;
 }
 
 .iconAlign{
@@ -225,8 +246,7 @@ form h2{
 }
 
 
-
-/*STATES*/
+/*WUSTATES*/
 .iconWorkunit {
     background-image: url("../img/workunit.png"); 
     width: 16px;
@@ -286,24 +306,14 @@ form h2{
     display: inline-block;
 }
 
-
-
-
 .ErrorCell{
-background: red;
-color: white;
+    background: red;
+    color: white;
 }
 
 .WarningCell{
-background: yellow;
-}
-
-
-/* CAN WE MOVE AND REPLACE Prompt with this instead?.bold{
-
-    font-weight:bold;
+    background: yellow;
 }
-*/
 
 .Prompt{
     font-weight:bold;

+ 80 - 70
esp/files/scripts/DFUWUDetailsWidget.js

@@ -17,6 +17,8 @@ define([
     "dojo/_base/declare",
     "dojo/_base/xhr",
     "dojo/dom",
+    "dojo/dom-class",
+    "dojo/dom-style",
 
     "dijit/layout/_LayoutWidget",
     "dijit/_TemplatedMixin",
@@ -39,7 +41,7 @@ define([
     "hpcc/ESPDFUWorkunit",
 
     "dojo/text!../templates/DFUWUDetailsWidget.html"
-], function (declare, xhr, dom,
+], function (declare, xhr, dom, domClass, domStyle,
                 _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, BorderContainer, TabContainer, ContentPane, Toolbar, Textarea, TitlePane, registry, ProgressBar,
                 EclSourceWidget, TargetSelectWidget, SampleSelectWidget, GraphWidget, ResultsWidget, InfoGridWidget, DFUWorkunit,
                 template) {
@@ -128,28 +130,12 @@ define([
                         style: "border: 0; width: 100%; height: 100%"
                     }));
                 }
-            });       
+            });
         },
 
         startup: function (args) {
             this.inherited(arguments);
-
-            
         },
-    //TODO
-
-        /*showProgress: function(event){
-            alert(response.PercentDone);
-            numParts = Math.floor(100/10);
-            
-            jsProgressBar.update({maximum:numParts, progress:response.PercentDone});
-
-            for (var i = response.PercentDone; i <= numParts; i++){                
-                timer = setTimeout(
-                "jsProgressBar.update({progress: " + i + "})", (i+1)*1000 //1000ms of 1
-                )
-            }        
-        },*/
 
         resize: function (args) {
             this.inherited(arguments);
@@ -160,13 +146,6 @@ define([
             this.inherited(arguments);
         },
 
-        //  Hitched actions  ---
-        _onSave: function (event) {
-        },
-
-        _onDelete: function (event) {
-        },
-
         //  Implementation  ---
         init: function (params) {
             //dom.byId("showWuid").innerHTML = params.Wuid;
@@ -182,10 +161,7 @@ define([
                     context.monitorDFUWorkunit(workunit);
                 });
             }
-           // this.infoGridWidget.init(params);
-        },
-
-        resetPage: function () {
+            // this.infoGridWidget.init(params);
         },
 
         objectToText: function (obj) {
@@ -207,7 +183,15 @@ define([
 
         },
 
-        _onSave: function (event) { 
+        //  Hitched actions  ---
+
+        resetPage: function () {
+        },
+
+        _onDelete: function (event) {
+        },
+
+        _onSave: function (event) {
             var protectedCheckbox = registry.byId(this.id + "Protected");
             var context = this;
             this.wu.update({
@@ -229,7 +213,7 @@ define([
                 }
             });
         },
-         _onResubmit: function (event) {
+        _onResubmit: function (event) {
             var context = this;
             this.wu.resubmit({
                 load: function (response) {
@@ -237,7 +221,7 @@ define([
                 }
             });
         },
-         _onModify: function (event) {
+        _onModify: function (event) {
             var context = this;
             this.wu.resubmit({
                 load: function (response) {
@@ -247,63 +231,89 @@ define([
         },
 
         monitorDFUWorkunit: function (response) {
-            if (!this.loaded) {                
-                 registry.byId(this.id + "Save").set("disabled", !this.wu.isComplete());            
-                 registry.byId(this.id + "Delete").set("disabled", !this.wu.isComplete());
-                 registry.byId(this.id + "Abort").set("disabled", this.wu.isComplete());            
-                 registry.byId(this.id + "Resubmit").set("disabled", !this.wu.isComplete());
-                 registry.byId(this.id + "Modify").set("disabled", !this.wu.isComplete());
-                 registry.byId(this.id + "Protected").set("readOnly", !this.wu.isComplete());
-                 
-                 dom.byId(this.id + "ID").innerHTML = response.ID;
-                 dom.byId(this.id + "JobName").value = response.JobName;
-                 dom.byId(this.id + "Queue").innerHTML = response.Queue;
-                 dom.byId(this.id + "Command").innerHTML = response.Command;
-                 dom.byId(this.id + "TimeStarted").innerHTML = response.TimeStarted;
-                 dom.byId(this.id + "TimeStopped").innerHTML = response.TimeStopped;                             
-                 dom.byId(this.id + "ProgressBar").value = response.PercentDone;
-
-                 dom.byId(this.id + "ProgressMessage").innerHTML = response.ProgressMessage;
-                 dom.byId(this.id + "SummaryMessage").innerHTML = response.SummaryMessage;
-                 dom.byId(this.id + "SourceLogicalName").innerHTML = response.SourceLogicalName;
-                 dom.byId(this.id + "DestDirectory").innerHTML = response.DestDirectory;
-                 dom.byId(this.id + "DestIP").innerHTML = response.DestIP;
-                 dom.byId(this.id + "DestFilePath").innerHTML = response.DestFilePath;
-                 dom.byId(this.id + "DestFormat").innerHTML = response.DestFormat;
-                 dom.byId(this.id + "DestNumParts").innerHTML = response.DestNumParts;
-                 dom.byId(this.id + "MonitorSub").innerHTML = response.MonitorSub;
-                 dom.byId(this.id + "Overwrite").innerHTML = response.Overwrite;
-                 dom.byId(this.id + "Replicate").innerHTML = response.Replicate;
-                 dom.byId(this.id + "Compress").innerHTML = response.Compress;
-                 dom.byId(this.id + "AutoRefresh").innerHTML = response.AutoRefresh;
-
-                 
-                this.loaded = true;
-            }
+            if (!this.loaded) {
+                registry.byId(this.id + "Save").set("disabled", !this.wu.isComplete());
+                registry.byId(this.id + "Delete").set("disabled", !this.wu.isComplete());
+                registry.byId(this.id + "Abort").set("disabled", this.wu.isComplete());
+                registry.byId(this.id + "Resubmit").set("disabled", !this.wu.isComplete());
+                registry.byId(this.id + "Modify").set("disabled", !this.wu.isComplete());
+                registry.byId(this.id + "Protected").set("readOnly", !this.wu.isComplete());
+
+                dom.byId(this.id + "ID").innerHTML = response.ID;
+                dom.byId(this.id + "ClusterName").value = response.ClusterName;
+                dom.byId(this.id + "JobName").value = response.JobName;
+                dom.byId(this.id + "Queue").innerHTML = response.Queue;
+                dom.byId(this.id + "TimeStarted").innerHTML = response.TimeStarted;
+                dom.byId(this.id + "TimeStopped").innerHTML = response.TimeStopped;
+                //dom.byId(this.id + "ProgressBar").value = response.PercentDone;
+                dom.byId(this.id + "ProgressMessage").innerHTML = response.ProgressMessage;
+                dom.byId(this.id + "SummaryMessage").innerHTML = response.SummaryMessage;
+                dom.byId(this.id + "MonitorSub").innerHTML = response.MonitorSub;
+                dom.byId(this.id + "Overwrite").innerHTML = response.Overwrite;
+                dom.byId(this.id + "Replicate").innerHTML = response.Replicate;
+                dom.byId(this.id + "Compress").innerHTML = response.Compress;
+                //dom.byId(this.id + "AutoRefresh").innerHTML = response.AutoRefresh;     
+                if (!response.AutoRefresh) {
+                    dom.byId(this.id + "AutoRefresh").innerHTML = "false";
+                }
+
+                if (response.Command == "6") {
+                    domClass.add(this.id + "ExportGroup", "hidden");
+                    dom.byId(this.id + "Command").innerHTML = "Spray";
+                    dom.byId(this.id + "SourceIP").innerHTML = response.SourceIP;
+                    dom.byId(this.id + "SourceFilePath").innerHTML = response.SourceFilePath;
+                    dom.byId(this.id + "SourceRecordSize").innerHTML = response.SourceRecordSize;
+                    dom.byId(this.id + "SourceFormat").innerHTML = response.SourceFormat;
+                    dom.byId(this.id + "SourceNumParts").innerHTML = response.SourceNumParts;
+                    dom.byId(this.id + "SourceDirectory").innerHTML = response.SourceDirectory;
+                    dom.byId(this.id + "DestGroupName").innerHTML = response.DestGroupName;
+                    dom.byId(this.id + "DestLogicalName").innerHTML = response.DestLogicalName;
+                    dom.byId(this.id + "DestDirectory").innerHTML = response.DestDirectory;
+                    dom.byId(this.id + "DestNumParts").innerHTML = response.DestNumParts;
+                } else {
+                    domClass.add(this.id + "ImportGroup", "hidden");
+                    domClass.add(this.id + "ClusterLine", "hidden");
+                    dom.byId(this.id + "Command").innerHTML = "Despray";
+                    dom.byId(this.id + "SourceLogicalName").innerHTML = response.SourceLogicalName;
+                    dom.byId(this.id + "DestDirectory").innerHTML = response.DestDirectory;
+                    dom.byId(this.id + "DestIP").innerHTML = response.DestIP;
+                    dom.byId(this.id + "DestFilePath").innerHTML = response.DestFilePath;
+                    dom.byId(this.id + "DestFormat").innerHTML = response.DestFormat;
+                    dom.byId(this.id + "DestNumParts").innerHTML = response.DestNumParts;
+                    dom.byId(this.id + "MonitorSub").innerHTML = response.MonitorSub;
+                    dom.byId(this.id + "Overwrite").innerHTML = response.Overwrite;
+                    dom.byId(this.id + "Replicate").innerHTML = response.Replicate;
+                    dom.byId(this.id + "Compress").innerHTML = response.Compress;
+                }
+                //start progress bar
+
 
 
 
+                //end progress bar
+                this.loaded = true;
+            }
             var context = this;
             if (this.wu.isComplete()) {
                 this.wu.getInfo({
                     onGetResults: function (response) {
-                        
+
                     },
 
                     onGetSourceFiles: function (response) {
-                        
+
                     },
 
                     onGetTimers: function (response) {
-                       
+
                     },
 
                     onGetGraphs: function (response) {
-                        
+
                     },
 
                     onGetAll: function (response) {
-                        
+
 
                     }
                 });

+ 312 - 0
esp/files/scripts/DFUWUQueryWidget.js

@@ -0,0 +1,312 @@
+/*##############################################################################
+#	HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
+#
+#	Licensed under the Apache License, Version 2.0 (the "License");
+#	you may not use this file except in compliance with the License.
+#	You may obtain a copy of the License at
+#
+#	   http://www.apache.org/licenses/LICENSE-2.0
+#
+#	Unless required by applicable law or agreed to in writing, software
+#	distributed under the License is distributed on an "AS IS" BASIS,
+#	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#	See the License for the specific language governing permissions and
+#	limitations under the License.
+############################################################################## */
+define([
+    "dojo/_base/declare",
+    "dojo/dom",
+    "dojo/data/ObjectStore",
+    "dojo/date",
+    "dojo/on",
+
+    "dijit/layout/_LayoutWidget",
+    "dijit/_TemplatedMixin",
+    "dijit/_WidgetsInTemplateMixin",
+    "dijit/registry",
+
+    "dojox/grid/EnhancedGrid",
+    "dojox/grid/enhanced/plugins/Pagination",
+    "dojox/grid/enhanced/plugins/IndirectSelection",
+
+    "hpcc/WsDfu",
+    "hpcc/LFDetailsWidget",
+
+    "dojo/text!../templates/DFUWUQueryWidget.html",
+
+    "dijit/layout/BorderContainer",
+    "dijit/layout/TabContainer",
+    "dijit/layout/ContentPane",
+    "dijit/form/Textarea",
+    "dijit/form/DateTextBox",
+    "dijit/form/TimeTextBox",
+    "dijit/form/Button",
+    "dijit/form/Select",
+    "dijit/Toolbar",
+    "dijit/TooltipDialog"
+], function (declare, dom, ObjectStore, date, on,
+                _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, registry,
+                EnhancedGrid, Pagination, IndirectSelection,
+                WsDfu, LFDetailsWidget,
+                template) {
+    return declare("DFUWUQueryWidget", [_LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
+        templateString: template,
+        baseClass: "DFUWUQueryWidget",
+        borderContainer: null,
+        tabContainer: null,
+        workunitsGrid: null,
+        legacyPane: null,
+        legacyPaneLoaded: false,
+
+        tabMap: [],
+
+        buildRendering: function (args) {
+            this.inherited(arguments);
+        },
+
+        postCreate: function (args) {
+            this.inherited(arguments);
+            this.borderContainer = registry.byId(this.id + "BorderContainer");
+            this.tabContainer = registry.byId(this.id + "TabContainer");
+            this.workunitsGrid = registry.byId(this.id + "WorkunitsGrid");
+            this.legacyPane = registry.byId(this.id + "Legacy");
+
+            var context = this;
+            this.tabContainer.watch("selectedChildWidget", function (name, oval, nval) {
+                if (nval.id == context.id + "Workunits") {
+                } else if (nval.id == context.id + "Legacy") {
+                    if (!context.legacyPaneLoaded) {
+                        context.legacyPaneLoaded = true;
+                        context.legacyPane.set("content", dojo.create("iframe", {
+                            src: "/WsDfu/DFUQuery",
+                            style: "border: 0; width: 100%; height: 100%"
+                        }));
+                    }
+                } else {
+                    if (!nval.initalized) {
+                        nval.init(nval.params);
+                    }
+                }
+                context.selectedTab = nval;
+            });
+        },
+
+        startup: function (args) {
+            this.inherited(arguments);
+            this.refreshActionState();
+            this.initWorkunitsGrid();
+        },
+
+        resize: function (args) {
+            this.inherited(arguments);
+            this.borderContainer.resize();
+        },
+
+        layout: function (args) {
+            this.inherited(arguments);
+        },
+
+        destroy: function (args) {
+            this.inherited(arguments);
+        },
+
+        //  Hitched actions  ---
+        _onOpen: function (event) {
+            var selections = this.workunitsGrid.selection.getSelected();
+            for (var i = selections.length - 1; i >= 0; --i) {
+                this.ensurePane(selections[i].Name, {
+                    Name: selections[i].Name
+                });
+            }
+        },
+        _onDelete: function (event) {
+            if (confirm('Delete selected workunits?')) {
+                var context = this;
+                WsDfu.WUAction(this.workunitsGrid.selection.getSelected(), "Delete", {
+                    load: function (response) {
+                        context.workunitsGrid.rowSelectCell.toggleAllSelection(false);
+                        context.refreshGrid(response);
+                    }
+                });
+            }
+        },
+        _onAddToSuperfile: function (event) {
+        },
+        _onFilterApply: function (event) {
+            this.workunitsGrid.rowSelectCell.toggleAllSelection(false);
+            this.refreshGrid();
+        },
+        _onFilterClear: function(event) {
+            this.workunitsGrid.rowSelectCell.toggleAllSelection(false);
+            dom.byId(this.id + "Owner").value = "";
+            dom.byId(this.id + "Jobname").value = "";
+            dom.byId(this.id + "Cluster").value = "";
+            dom.byId(this.id + "State").value = "";
+            dom.byId(this.id + "ECL").value = "";
+            dom.byId(this.id + "LogicalFile").value = "";
+            dom.byId(this.id + "LogicalFileSearchType").value = "";
+            dom.byId(this.id + "FromDate").value = "";
+            dom.byId(this.id + "FromTime").value = "";
+            dom.byId(this.id + "ToDate").value = "";
+            dom.byId(this.id + "LastNDays").value = "";
+            this.refreshGrid();
+        },
+
+        getFilter: function () {
+            var retVal = {
+                Owner: dom.byId(this.id + "Owner").value,
+                Jobname: dom.byId(this.id + "Jobname").value,
+                Cluster: dom.byId(this.id + "Cluster").value,
+                State: dom.byId(this.id + "State").value,
+                ECL: dom.byId(this.id + "ECL").value,
+                LogicalFile: dom.byId(this.id + "LogicalFile").value,
+                StartDate: this.getISOString("FromDate", "FromTime"),
+                EndDate: this.getISOString("ToDate", "ToTime"),
+                LastNDays: dom.byId(this.id + "LastNDays").value
+            };
+            if (retVal.StartDate != "" && retVal.EndDate != "") {
+                retVal["DateRB"] = "0";
+            } else if (retVal.LastNDays != "") {
+                retVal["DateRB"] = "0";
+                var now = new Date();
+                retVal.StartDate = date.add(now, "day", dom.byId(this.id + "LastNDays").value * -1).toISOString();
+                retVal.EndDate = now.toISOString();
+            }
+            return retVal;
+        },
+
+        getISOString: function (dateField, timeField) {
+            var d = registry.byId(this.id + dateField).attr("value");
+            var t = registry.byId(this.id + timeField).attr("value");
+            if (d) {
+                if (t) {
+                    d.setHours(t.getHours());
+                    d.setMinutes(t.getMinutes());
+                    d.setSeconds(t.getSeconds());
+                }
+                return d.toISOString();
+            }
+            return "";
+        },
+
+        //  Implementation  ---
+        init: function (params) {
+        },
+
+        initWorkunitsGrid: function() {
+            this.workunitsGrid.setStructure([
+			    {
+			        name: "C",
+			        field: "isZipfile",
+			        width: "16px",
+			        formatter: function (compressed) {
+			            if (compressed == true) {
+			                return "C";
+			            }
+			            return "";
+			        }
+			    },
+			    {
+			        name: "K",
+			        field: "isKeyFile",
+			        width: "16px",
+			        formatter: function (keyfile) {
+			            if (keyfile == true) {
+			                return "K";
+			            }
+			            return "";
+			        }
+			    },
+			    {
+			        name: "S",
+			        field: "isSuperfile",
+			        width: "16px",
+			        formatter: function (superfile) {
+			            if (superfile == true) {
+			                return "S";
+			            }
+			            return "";
+			        }
+			    },
+			    { name: "Logical Name", field: "Name", width: "32" },
+			    { name: "Owner", field: "Owner", width: "8" },
+			    { name: "Description", field: "Description", width: "12" },
+			    { name: "Cluster", field: "ClusterName", width: "12" },
+			    { name: "Records", field: "RecordCount", width: "8" },
+			    { name: "Size", field: "Totalsize", width: "8" },
+			    { name: "Parts", field: "Parts", width: "4" },
+			    { name: "Modified (UTC/GMT)", field: "Modified", width: "12" }
+            ]);
+            var store = new WsDfu.DFUQuery();
+            var objStore = new ObjectStore({ objectStore: store });
+            this.workunitsGrid.setStore(objStore);
+            this.workunitsGrid.setQuery(this.getFilter());
+
+            var context = this;
+            this.workunitsGrid.on("RowDblClick", function (evt) {
+                if (context.onRowDblClick) {
+                    var idx = evt.rowIndex;
+                    var item = this.getItem(idx);
+                    var Name = this.store.getValue(item, "Name");
+                    context.onRowDblClick(Name);
+                }
+            }, true);
+
+            dojo.connect(this.workunitsGrid.selection, 'onSelected', function (idx) {
+                context.refreshActionState();
+            });
+            dojo.connect(this.workunitsGrid.selection, 'onDeselected', function (idx) {
+                context.refreshActionState();
+            });
+
+            this.workunitsGrid.startup();
+        },
+
+        refreshGrid: function (args) {
+            this.workunitsGrid.setQuery(this.getFilter());
+            var context = this;
+            setTimeout(function () {
+                context.refreshActionState()
+            }, 200);
+        },
+
+        refreshActionState: function () {
+            var selection = this.workunitsGrid.selection.getSelected();
+            var hasSelection = false;
+            for (var i = 0; i < selection.length; ++i) {
+                hasSelection = true;
+            }
+
+            registry.byId(this.id + "Open").set("disabled", !hasSelection);
+            registry.byId(this.id + "Delete").set("disabled", !hasSelection);
+            registry.byId(this.id + "AddToSuperfile").set("disabled", !hasSelection);
+        },
+
+        ensurePane: function (id, params) {
+            var retVal = this.tabMap[id];
+            if (!retVal) {
+                var context = this;
+                retVal = new LFDetailsWidget({
+                    Name: id,
+                    title: id,
+                    closable: true,
+                    onClose: function () {
+                        delete context.tabMap[id];
+                        return true;
+                    },
+                    params: params
+                });
+                this.tabMap[id] = retVal;
+                this.tabContainer.addChild(retVal, 2);
+            }
+            return retVal;
+        },
+
+        onRowDblClick: function (name) {
+            var wuTab = this.ensurePane(name, {
+                Name: name
+            });
+            this.tabContainer.selectChild(wuTab);
+        }
+    });
+});

+ 3 - 1
esp/files/scripts/ECLSourceWidget.js

@@ -74,7 +74,9 @@ define([
                     gutter: true,
                     lineNumbers: true,
                     mode: this.WUXml ? "xml" : "ecl",
-                    readOnly: this.readOnly
+                    readOnly: this.readOnly,
+                    gutter: this.WUXml ? true : false,
+                    onGutterClick: CodeMirror.newFoldFunction(CodeMirror.tagRangeFinder)
                 });
 
                 var context = this;

+ 114 - 0
esp/files/scripts/FileSpray.js

@@ -0,0 +1,114 @@
+/*##############################################################################
+#    HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+############################################################################## */
+define([
+    "dojo/_base/declare",
+    "dojo/_base/lang",
+    "dojo/_base/xhr",
+    "dojo/_base/Deferred",
+    "dojo/store/util/QueryResults",
+    "dojo/store/JsonRest", 
+    "dojo/store/Memory", 
+    "dojo/store/Cache", 
+    "dojo/store/Observable",
+    
+    "dojox/xml/parser",    
+
+    "hpcc/ESPBase"
+], function (declare, lang, xhr, Deferred, QueryResults, JsonRest, Memory, Cache, Observable,
+    parser,
+    ESPBase) {
+    var GetDFUWorkunits = declare(ESPBase, {
+        idProperty: "ID",
+
+        constructor: function (options) {
+            declare.safeMixin(this, options);
+        },
+
+        getIdentity: function (object) {
+            return object[this.idProperty];
+        },
+
+        query: function (query, options) {
+            var request = {};
+            lang.mixin(request, options.query);
+            if (options.start)
+                request['PageStartFrom'] = options.start;
+            if (options.count)
+                request['PageSize'] = options.count;
+            if (options.sort) {
+                request['Sortby'] = options.sort[0].attribute;
+                request['Descending'] = options.sort[0].descending;
+            }
+            request['rawxml_'] = "1";
+
+            var results = xhr.get({
+                url: this.getBaseURL("FileSpray") + "/GetDFUWorkunits.json",
+                handleAs: "json",
+                content: request
+            });
+
+            var deferredResults = new Deferred();
+            deferredResults.total = results.then(function (response) {
+                if (lang.exists("GetDFUWorkunitsResponse.NumWUs", response)) {
+                    return response.GetDFUWorkunitsResponse.NumWUs;
+                }
+                return 0;
+            });
+            Deferred.when(results, function (response) {
+                var workunits = [];
+                if (lang.exists("GetDFUWorkunitsResponse.results.DFUWorkunit", response)) {
+                    workunits = response.GetDFUWorkunitsResponse.results.DFUWorkunit;
+                }
+                deferredResults.resolve(workunits);
+            });
+
+            return QueryResults(deferredResults);
+        }
+    });
+
+    return {
+        GetDFUWorkunits: GetDFUWorkunits,
+
+        WUAction: function (items, actionType, callback) {
+            var request = {
+                Type: actionType
+            };
+
+            for (var i = 0; i < items.length; ++i) {
+                request["wuids_i" + i] = items[i].ID;
+            }
+
+            var espBase = new ESPBase();
+            var context = this;
+            xhr.post({
+                url: espBase.getBaseURL("FileSpray") + "/DFUWorkunitsAction.json",
+                handleAs: "json",
+                content: request,
+                load: function (response) {
+                    if (callback && callback.load) {
+                        callback.load(response);
+                    }
+                },
+                error: function () {
+                    if (callback && callback.error) {
+                        callback.error(e);
+                    }
+                }
+            });
+        }
+    };
+});
+

+ 352 - 0
esp/files/scripts/GetDFUWorkunitsWidget.js

@@ -0,0 +1,352 @@
+/*##############################################################################
+#	HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
+#
+#	Licensed under the Apache License, Version 2.0 (the "License");
+#	you may not use this file except in compliance with the License.
+#	You may obtain a copy of the License at
+#
+#	   http://www.apache.org/licenses/LICENSE-2.0
+#
+#	Unless required by applicable law or agreed to in writing, software
+#	distributed under the License is distributed on an "AS IS" BASIS,
+#	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#	See the License for the specific language governing permissions and
+#	limitations under the License.
+############################################################################## */
+define([
+    "dojo/_base/declare",
+    "dojo/dom",
+    "dojo/data/ObjectStore",
+    "dojo/date",
+    "dojo/on",
+
+    "dijit/layout/_LayoutWidget",
+    "dijit/_TemplatedMixin",
+    "dijit/_WidgetsInTemplateMixin",
+    "dijit/registry",
+
+    "dojox/grid/EnhancedGrid",
+    "dojox/grid/enhanced/plugins/Pagination",
+    "dojox/grid/enhanced/plugins/IndirectSelection",
+
+    "hpcc/FileSpray",
+    "hpcc/DFUWUDetailsWidget",
+
+    "dojo/text!../templates/GetDFUWorkunitsWidget.html",
+
+    "dijit/layout/BorderContainer",
+    "dijit/layout/TabContainer",
+    "dijit/layout/ContentPane",
+    "dijit/form/Textarea",
+    "dijit/form/DateTextBox",
+    "dijit/form/TimeTextBox",
+    "dijit/form/Button",
+    "dijit/form/Select",
+    "dijit/Toolbar",
+    "dijit/TooltipDialog"
+], function (declare, dom, ObjectStore, date, on,
+                _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, registry,
+                EnhancedGrid, Pagination, IndirectSelection,
+                FileSpray, DFUWUDetailsWidget,
+                template) {
+    return declare("GetDFUWorkunitsWidget", [_LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
+        templateString: template,
+        baseClass: "GetDFUWorkunitsWidget",
+        borderContainer: null,
+        tabContainer: null,
+        workunitsGrid: null,
+        legacyPane: null,
+        legacyPaneLoaded: false,
+
+        tabMap: [],
+
+        buildRendering: function (args) {
+            this.inherited(arguments);
+        },
+
+        postCreate: function (args) {
+            this.inherited(arguments);
+            this.borderContainer = registry.byId(this.id + "BorderContainer");
+            this.tabContainer = registry.byId(this.id + "TabContainer");
+            this.workunitsGrid = registry.byId(this.id + "WorkunitsGrid");
+            this.legacyPane = registry.byId(this.id + "Legacy");
+
+            var context = this;
+            this.tabContainer.watch("selectedChildWidget", function (name, oval, nval) {
+                if (nval.id == context.id + "Workunits") {
+                } else if (nval.id == context.id + "Legacy") {
+                    if (!context.legacyPaneLoaded) {
+                        context.legacyPaneLoaded = true;
+                        context.legacyPane.set("content", dojo.create("iframe", {
+                            src: "/FileSpray/GetDFUWorkunits",
+                            style: "border: 0; width: 100%; height: 100%"
+                        }));
+                    }
+                } else {
+                    if (!nval.initalized) {
+                        nval.init(nval.params);
+                    }
+                }
+                context.selectedTab = nval;
+            });
+        },
+
+        startup: function (args) {
+            this.inherited(arguments);
+            this.refreshActionState();
+            this.initWorkunitsGrid();
+        },
+
+        resize: function (args) {
+            this.inherited(arguments);
+            this.borderContainer.resize();
+        },
+
+        layout: function (args) {
+            this.inherited(arguments);
+        },
+
+        destroy: function (args) {
+            this.inherited(arguments);
+        },
+
+        //  Hitched actions  ---
+        _onOpen: function (event) {
+            var selections = this.workunitsGrid.selection.getSelected();
+            for (var i = selections.length - 1; i >= 0; --i) {
+                this.ensurePane(selections[i].ID, {
+                    Wuid: selections[i].ID
+                });
+            }
+        },
+        _onDelete: function (event) {
+            if (confirm('Delete selected workunits?')) {
+                var context = this;
+                FileSpray.WUAction(this.workunitsGrid.selection.getSelected(), "Delete", {
+                    load: function (response) {
+                        context.workunitsGrid.rowSelectCell.toggleAllSelection(false);
+                        context.refreshGrid(response);
+                    }
+                });
+            }
+        },
+        _onSetToFailed: function (event) {
+            var context = this;
+            FileSpray.WUAction(this.workunitsGrid.selection.getSelected(), "SetToFailed", {
+                load: function (response) {
+                    context.refreshGrid(response);
+                }
+            });
+        },
+        _onProtect: function (event) {
+            var context = this;
+            FileSpray.WUAction(this.workunitsGrid.selection.getSelected(), "Protect", {
+                load: function (response) {
+                    context.refreshGrid(response);
+                }
+            });
+        },
+        _onUnprotect: function (event) {
+            var context = this;
+            FileSpray.WUAction(this.workunitsGrid.selection.getSelected(), "Unprotect", {
+                load: function (response) {
+                    context.refreshGrid(response);
+                }
+            });
+        },
+        _onFilterApply: function (event) {
+            this.workunitsGrid.rowSelectCell.toggleAllSelection(false);
+            this.refreshGrid();
+        },
+        _onFilterClear: function(event) {
+            this.workunitsGrid.rowSelectCell.toggleAllSelection(false);
+            dom.byId(this.id + "Owner").value = "";
+            dom.byId(this.id + "Jobname").value = "";
+            dom.byId(this.id + "Cluster").value = "";
+            dom.byId(this.id + "State").value = "";
+            dom.byId(this.id + "ECL").value = "";
+            dom.byId(this.id + "LogicalFile").value = "";
+            dom.byId(this.id + "LogicalFileSearchType").value = "";
+            dom.byId(this.id + "FromDate").value = "";
+            dom.byId(this.id + "FromTime").value = "";
+            dom.byId(this.id + "ToDate").value = "";
+            dom.byId(this.id + "LastNDays").value = "";
+            this.refreshGrid();
+        },
+
+        getFilter: function () {
+            var retVal = {
+                Owner: dom.byId(this.id + "Owner").value,
+                Jobname: dom.byId(this.id + "Jobname").value,
+                Cluster: dom.byId(this.id + "Cluster").value,
+                State: dom.byId(this.id + "State").value,
+                ECL: dom.byId(this.id + "ECL").value,
+                LogicalFile: dom.byId(this.id + "LogicalFile").value,
+                LogicalFileSearchType: registry.byId(this.id + "LogicalFileSearchType").get("value"),
+                StartDate: this.getISOString("FromDate", "FromTime"),
+                EndDate: this.getISOString("ToDate", "ToTime"),
+                LastNDays: dom.byId(this.id + "LastNDays").value
+            };
+            if (retVal.StartDate != "" && retVal.EndDate != "") {
+                retVal["DateRB"] = "0";
+            } else if (retVal.LastNDays != "") {
+                retVal["DateRB"] = "0";
+                var now = new Date();
+                retVal.StartDate = date.add(now, "day", dom.byId(this.id + "LastNDays").value * -1).toISOString();
+                retVal.EndDate = now.toISOString();
+            }
+            return retVal;
+        },
+
+        getISOString: function (dateField, timeField) {
+            var d = registry.byId(this.id + dateField).attr("value");
+            var t = registry.byId(this.id + timeField).attr("value");
+            if (d) {
+                if (t) {
+                    d.setHours(t.getHours());
+                    d.setMinutes(t.getMinutes());
+                    d.setSeconds(t.getSeconds());
+                }
+                return d.toISOString();
+            }
+            return "";
+        },
+
+        //  Implementation  ---
+        init: function (params) {
+        },
+
+        initWorkunitsGrid: function() {
+            this.workunitsGrid.setStructure([
+			    {
+				    name: "P",
+				    field: "isProtected",
+				    width: "20px",
+				    formatter: function (_protected) {
+				        if (_protected == true) {
+					        return "P";
+					    }
+					    return "";
+				    }
+			    },
+			    { name: "ID", field: "ID", width: "12" },
+			    {
+			        name: "Type",
+			        field: "Command",
+			        width: "8",
+			        formatter: function (command) {
+			            switch (command) {
+			                case 1: return "Copy";
+			                case 2: return "Remove";
+			                case 3: return "Move";
+			                case 4: return "Rename";
+			                case 5: return "Replicate";
+			                case 6: return "Spray";
+			                case 7: return "Despray";
+			                case 8: return "Add";
+			                case 9: return "Transfer";
+			                case 10: return "Save Map";
+			                case 11: return "Add Group";
+			                case 12: return "Server";
+			                case 13: return "Monitor";
+			                case 14: return "Copy Merge";
+			                case 15: return "Super Copy";
+			            }
+			            return "Unknown";
+			        }
+			    },
+			    { name: "Owner", field: "Owner", width: "8" },
+			    { name: "Job Name", field: "JobName", width: "16" },
+			    { name: "Cluster", field: "ClusterName", width: "8" },
+			    { name: "State", field: "StateMessage", width: "8" },
+			    { name: "% Complete", field: "PercentDone", width: "8" }
+            ]);
+            var store = new FileSpray.GetDFUWorkunits();
+            var objStore = new ObjectStore({ objectStore: store });
+            this.workunitsGrid.setStore(objStore);
+            this.workunitsGrid.setQuery(this.getFilter());
+
+            var context = this;
+            this.workunitsGrid.on("RowDblClick", function (evt) {
+                if (context.onRowDblClick) {
+                    var idx = evt.rowIndex;
+                    var item = this.getItem(idx);
+                    var id = this.store.getValue(item, "ID");
+                    context.onRowDblClick(id);
+                }
+            }, true);
+
+            dojo.connect(this.workunitsGrid.selection, 'onSelected', function (idx) {
+                context.refreshActionState();
+            });
+            dojo.connect(this.workunitsGrid.selection, 'onDeselected', function (idx) {
+                context.refreshActionState();
+            });
+
+            this.workunitsGrid.startup();
+        },
+
+        refreshGrid: function (args) {
+            this.workunitsGrid.setQuery(this.getFilter());
+            var context = this;
+            setTimeout(function () {
+                context.refreshActionState()
+            }, 200);
+        },
+
+        refreshActionState: function () {
+            var selection = this.workunitsGrid.selection.getSelected();
+            var hasSelection = false;
+            var hasProtected = false;
+            var hasNotProtected = false;
+            var hasFailed = false;
+            var hasNotFailed = false;
+            for (var i = 0; i < selection.length; ++i) {
+                hasSelection = true;
+                if (selection[i] && selection[i].isProtected && selection[i].isProtected != "0") {
+                    hasProtected = true;
+                } else {
+                    hasNotProtected = true;
+                }
+                if (selection[i] && selection[i].State && selection[i].State == "5") {
+                    hasFailed = true;
+                } else {
+                    hasNotFailed = true;
+                }
+            }
+
+            registry.byId(this.id + "Open").set("disabled", !hasSelection);
+            registry.byId(this.id + "Delete").set("disabled", !hasNotProtected);
+            registry.byId(this.id + "SetToFailed").set("disabled", !hasNotProtected);
+            registry.byId(this.id + "Protect").set("disabled", !hasNotProtected);
+            registry.byId(this.id + "Unprotect").set("disabled", !hasProtected);
+        },
+
+        ensurePane: function (id, params) {
+            var retVal = this.tabMap[id];
+            if (!retVal) {
+                var context = this;
+                retVal = new DFUWUDetailsWidget({
+                    Wuid: id,
+                    title: id,
+                    closable: true,
+                    onClose: function () {
+                        delete context.tabMap[id];
+                        return true;
+                    },
+                    params: params
+                });
+                this.tabMap[id] = retVal;
+                this.tabContainer.addChild(retVal, 2);
+            }
+            return retVal;
+        },
+
+        onRowDblClick: function (id) {
+            var wuTab = this.ensurePane(id, {
+                Wuid: id
+            });
+            this.tabContainer.selectChild(wuTab);
+        }
+    });
+});

+ 1 - 1
esp/files/scripts/LFDetailsWidget.js

@@ -133,7 +133,7 @@ define([
                 } else if (nval.id == context.id + "Legacy" && !context.legacyPaneLoaded) {
                     context.legacyPaneLoaded = true;
                     context.legacyPane.set("content", dojo.create("iframe", {
-                        src: "/WsDfu/DFUInfo?Name=" + context.logicalFile.logicalName + "&Cluster=" + context.logicalFile.cluster,
+                        src: "/WsDfu/DFUInfo?Name=" + context.logicalFile.logicalName,//+ "&Cluster=" + context.logicalFile.cluster,
                         style: "border: 0; width: 100%; height: 100%"
                     }));
                 }

+ 9 - 0
esp/files/scripts/WUDetailsWidget.js

@@ -72,6 +72,7 @@ define([
         legacyPane: null,
         legacyPaneLoaded: false,
 
+        initalized: false,
         wu: null,
         prevState: "",
 
@@ -161,6 +162,10 @@ define([
             this.inherited(arguments);
         },
 
+        destroy: function (args) {
+            this.inherited(arguments);
+        },
+
         //  Hitched actions  ---
         _onSave: function (event) {
             var protectedCheckbox = registry.byId(this.id + "Protected");
@@ -222,6 +227,10 @@ define([
 
         //  Implementation  ---
         init: function (params) {
+            if (this.initalized)
+                return;
+
+            this.initalized = true;
             if (params.Wuid) {
                 registry.byId(this.id + "Summary").set("title", params.Wuid);
 

+ 336 - 0
esp/files/scripts/WUQueryWidget.js

@@ -0,0 +1,336 @@
+/*##############################################################################
+#	HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
+#
+#	Licensed under the Apache License, Version 2.0 (the "License");
+#	you may not use this file except in compliance with the License.
+#	You may obtain a copy of the License at
+#
+#	   http://www.apache.org/licenses/LICENSE-2.0
+#
+#	Unless required by applicable law or agreed to in writing, software
+#	distributed under the License is distributed on an "AS IS" BASIS,
+#	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#	See the License for the specific language governing permissions and
+#	limitations under the License.
+############################################################################## */
+define([
+    "dojo/_base/declare",
+    "dojo/dom",
+    "dojo/data/ObjectStore",
+    "dojo/date",
+    "dojo/on",
+
+    "dijit/layout/_LayoutWidget",
+    "dijit/_TemplatedMixin",
+    "dijit/_WidgetsInTemplateMixin",
+    "dijit/registry",
+
+    "dojox/grid/EnhancedGrid",
+    "dojox/grid/enhanced/plugins/Pagination",
+    "dojox/grid/enhanced/plugins/IndirectSelection",
+
+    "hpcc/WsWorkunits",
+    "hpcc/WUDetailsWidget",
+
+    "dojo/text!../templates/WUQueryWidget.html",
+
+    "dijit/layout/BorderContainer",
+    "dijit/layout/TabContainer",
+    "dijit/layout/ContentPane",
+    "dijit/form/Textarea",
+    "dijit/form/DateTextBox",
+    "dijit/form/TimeTextBox",
+    "dijit/form/Button",
+    "dijit/form/Select",
+    "dijit/Toolbar",
+    "dijit/TooltipDialog"
+], function (declare, dom, ObjectStore, date, on,
+                _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, registry,
+                EnhancedGrid, Pagination, IndirectSelection,
+                WsWorkunits, WUDetailsWidget,
+                template) {
+    return declare("WUQueryWidget", [_LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
+        templateString: template,
+        baseClass: "WUQueryWidget",
+        borderContainer: null,
+        tabContainer: null,
+        workunitsGrid: null,
+        legacyPane: null,
+        legacyPaneLoaded: false,
+
+        tabMap: [],
+
+        buildRendering: function (args) {
+            this.inherited(arguments);
+        },
+
+        postCreate: function (args) {
+            this.inherited(arguments);
+            this.borderContainer = registry.byId(this.id + "BorderContainer");
+            this.tabContainer = registry.byId(this.id + "TabContainer");
+            this.workunitsGrid = registry.byId(this.id + "WorkunitsGrid");
+            this.legacyPane = registry.byId(this.id + "Legacy");
+
+            var context = this;
+            this.tabContainer.watch("selectedChildWidget", function (name, oval, nval) {
+                if (nval.id == context.id + "Workunits") {
+                } else if (nval.id == context.id + "Legacy") {
+                    if (!context.legacyPaneLoaded) {
+                        context.legacyPaneLoaded = true;
+                        context.legacyPane.set("content", dojo.create("iframe", {
+                            src: "/WsWorkunits/WUQuery",
+                            style: "border: 0; width: 100%; height: 100%"
+                        }));
+                    }
+                } else {
+                    if (!nval.initalized) {
+                        nval.init(nval.params);
+                    }
+                }
+                context.selectedTab = nval;
+            });
+        },
+
+        startup: function (args) {
+            this.inherited(arguments);
+            this.refreshActionState();
+            this.initWorkunitsGrid();
+        },
+
+        resize: function (args) {
+            this.inherited(arguments);
+            this.borderContainer.resize();
+        },
+
+        layout: function (args) {
+            this.inherited(arguments);
+        },
+
+        destroy: function (args) {
+            this.inherited(arguments);
+        },
+
+        //  Hitched actions  ---
+        _onOpen: function (event) {
+            var selections = this.workunitsGrid.selection.getSelected();
+            for (var i = selections.length - 1; i >= 0; --i) {
+                this.ensurePane(selections[i].Wuid, {
+                    Wuid: selections[i].Wuid
+                });
+            }
+        },
+        _onDelete: function (event) {
+            if (confirm('Delete selected workunits?')) {
+                var context = this;
+                WsWorkunits.WUAction(this.workunitsGrid.selection.getSelected(), "Delete", {
+                    load: function (response) {
+                        context.workunitsGrid.rowSelectCell.toggleAllSelection(false);
+                        context.refreshGrid(response);
+                    }
+                });
+            }
+        },
+        _onSetToFailed: function (event) {
+            var context = this;
+            WsWorkunits.WUAction(this.workunitsGrid.selection.getSelected(), "SetToFailed", {
+                load: function (response) {
+                    context.refreshGrid(response);
+                }
+            });
+        },
+        _onProtect: function (event) {
+            var context = this;
+            WsWorkunits.WUAction(this.workunitsGrid.selection.getSelected(), "Protect", {
+                load: function (response) {
+                    context.refreshGrid(response);
+                }
+            });
+        },
+        _onUnprotect: function (event) {
+            var context = this;
+            WsWorkunits.WUAction(this.workunitsGrid.selection.getSelected(), "Unprotect", {
+                load: function (response) {
+                    context.refreshGrid(response);
+                }
+            });
+        },
+        _onReschedule: function (event) {
+        },
+        _onDeschedule: function (event) {
+        },
+        _onFilterApply: function (event) {
+            this.workunitsGrid.rowSelectCell.toggleAllSelection(false);
+            this.refreshGrid();
+        },
+        _onFilterClear: function(event) {
+            this.workunitsGrid.rowSelectCell.toggleAllSelection(false);
+            dom.byId(this.id + "Owner").value = "";
+            dom.byId(this.id + "Jobname").value = "";
+            dom.byId(this.id + "Cluster").value = "";
+            dom.byId(this.id + "State").value = "";
+            dom.byId(this.id + "ECL").value = "";
+            dom.byId(this.id + "LogicalFile").value = "";
+            dom.byId(this.id + "LogicalFileSearchType").value = "";
+            dom.byId(this.id + "FromDate").value = "";
+            dom.byId(this.id + "FromTime").value = "";
+            dom.byId(this.id + "ToDate").value = "";
+            dom.byId(this.id + "LastNDays").value = "";
+            this.refreshGrid();
+        },
+
+        getFilter: function () {
+            var retVal = {
+                Owner: dom.byId(this.id + "Owner").value,
+                Jobname: dom.byId(this.id + "Jobname").value,
+                Cluster: dom.byId(this.id + "Cluster").value,
+                State: dom.byId(this.id + "State").value,
+                ECL: dom.byId(this.id + "ECL").value,
+                LogicalFile: dom.byId(this.id + "LogicalFile").value,
+                LogicalFileSearchType: registry.byId(this.id + "LogicalFileSearchType").get("value"),
+                StartDate: this.getISOString("FromDate", "FromTime"),
+                EndDate: this.getISOString("ToDate", "ToTime"),
+                LastNDays: dom.byId(this.id + "LastNDays").value
+            };
+            if (retVal.StartDate != "" && retVal.EndDate != "") {
+                retVal["DateRB"] = "0";
+            } else if (retVal.LastNDays != "") {
+                retVal["DateRB"] = "0";
+                var now = new Date();
+                retVal.StartDate = date.add(now, "day", dom.byId(this.id + "LastNDays").value * -1).toISOString();
+                retVal.EndDate = now.toISOString();
+            }
+            return retVal;
+        },
+
+        getISOString: function (dateField, timeField) {
+            var d = registry.byId(this.id + dateField).attr("value");
+            var t = registry.byId(this.id + timeField).attr("value");
+            if (d) {
+                if (t) {
+                    d.setHours(t.getHours());
+                    d.setMinutes(t.getMinutes());
+                    d.setSeconds(t.getSeconds());
+                }
+                return d.toISOString();
+            }
+            return "";
+        },
+
+        //  Implementation  ---
+        init: function (params) {
+            if (params.Wuid) {
+            }
+        },
+
+        initWorkunitsGrid: function() {
+            this.workunitsGrid.setStructure([
+			    {
+				    name: "P",
+				    field: "Protected",
+				    width: "20px",
+				    formatter: function (protected) {
+					    if (protected == true) {
+					        return "P";
+					    }
+					    return "";
+				    }
+			    },
+			    { name: "Wuid", field: "Wuid", width: "12" },
+			    { name: "Owner", field: "Owner", width: "8" },
+			    { name: "Job Name", field: "Jobname", width: "16" },
+			    { name: "Cluster", field: "Cluster", width: "8" },
+			    { name: "Roxie Cluster", field: "RoxieCluster", width: "8" },
+			    { name: "State", field: "State", width: "8" },
+			    { name: "Total Thor Time", field: "TotalThorTime", width: "8" }
+            ]);
+            var store = new WsWorkunits.WUQuery();
+            var objStore = new ObjectStore({ objectStore: store });
+            this.workunitsGrid.setStore(objStore);
+            this.workunitsGrid.setQuery(this.getFilter());
+
+            var context = this;
+            this.workunitsGrid.on("RowDblClick", function (evt) {
+                if (context.onRowDblClick) {
+                    var idx = evt.rowIndex;
+                    var item = this.getItem(idx);
+                    var Wuid = this.store.getValue(item, "Wuid");
+                    context.onRowDblClick(Wuid);
+                }
+            }, true);
+
+            dojo.connect(this.workunitsGrid.selection, 'onSelected', function (idx) {
+                context.refreshActionState();
+            });
+            dojo.connect(this.workunitsGrid.selection, 'onDeselected', function (idx) {
+                context.refreshActionState();
+            });
+
+            this.workunitsGrid.startup();
+        },
+
+        refreshGrid: function (args) {
+            this.workunitsGrid.setQuery(this.getFilter());
+            var context = this;
+            setTimeout(function () {
+                context.refreshActionState()
+            }, 200);
+        },
+
+        refreshActionState: function () {
+            var selection = this.workunitsGrid.selection.getSelected();
+            var hasSelection = false;
+            var hasProtected = false;
+            var hasNotProtected = false;
+            var hasFailed = false;
+            var hasNotFailed = false;
+            for (var i = 0; i < selection.length; ++i) {
+                hasSelection = true;
+                if (selection[i] && selection[i].Protected && selection[i].Protected != "0") {
+                    hasProtected = true;
+                } else {
+                    hasNotProtected = true;
+                }
+                if (selection[i] && selection[i].StateID && selection[i].StateID == "4") {
+                    hasFailed = true;
+                } else {
+                    hasNotFailed = true;
+                }
+            }
+
+            registry.byId(this.id + "Open").set("disabled", !hasSelection);
+            registry.byId(this.id + "Delete").set("disabled", !hasNotProtected);
+            registry.byId(this.id + "SetToFailed").set("disabled", !hasNotProtected);
+            registry.byId(this.id + "Protect").set("disabled", !hasNotProtected);
+            registry.byId(this.id + "Unprotect").set("disabled", !hasProtected);
+            registry.byId(this.id + "Reschedule").set("disabled", true);    //TODO
+            registry.byId(this.id + "Deschedule").set("disabled", true);    //TODO
+        },
+
+        ensurePane: function (id, params) {
+            var retVal = this.tabMap[id];
+            if (!retVal) {
+                var context = this;
+                retVal = new WUDetailsWidget({
+                    id: id,
+                    title: id,
+                    closable: true,
+                    onClose: function () {
+                        delete context.tabMap[id];
+                        return true;
+                    },
+                    params: params
+                });
+                this.tabMap[id] = retVal;
+                this.tabContainer.addChild(retVal, 2);
+            }
+            return retVal;
+        },
+
+        onRowDblClick: function (wuid) {
+            var wuTab = this.ensurePane(wuid, {
+                Wuid: wuid
+            });
+            this.tabContainer.selectChild(wuTab);
+        }
+    });
+});

+ 82 - 80
esp/files/scripts/WsDfu.js

@@ -15,100 +15,102 @@
 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ############################################################################## */
 define([
-	"dojo/_base/declare",
-	"dojo/_base/lang",
-	"dojo/_base/xhr",
-	"dojo/_base/Deferred",
-	"dojo/store/util/QueryResults",
-	"hpcc/ESPBase"
+    "dojo/_base/declare",
+    "dojo/_base/lang",
+    "dojo/_base/xhr",
+    "dojo/_base/Deferred",
+    "dojo/store/util/QueryResults",
+    "hpcc/ESPBase"
 ], function (declare, lang, xhr, Deferred, QueryResults, ESPBase) {
-	var DFUQuery = declare(ESPBase, {
-		idProperty: "Name",
+    var DFUQuery = declare(ESPBase, {
+        idProperty: "Name",
 
-		constructor: function (options) {
-			declare.safeMixin(this, options);
-		},
+        constructor: function (options) {
+            declare.safeMixin(this, options);
+        },
 
-		getIdentity: function (object) {
-			return object[this.idProperty];
-		},
+        getIdentity: function (object) {
+            return object[this.idProperty];
+        },
 
-		query: function (query, options) {
-			var request = {};
-			lang.mixin(request, options.query);
-			request['PageStartFrom'] = options.start;
-			request['PageSize'] = options.count;
-			if (options.sort) {
-				request['Sortby'] = options.sort[0].attribute;
-				request['Descending'] = options.sort[0].descending;
-			}
-			request['rawxml_'] = "1";
+        query: function (query, options) {
+            var request = {};
+            lang.mixin(request, options.query);
+            request['PageStartFrom'] = options.start;
+            request['PageSize'] = options.count;
+            if (options.sort) {
+                request['Sortby'] = options.sort[0].attribute;
+                request['Descending'] = options.sort[0].descending;
+            }
+            request['rawxml_'] = "1";
 
-			var results = xhr.get({
-				url: this.getBaseURL("WsDfu") + "/DFUQuery",
-				handleAs: "xml",
-				content: request
-			});
+            var results = xhr.get({
+                url: this.getBaseURL("WsDfu") + "/DFUQuery.json",
+                handleAs: "json",
+                content: request
+            });
 
-			var context = this;
-			var parsedResults = results.then(function (domXml) {
-				data = context.getValues(domXml, "DFULogicalFile");
-				data.total = context.getValue(domXml, "NumFiles");
-				return data;
-			});
+            var deferredResults = new Deferred();
+            deferredResults.total = results.then(function (response) {
+                if (lang.exists("DFUQueryResponse.NumFiles", response)) {
+                    return response.DFUQueryResponse.NumFiles;
+                }
+                return 0;
+            });
+            Deferred.when(results, function (response) {
+                var workunits = [];
+                if (lang.exists("DFUQueryResponse.DFULogicalFiles.DFULogicalFile", response)) {
+                    workunits = response.DFUQueryResponse.DFULogicalFiles.DFULogicalFile;
+                }
+                deferredResults.resolve(workunits);
+            });
 
-			lang.mixin(parsedResults, {
-				total: Deferred.when(parsedResults, function (data) {
-					return data.total;
-				})
-			});
-	
-			return QueryResults(parsedResults);
-		}
-	});
+            return QueryResults(deferredResults);
+        }
+    });
 
-	var DFUFileView = declare(ESPBase, {
-		idProperty: "Wuid",
+    var DFUFileView = declare(ESPBase, {
+        idProperty: "Wuid",
 
-		constructor: function (options) {
-			declare.safeMixin(this, options);
-		},
+        constructor: function (options) {
+            declare.safeMixin(this, options);
+        },
 
-		getIdentity: function (object) {
-			return object[this.idProperty];
-		},
+        getIdentity: function (object) {
+            return object[this.idProperty];
+        },
 
-		query: function (query, options) {
-			var request = {};
-			lang.mixin(request, options.query);
-			request['rawxml_'] = "1";
+        query: function (query, options) {
+            var request = {};
+            lang.mixin(request, options.query);
+            request['rawxml_'] = "1";
 
-			var results = xhr.get({
-				url: this.getBaseURL("WsDfu") + "/DFUFileView",
-				handleAs: "xml",
-				content: request
-			});
+            var results = xhr.get({
+                url: this.getBaseURL("WsDfu") + "/DFUFileView",
+                handleAs: "xml",
+                content: request
+            });
 
-			var context = this;
-			var parsedResults = results.then(function (domXml) {
-				var debug = context.getValues(domXml);
-				var data = context.getValues(domXml, "DFULogicalFile");
-				return data;
-			});
+            var context = this;
+            var parsedResults = results.then(function (domXml) {
+                var debug = context.getValues(domXml);
+                var data = context.getValues(domXml, "DFULogicalFile");
+                return data;
+            });
 
-			lang.mixin(parsedResults, {
-				total: Deferred.when(parsedResults, function (data) {
-					return data ? data.length : 0;
-				})
-			});
-	
-			return QueryResults(parsedResults);
-		}
-	});
+            lang.mixin(parsedResults, {
+                total: Deferred.when(parsedResults, function (data) {
+                    return data ? data.length : 0;
+                })
+            });
+    
+            return QueryResults(parsedResults);
+        }
+    });
 
-	return {
-		DFUQuery: DFUQuery,
-		DFUFileView: DFUFileView
-	};
+    return {
+        DFUQuery: DFUQuery,
+        DFUFileView: DFUFileView
+    };
 });
 

+ 105 - 14
esp/files/scripts/WsWorkunits.js

@@ -19,8 +19,17 @@ define([
     "dojo/_base/xhr",
     "dojo/_base/Deferred",
     "dojo/store/util/QueryResults",
+    "dojo/store/JsonRest", 
+    "dojo/store/Memory", 
+    "dojo/store/Cache", 
+    "dojo/store/Observable",
+    
+    "dojox/xml/parser",    
+
     "hpcc/ESPBase"
-], function (declare, lang, xhr, Deferred, QueryResults, ESPBase) {
+], function (declare, lang, xhr, Deferred, QueryResults, JsonRest, Memory, Cache, Observable,
+    parser,
+    ESPBase) {
     var WUQuery = declare(ESPBase, {
         idProperty: "Wuid",
 
@@ -46,25 +55,79 @@ define([
             request['rawxml_'] = "1";
 
             var results = xhr.get({
-                url: this.getBaseURL("WsWorkunits") + "/WUQuery",
-                handleAs: "xml",
+                url: this.getBaseURL("WsWorkunits") + "/WUQuery.json",
+                handleAs: "json",
                 content: request
             });
 
-            var context = this;
-            var parsedResults = results.then(function (domXml) {
-                data = context.getValues(domXml, "ECLWorkunit");
-                data.total = context.getValue(domXml, "NumWUs");
-                return data;
+            var deferredResults = new Deferred();
+            deferredResults.total = results.then(function (response) {
+                if (lang.exists("WUQueryResponse.NumWUs", response)) {
+                    return response.WUQueryResponse.NumWUs;
+                }
+                return 0;
+            });
+            Deferred.when(results, function (response) {
+                var workunits = [];
+                if (lang.exists("WUQueryResponse.Workunits.ECLWorkunit", response)) {
+                    workunits = response.WUQueryResponse.Workunits.ECLWorkunit;
+                }
+                deferredResults.resolve(workunits);
             });
 
-            lang.mixin(parsedResults, {
-                total: Deferred.when(parsedResults, function (data) {
-                    return data.total;
-                })
+            return QueryResults(deferredResults);
+        }
+    });
+
+    var WUResultTest = declare(ESPBase, {
+        idProperty: "myInjectedRowNum",
+        wuid: "",
+        sequence: 0,
+        isComplete: false,
+
+        constructor: function (args) {
+            declare.safeMixin(this, args);
+        },
+
+        getIdentity: function (object) {
+            return object[this.idProperty];
+        },
+
+        query: function (query, options) {
+            var request = {};
+            request['Wuid'] = this.wuid;
+            if (this.cluster && this.name) {
+                request['Cluster'] = this.cluster;
+                request['LogicalName'] = this.name;
+            } else {
+                request['Sequence'] = this.sequence;
+            }
+            request['Start'] = options.start;
+            request['Count'] = options.count;
+            request['rawxml_'] = "1";
+
+            var results = xhr.get({
+                url: this.getBaseURL("WsWorkunits") + "/WUResult.json",
+                handleAs: "json",
+                content: request
             });
 
-            return QueryResults(parsedResults);
+            var deferredResults = new Deferred();
+            deferredResults.total = results.then(function (response) {
+                return response.WUResultResponse.Total;
+            });
+            var context = this;
+            Deferred.when(results, function (response) {
+                var resultXml = response.WUResultResponse.Result;
+                var domXml = parser.parse("<WUResultResponse>" + resultXml + "</WUResultResponse>");
+                var rows = context.getValues(domXml, "Row");
+                for (var i = 0; i < rows.length; ++i) {
+                    rows[i].myInjectedRowNum = options.start + i + 1;
+                }
+                deferredResults.resolve(rows);
+            });
+
+            return QueryResults(deferredResults);
         }
     });
 
@@ -144,7 +207,35 @@ define([
 
     return {
         WUQuery: WUQuery,
-        WUResult: WUResult
+        WUResult: WUResult,
+
+        WUAction: function (items, actionType, callback) {
+            var request = {
+                ActionType: actionType
+            };
+
+            for (var i = 0; i < items.length; ++i) {
+                request["Wuids_i" + i] = items[i].Wuid;
+            }
+
+            var espBase = new ESPBase();
+            var context = this;
+            xhr.post({
+                url: espBase.getBaseURL("WsWorkunits") + "/WUAction.json",
+                handleAs: "json",
+                content: request,
+                load: function (response) {
+                    if (callback && callback.load) {
+                        callback.load(response);
+                    }
+                },
+                error: function () {
+                    if (callback && callback.error) {
+                        callback.error(e);
+                    }
+                }
+            });
+        }
     };
 });
 

+ 1 - 0
esp/files/stub.htm

@@ -22,6 +22,7 @@
     <title>HPCC: Stub</title>
     <link href="CodeMirror2/lib/codemirror.css" rel="stylesheet">
     <script src="CodeMirror2/lib/codemirror.js"></script>
+    <script src="CodeMirror2/lib/util/foldcode.js"></script>    
     <script src="CodeMirror2/mode/ecl/ecl.js"></script>
     <script src="CodeMirror2/mode/xml/xml.js"></script>
     <link href="css/ecl.css" rel="stylesheet">

+ 5 - 1
esp/files/stub.js

@@ -29,11 +29,15 @@ define([
     "hpcc/TimingTreeMapWidget",
     "hpcc/ECLSourceWidget",
     "hpcc/InfoGridWidget",
+    "hpcc/WUQueryWidget",
     "hpcc/WUDetailsWidget",
+    "hpcc/GetDFUWorkunitsWidget",
     "hpcc/DFUWUDetailsWidget",
+    "hpcc/DFUWUQueryWidget",
     "hpcc/LFDetailsWidget"
 ], function (fx, baseWindow, dom, domStyle, domGeometry, ioQuery, ready,
-        ECLPlaygroundWidget, GraphPageWidget, ResultsWidget, TimingPageWidget, TimingTreeMapWidget, ECLSourceWidget, InfoGridWidget, WUDetailsWidget, DFUWUDetailsWidget, LFDetailsWidget) {
+        ECLPlaygroundWidget, GraphPageWidget, ResultsWidget, TimingPageWidget, TimingTreeMapWidget, ECLSourceWidget, InfoGridWidget, WUQueryWidget, WUDetailsWidget, GetDFUWorkunitsWidget, DFUWUDetailsWidget, DFUWUQueryWidget, LFDetailsWidget
+        ) {
 
     var initUi = function () {
         var params = ioQuery.queryToObject(dojo.doc.location.search.substr((dojo.doc.location.search.substr(0, 1) == "?" ? 1 : 0)));

+ 208 - 119
esp/files/templates/DFUWUDetailsWidget.html

@@ -6,133 +6,222 @@
                     <div id="${id}Save" data-dojo-attach-event="onClick:_onSave" data-dojo-type="dijit.form.Button">Save</div>
                     <div id="${id}Delete" data-dojo-attach-event="onClick:_onDelete" data-dojo-type="dijit.form.Button">Delete</div>
                     <span data-dojo-type="dijit.ToolbarSeparator"></span>
-                <div id="${id}Abort" data-dojo-attach-event="onClick:_onAbort" data-dojo-type="dijit.form.Button">Abort</div>
-                <span data-dojo-type="dijit.ToolbarSeparator"></span>
-                <div id="${id}Resubmit" data-dojo-attach-event="onClick:_onResubmit" data-dojo-type="dijit.form.Button">Resubmit</div>
-                <div id="${id}Modify" data-dojo-attach-event="onClick:_onModify" data-dojo-type="dijit.form.Button">Modify</div>
-                <span data-dojo-type="dijit.ToolbarSeparator"></span>
-                </div>                
-                <div data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">                    
+                    <div id="${id}Abort" data-dojo-attach-event="onClick:_onAbort" data-dojo-type="dijit.form.Button">Abort</div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                    <div id="${id}Resubmit" data-dojo-attach-event="onClick:_onResubmit" data-dojo-type="dijit.form.Button">Resubmit</div>
+                    <div id="${id}Modify" data-dojo-attach-event="onClick:_onModify" data-dojo-type="dijit.form.Button">Modify</div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                </div>
+                <div data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">
                     <div class="rounded">
-                       <h2>
-                        <img id="${id}ProtectedImage" src="img/locked.png"/>&nbsp<img id="${id}StateIdImage" src="img/workunit.png"/>&nbsp<span id="${id}Wuid" class="bold">WUID</span>
-                    </h2>
-                    <form id="longList">                    
-                         <!--<div id="jsProgressBar" data-dojo-type="dijit.form.Button" data-dojo-attach-event="onClick:showProgress">go</div>-->
-                        <ul>                           
-                             <li>
-                                <label for="ID">ID:</label>
-                                <div id="${id}ID"></div>
-                            </li>
-                             <li>
-                                <label for="Owner">Job name:</label>
-                                <div><input id="${id}JobName" data-dojo-props="trim:true" data-dojo-type="dijit.form.TextBox"/></div>
-                            </li>
-                             <li>                 
-                                <label for="Protected">Protected:</label>
-                                <div><input id="${id}Protected" data-dojo-type="dijit.form.CheckBox"/></div>
-                            </li>
-                            <li>
-                                <label for="Queue">Queue:</label>
-                                <div id="${id}Queue"></div>
-                            </li>
-                            <li>
-                                <label for="Command">Command:</label>
-                                <div id="${id}Command"></div>
-                            </li>
-                            <li>
-                                <label for="Time Started">Time Started:</label>
-                                <div id="${id}TimeStarted"></div>
-                            </li>
-                            <li>
-                                <label for="Time Stopped">Time Stopped:</label>
-                                <div id="${id}TimeStopped"></div>
-                            </li>
-                            <li>
-                                <label for="Percent Done">Percent Done:</label>
-                                <!-- TODO Need to write a IE8 fallback -->
-                                <div><progress id="${id}ProgressBar" max='100' style='width:197px'></progress></div>
-                                
-                            </li>
-                            <li>
-                                <label for="Progress Message">Progress Message:</label>
-                                <div id="${id}ProgressMessage"></div>
-                            </li>                            
-                            <li>
-                                <label for="Summary Message">SummaryMessage:</label>
-                                <div id="${id}SummaryMessage"></div>
-                            </li>
-                        </ul>
-                    </form>
-                        </div>
-                        <div class="rounded">
-                            <h1>Additional Details</h1>
-                            <form>
+                        <h2>
+                            <img id="${id}ProtectedImage" src="img/locked.png" />&nbsp<img id="${id}StateIdImage" src="img/workunit.png" />&nbsp<span id="${id}Wuid" class="bold">WUID</span>
+                        </h2>
+                        <form>
+                            <ul>
+                                <li>
+                                    <label for="${id}ID">ID:</label>
+                                    <div id="${id}ID"></div>
+                                </li>
+                                <li id="${id}ClusterLine">
+                                    <label for="Cluster Name">Cluster Name:</label>
+                                    <div>
+                                        <input id="${id}ClusterName" data-dojo-props="trim:true" data-dojo-type="dijit.form.TextBox" />
+                                    </div>
+                                </li>
+                                <li>
+                                    <label for="Owner">Job name:</label>
+                                    <div>
+                                        <input id="${id}JobName" data-dojo-props="trim:true" data-dojo-type="dijit.form.TextBox" />
+                                    </div>
+                                </li>
+                                <li>
+                                    <label for="Queue">Queue:</label>
+                                    <div id="${id}Queue"></div>
+                                </li>
+                                <!--<li>
+                                <label for="User">User:</label>
+                                <div id="${id}User"></div>
+                                </li>-->
+                                <li>
+                                    <label for="Protected">Protected:</label>
+                                    <div>
+                                        <input id="${id}Protected" data-dojo-type="dijit.form.CheckBox" />
+                                    </div>
+                                </li>
+                                <li>
+                                    <label for="Command">Command:</label>
+                                    <div id="${id}Command"></div>
+                                </li>
+                                <li>
+                                    <label for="Time Started">Time Started:</label>
+                                    <div id="${id}TimeStarted"></div>
+                                </li>
+                                <li>
+                                    <label for="Time Stopped">Time Stopped:</label>
+                                    <div id="${id}TimeStopped"></div>
+                                </li>
+                                <li>
+                                    <label for="Percent Done">Percent Done:</label>
+                                    <!-- TODO Need to write a IE8 fallback -->
+                                    <!--<div><progress id="${id}ProgressBar" max='100' style='width:197px'></progress></div>-->
+                                    <div id="${id}downloadProgress" style="width: 190px"
+                                        data-dojo-id="myProgressBar" jsid="jsProgress" data-dojo-props="maximum:10" data-dojo-type="dijit/ProgressBar">
+                                    </div>
+                                </li>
+                                <li>
+                                    <label for="Progress Message">Progress Message:</label>
+                                    <div id="${id}ProgressMessage"></div>
+                                </li>
+                                <li>
+                                    <label for="Summary Message">SummaryMessage:</label>
+                                    <div id="${id}SummaryMessage"></div>
+                                </li>
+                            </ul>
+                        </form>
+                    </div>
+                    <div id="${id}ImportGroup" class="rounded">
+                        <h1>Spray Details</h1>
+                        <form>
+                            <ul>
+                                <li>
+                                    <label for="State">State:</label>
+                                    <div>
+                                        <select id="${id}State" name="SelectType" data-dojo-type="dijit/form/Select">
+                                            <option value="Finished">Finished</option>
+                                            <option value="Failed">Failed</option>
+                                        </select>
+                                    </div>
+                                </li>
+                                <li>
+                                    <label for="Source IP">Source IP:</label>
+                                    <div id="${id}SourceIP"></div>
+                                </li>
+                                <li>
+                                    <label for="Source File Path">SourceFilePath:</label>
+                                    <div id="${id}SourceFilePath"></div>
+                                </li>
+                                <li>
+                                    <label for="Source Record Size">SourceRecordSize:</label>
+                                    <div id="${id}SourceRecordSize"></div>
+                                </li>
+                                <li>
+                                    <label for="Source Format">SourceFormat:</label>
+                                    <div id="${id}SourceFormat"></div>
+                                </li>
+                                <li>
+                                    <label for="Source Num Parts">SourceNumParts:</label>
+                                    <div id="${id}SourceNumParts"></div>
+                                </li>
+                                <li>
+                                    <label for="Source Directory">SourceDirectory:</label>
+                                    <div id="${id}SourceDirectory"></div>
+                                </li>
+                                <li>
+                                    <label for="DestLogicalName">DestLogicalName:</label>
+                                    <div id="${id}DestLogicalName"></div>
+                                </li>
+                                <li>
+                                    <label for="Destination Group Name">DestGroupName:</label>
+                                    <div id="${id}DestGroupName"></div>
+                                </li>
+                                <li>
+                                    <label for="Destination Directory">DestDirectory:</label>
+                                    <div id="${id}DestDirectory"></div>
+                                </li>
+                                <li>
+                                    <label for="Destination Number Parts">DestNumParts:</label>
+                                    <div id="${id}DestNumParts"></div>
+                                </li>
+                                <li>
+                                    <label for="Monitor Sub">MonitorSub:</label>
+                                    <div id="${id}MonitorSub"></div>
+                                </li>
+                                <li>
+                                    <label for="Overwrite">Overwrite:</label>
+                                    <div id="${id}Overwrite"></div>
+                                </li>
+                                <li>
+                                    <label for="Replicate">Replicate:</label>
+                                    <div id="${id}Replicate"></div>
+                                </li>
+                                <li>
+                                    <label for="Compress">Compress:</label>
+                                    <div id="${id}Compress"></div>
+                                </li>
+                                <li>
+                                    <label for="Auto Refresh">AutoRefresh:</label>
+                                    <div id="${id}AutoRefresh"></div>
+                                </li>
+                            </ul>
+                        </form>
+                    </div>
+                    <div id="${id}ExportGroup" class="rounded">
+                        <h1>Despray Details</h1>
+                        <form>
                             <ul>
-                             <li>
-                                <label for="State">State:</label>
-                                <div>
-                                    <select name="SelectType" data-dojo-type="dijit/form/Select" id="${id}State">
-                                        <option value="Finished">Finished</option>
-                                        <option value="Failed">Failed</option>    
-                                    </select>
-                                </div>
-                            </li>
-                            <li>
-                                <label for="Source Logical Name">SourceLogicalName:</label>
-                                <div id="${id}SourceLogicalName"></div>
-                            </li>
-                            <li>
-                                <label for="Destination Directory">DestDirectory:</label>
-                                <div id="${id}DestDirectory"></div>
-                            </li>
-                            <li>
-                                <label for="Destination IP">DestIP:</label>
-                                <div id="${id}DestIP"></div>
-                            </li>
-                            <li>
-                                <label for="Destination File Path">DestFilePath:</label>
-                                <div id="${id}DestFilePath"></div>
-                            </li>
-                            <li>
-                                <label for="Destination Format">DestFormat:</label>
-                                <div id="${id}DestFormat"></div>
-                            </li>
-                            <li>
-                                <label for="Destination Number Parts">DestNumParts:</label>
-                                <div id="${id}DestNumParts"></div>
-                            </li>
-                            <li>
-                                <label for="Monitor Sub">MonitorSub:</label>
-                                <div id="${id}MonitorSub"></div>
-                            </li>
-                            <li>
-                                <label for="Overwrite">Overwrite:</label>
-                                <div id="${id}Overwrite"></div>
-                            </li>
-                            <li>
-                                <label for="Replicate">Replicate:</label>
-                                <div id="${id}Replicate"></div>
-                            </li>
-                            <li>
-                                <label for="Compress">Compress:</label>
-                                <div id="${id}Compress"></div>
-                            </li>
-                             <li>
-                                <label for="Auto Refresh">AutoRefresh:</label>
-                                <div id="${id}AutoRefresh"></div>
-                            </li>
-                        </ul>
-                        </form>  
+                                <li>
+                                    <label for="State">State:</label>
+                                    <div>
+                                        <select id="${id}State2" name="SelectType" data-dojo-type="dijit/form/Select">
+                                            <option value="Finished">Finished</option>
+                                            <option value="Failed">Failed</option>
+                                        </select>
+                                    </div>
+                                </li>
+                                <li>
+                                    <label for="Source Logical Name">SourceLogicalName:</label>
+                                    <div id="${id}SourceLogicalName"></div>
+                                </li>
+                                <li>
+                                    <label for="Destination Directory">DestDirectory:</label>
+                                    <div id="${id}DestDirectory"></div>
+                                </li>
+                                <li>
+                                    <label for="Destination IP">DestIP:</label>
+                                    <div id="${id}DestIP"></div>
+                                </li>
+                                <li>
+                                    <label for="Destination File Path">DestFilePath:</label>
+                                    <div id="${id}DestFilePath"></div>
+                                </li>
+                                <li>
+                                    <label for="Destination Format">DestFormat:</label>
+                                    <div id="${id}DestFormat"></div>
+                                </li>
+                                <li>
+                                    <label for="Destination Number Parts">DestNumParts:</label>
+                                    <div id="${id}DestNumParts"></div>
+                                </li>
+                                <li>
+                                    <label for="Monitor Sub">MonitorSub:</label>
+                                    <div id="${id}MonitorSub"></div>
+                                </li>
+                                <li>
+                                    <label for="Overwrite">Overwrite:</label>
+                                    <div id="${id}Overwrite"></div>
+                                </li>
+                                <li>
+                                    <label for="Replicate">Replicate:</label>
+                                    <div id="${id}Replicate"></div>
+                                </li>
+                                <li>
+                                    <label for="Compress">Compress:</label>
+                                    <div id="${id}Compress"></div>
+                                </li>
+                                <li>
+                                    <label for="Auto Refresh">AutoRefresh:</label>
+                                    <div id="${id}AutoRefresh"></div>
+                                </li>
+                            </ul>
+                        </form>
                     </div>
-                                  
                 </div>
             </div>
             <div id="${id}XML" title="XML" data-dojo-props="WUXml: true" data-dojo-type="ECLSourceWidget">
             </div>
-            <div id="${id}Legacy" title="Legacy Web Page" data-dojo-type="dijit.layout.ContentPane">                
+            <div id="${id}Legacy" title="Legacy Web Page" data-dojo-type="dijit.layout.ContentPane">
             </div>
-
         </div>
     </div>
 </div>

+ 76 - 0
esp/files/templates/DFUWUQueryWidget.html

@@ -0,0 +1,76 @@
+<div class="${baseClass}">
+    <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%;" data-dojo-type="dijit.layout.BorderContainer">
+        <div id="${id}TabContainer" data-dojo-props="region: 'center', tabPosition: 'top'" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.TabContainer">
+            <div id="${id}Workunits" style="width: 100%; height: 100%" data-dojo-props='title:"Logical Files"' data-dojo-type="dijit.layout.BorderContainer">
+                <div id="${id}Toolbar" class="topPanel" data-dojo-props="region: 'top'" data-dojo-type="dijit.Toolbar">
+                    <div id="${id}Open" data-dojo-attach-event="onClick:_onOpen" data-dojo-type="dijit.form.Button">Open</div>
+                    <div id="${id}Delete" data-dojo-attach-event="onClick:_onDelete" data-dojo-type="dijit.form.Button">Delete</div>
+                    <div id="${id}AddToSuperfile" data-dojo-attach-event="onClick:_onAddToSuperfile" data-dojo-type="dijit.form.Button">Add To Superfile</div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                    <div data-dojo-type="dijit.form.DropDownButton">
+                        <span>Filter</span>
+                        <div data-dojo-type="dijit.TooltipDialog" class="toolTip">
+                            <form class="smallForm">
+                                <ul>
+                                    <li>
+                                        <label for="${id}LogicalFile">Name:</label>
+                                        <input id="${id}LogicalFile" data-dojo-props="trim: true, placeHolder:'*::somefile*'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}Owner">Owner:</label>
+                                        <input id="${id}Owner" data-dojo-props="trim: true, placeHolder:'jsmi*'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}Jobname">Job Name:</label>
+                                        <input id="${id}Jobname" data-dojo-props="trim: true, placeHolder:'log_analysis_1'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}Cluster">Cluster:</label>
+                                        <input id="${id}Cluster" data-dojo-props="trim: true, placeHolder:'r?x*'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}State">State:</label>
+                                        <input id="${id}State" data-dojo-props="trim: true, placeHolder:'failed'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}ECL">ECL Text:</label>
+                                        <input id="${id}ECL" data-dojo-props="trim: true, placeHolder:':=dataset'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}FromDate">From:</label>
+                                        <img src="img/cal.gif" alt="calendar"/>
+                                        <input id="${id}FromDate" data-dojo-props="trim: true, placeHolder:'7/28/2012'" data-dojo-type="dijit.form.DateTextBox"/>
+                                        <input id="${id}FromTime" class="smallCombo" data-dojo-props="trim: true, placeHolder:'7:30 AM'" data-dojo-type="dijit.form.TimeTextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}ToDate">To:</label>
+                                        <img src="img/cal.gif" alt="calendar"/>
+                                        <input id="${id}ToDate" data-dojo-props="trim: true, placeHolder:'7/28/2012'" data-dojo-type="dijit.form.DateTextBox"/>
+                                        <input id="${id}ToTime" class="smallCombo" data-dojo-props="trim: true, placeHolder:'7:30 PM'" data-dojo-type="dijit.form.TimeTextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}LastNDays">Last N Days:</label>
+                                        <input id="${id}LastNDays" data-dojo-props="trim: true, placeHolder:'2'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                </ul>
+                                <button data-dojo-attach-event="onClick:_onFilterApply" data-dojo-type="dijit.form.Button">Apply</button>
+                                <button data-dojo-attach-event="onClick:_onFilterClear" data-dojo-type="dijit.form.Button">Clear</button>
+                            </form>
+                        </div>
+                    </div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                </div>
+                <div id="${id}WorkunitsGrid" data-dojo-props="region: 'center', plugins: { pagination: { pageSizes: [25, 50, 100, 'All'], defaultPageSize: 50, description: true, sizeSwitch: true, pageStepper: true, gotoButton: true, maxPageStep: 4, position: 'bottom' }
+                    , indirectSelection: {
+                        headerSelector: true,
+                        width: '20px',
+                        styles: 'text-align: center;'
+                    }
+                }" data-dojo-type="dojox.grid.EnhancedGrid">
+                </div>
+            </div>
+            <div id="${id}Legacy" title="Legacy Web Page" data-dojo-type="dijit.layout.ContentPane">
+            </div>
+        </div>
+    </div>
+</div>

+ 83 - 0
esp/files/templates/GetDFUWorkunitsWidget.html

@@ -0,0 +1,83 @@
+<div class="${baseClass}">
+    <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%;" data-dojo-type="dijit.layout.BorderContainer">
+        <div id="${id}TabContainer" data-dojo-props="region: 'center', tabPosition: 'top'" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.TabContainer">
+            <div id="${id}Workunits" style="width: 100%; height: 100%" data-dojo-props='title:"Workunits"' data-dojo-type="dijit.layout.BorderContainer">
+                <div id="${id}Toolbar" class="topPanel" data-dojo-props="region: 'top'" data-dojo-type="dijit.Toolbar">
+                    <div id="${id}Open" data-dojo-attach-event="onClick:_onOpen" data-dojo-type="dijit.form.Button">Open</div>
+                    <div id="${id}Delete" data-dojo-attach-event="onClick:_onDelete" data-dojo-type="dijit.form.Button">Delete</div>
+                    <div id="${id}SetToFailed" data-dojo-attach-event="onClick:_onSetToFailed" data-dojo-type="dijit.form.Button">Set To Failed</div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                    <div id="${id}Protect" data-dojo-attach-event="onClick:_onProtect" data-dojo-type="dijit.form.Button">Protect</div>
+                    <div id="${id}Unprotect" data-dojo-attach-event="onClick:_onUnprotect" data-dojo-type="dijit.form.Button">Unprotect</div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                    <div data-dojo-type="dijit.form.DropDownButton">
+                        <span>Filter</span>
+                        <div data-dojo-type="dijit.TooltipDialog" class="toolTip">
+                            <form class="smallForm">
+                                <ul>
+                                    <li> 
+                                        <label for="${id}Owner">Owner:</label>
+                                        <input id="${id}Owner" data-dojo-props="trim: true, placeHolder:'jsmi*'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}Jobname">Job Name:</label>
+                                        <input id="${id}Jobname" data-dojo-props="trim: true, placeHolder:'log_analysis_1'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}Cluster">Cluster:</label>
+                                        <input id="${id}Cluster" data-dojo-props="trim: true, placeHolder:'r?x*'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}State">State:</label>
+                                        <input id="${id}State" data-dojo-props="trim: true, placeHolder:'failed'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}ECL">ECL Text:</label>
+                                        <input id="${id}ECL" data-dojo-props="trim: true, placeHolder:':=dataset'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li>
+                                        <label for="${id}LogicalFile">Logical File:</label>
+                                        <input id="${id}LogicalFile" data-dojo-props="trim: true, placeHolder:'*::somefile'" data-dojo-type="dijit.form.TextBox"/>
+                                        <select id="${id}LogicalFileSearchType" name="${id}LogicalFileSearchType" style="width: 8em" data-dojo-type="dijit.form.Select">
+                                            <option value="Created">Created</option>
+                                            <option value="Used" selected="selected">Used</option>
+                                        </select>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}FromDate">From:</label>
+                                        <img src="img/cal.gif" alt="calendar"/>
+                                        <input id="${id}FromDate" data-dojo-props="trim: true, placeHolder:'7/28/2012'" data-dojo-type="dijit.form.DateTextBox"/>
+                                        <input id="${id}FromTime" class="smallCombo" data-dojo-props="trim: true, placeHolder:'7:30 AM'" data-dojo-type="dijit.form.TimeTextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}ToDate">To:</label>
+                                        <img src="img/cal.gif" alt="calendar"/>
+                                        <input id="${id}ToDate" data-dojo-props="trim: true, placeHolder:'7/28/2012'" data-dojo-type="dijit.form.DateTextBox"/>
+                                        <input id="${id}ToTime" class="smallCombo" data-dojo-props="trim: true, placeHolder:'7:30 PM'" data-dojo-type="dijit.form.TimeTextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}LastNDays">Last N Days:</label>
+                                        <input id="${id}LastNDays" data-dojo-props="trim: true, placeHolder:'2'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                </ul>
+                                <button data-dojo-attach-event="onClick:_onFilterApply" data-dojo-type="dijit.form.Button">Apply</button>
+                                <button data-dojo-attach-event="onClick:_onFilterClear" data-dojo-type="dijit.form.Button">Clear</button>
+                            </form>
+                        </div>
+                    </div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                </div>
+                <div id="${id}WorkunitsGrid" data-dojo-props="region: 'center', plugins: { pagination: { pageSizes: [25, 50, 100, 'All'], defaultPageSize: 50, description: true, sizeSwitch: true, pageStepper: true, gotoButton: true, maxPageStep: 4, position: 'bottom' }
+                    , indirectSelection: {
+                        headerSelector: true,
+                        width: '20px',
+                        styles: 'text-align: center;'
+                    }
+                }" data-dojo-type="dojox.grid.EnhancedGrid">
+                </div>
+            </div>
+            <div id="${id}Legacy" title="Legacy Web Page" data-dojo-type="dijit.layout.ContentPane">
+            </div>
+        </div>
+    </div>
+</div>

+ 86 - 0
esp/files/templates/WUQueryWidget.html

@@ -0,0 +1,86 @@
+<div class="${baseClass}">
+    <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%;" data-dojo-type="dijit.layout.BorderContainer">
+        <div id="${id}TabContainer" data-dojo-props="region: 'center', tabPosition: 'top'" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.TabContainer">
+            <div id="${id}Workunits" style="width: 100%; height: 100%" data-dojo-props='title:"Workunits"' data-dojo-type="dijit.layout.BorderContainer">
+                <div id="${id}Toolbar" class="topPanel" data-dojo-props="region: 'top'" data-dojo-type="dijit.Toolbar">
+                    <div id="${id}Open" data-dojo-attach-event="onClick:_onOpen" data-dojo-type="dijit.form.Button">Open</div>
+                    <div id="${id}Delete" data-dojo-attach-event="onClick:_onDelete" data-dojo-type="dijit.form.Button">Delete</div>
+                    <div id="${id}SetToFailed" data-dojo-attach-event="onClick:_onSetToFailed" data-dojo-type="dijit.form.Button">Set To Failed</div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                    <div id="${id}Protect" data-dojo-attach-event="onClick:_onProtect" data-dojo-type="dijit.form.Button">Protect</div>
+                    <div id="${id}Unprotect" data-dojo-attach-event="onClick:_onUnprotect" data-dojo-type="dijit.form.Button">Unprotect</div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                    <div id="${id}Reschedule" data-dojo-attach-event="onClick:_onReschedule" data-dojo-type="dijit.form.Button">Reschedule</div>
+                    <div id="${id}Deschedule" data-dojo-attach-event="onClick:_onDeschedule" data-dojo-type="dijit.form.Button">Deschedule</div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                    <div data-dojo-type="dijit.form.DropDownButton">
+                        <span>Filter</span>
+                        <div data-dojo-type="dijit.TooltipDialog" class="toolTip">
+                            <form class="smallForm">
+                                <ul>
+                                    <li> 
+                                        <label for="${id}Owner">Owner:</label>
+                                        <input id="${id}Owner" data-dojo-props="trim: true, placeHolder:'jsmi*'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}Jobname">Job Name:</label>
+                                        <input id="${id}Jobname" data-dojo-props="trim: true, placeHolder:'log_analysis_1'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}Cluster">Cluster:</label>
+                                        <input id="${id}Cluster" data-dojo-props="trim: true, placeHolder:'r?x*'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}State">State:</label>
+                                        <input id="${id}State" data-dojo-props="trim: true, placeHolder:'failed'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}ECL">ECL Text:</label>
+                                        <input id="${id}ECL" data-dojo-props="trim: true, placeHolder:':=dataset'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                    <li>
+                                        <label for="${id}LogicalFile">Logical File:</label>
+                                        <input id="${id}LogicalFile" data-dojo-props="trim: true, placeHolder:'*::somefile'" data-dojo-type="dijit.form.TextBox"/>
+                                        <select id="${id}LogicalFileSearchType" name="${id}LogicalFileSearchType" style="width: 8em" data-dojo-type="dijit.form.Select">
+                                            <option value="Created">Created</option>
+                                            <option value="Used" selected="selected">Used</option>
+                                        </select>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}FromDate">From:</label>
+                                        <img src="img/cal.gif" alt="calendar"/>
+                                        <input id="${id}FromDate" data-dojo-props="trim: true, placeHolder:'7/28/2012'" data-dojo-type="dijit.form.DateTextBox"/>
+                                        <input id="${id}FromTime" class="smallCombo" data-dojo-props="trim: true, placeHolder:'7:30 AM'" data-dojo-type="dijit.form.TimeTextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}ToDate">To:</label>
+                                        <img src="img/cal.gif" alt="calendar"/>
+                                        <input id="${id}ToDate" data-dojo-props="trim: true, placeHolder:'7/28/2012'" data-dojo-type="dijit.form.DateTextBox"/>
+                                        <input id="${id}ToTime"  data-dojo-props="trim: true, placeHolder:'7:30 PM'" data-dojo-type="dijit.form.TimeTextBox"/>
+                                    </li>
+                                    <li> 
+                                        <label for="${id}LastNDays">Last N Days:</label>
+                                        <input id="${id}LastNDays" data-dojo-props="trim: true, placeHolder:'2'" data-dojo-type="dijit.form.TextBox"/>
+                                    </li>
+                                </ul>
+                                <button data-dojo-attach-event="onClick:_onFilterApply" data-dojo-type="dijit.form.Button">Apply</button>
+                                <button data-dojo-attach-event="onClick:_onFilterClear" data-dojo-type="dijit.form.Button">Clear</button>
+                            </form>
+                        </div>
+                    </div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                </div>
+                <div id="${id}WorkunitsGrid" data-dojo-props="region: 'center', plugins: { pagination: { pageSizes: [25, 50, 100, 'All'], defaultPageSize: 50, description: true, sizeSwitch: true, pageStepper: true, gotoButton: true, maxPageStep: 4, position: 'bottom' }
+                    , indirectSelection: {
+                        headerSelector: true,
+                        width: '20px',
+                        styles: 'text-align: center;'
+                    }
+                }" data-dojo-type="dojox.grid.EnhancedGrid">
+                </div>
+            </div>
+            <div id="${id}Legacy" title="Legacy Web Page" data-dojo-type="dijit.layout.ContentPane">
+            </div>
+        </div>
+    </div>
+</div>

+ 2 - 2
esp/services/ws_fs/ws_fsBinding.hpp

@@ -52,14 +52,14 @@ public:
 
         IPropertyTree *folder0 = ensureNavFolder(data, "DFU Workunits", NULL, NULL, false, 5);
         ensureNavLink(*folder0, "Search", "/FileSpray/DFUWUSearch", "Search for DFU workunits ", NULL, NULL, 1);
-        ensureNavLink(*folder0, "Browse", "/FileSpray/GetDFUWorkunits", "Browse a list of DFU workunits", NULL, NULL, 2);
+        ensureNavLink(*folder0, "Browse", "/esp/files/stub.htm?Widget=GetDFUWorkunitsWidget", "Browse a list of DFU workunits", NULL, NULL, 2);
         IPropertyTree *folder = ensureNavFolder(data, "DFU Files", NULL, NULL, false, 6);
         ensureNavLink(*folder, "Upload/download File", "/FileSpray/DropZoneFiles", "Upload or download File from a Drop Zone in the environment", NULL, NULL, 1);
         ensureNavLink(*folder, "View Data File", "/WsDfu/DFUGetDataColumns?ChooseFile=1", "Allows you to view the contents of a logical file", NULL, NULL, 2);
         ensureNavLink(*folder, "Search File Relationships", path.str(), "Search File Relationships", NULL, NULL, 3);
         ensureNavLink(*folder, "Browse Space Usage", "/WsDfu/DFUSpace", "View details about Space Usage", NULL, NULL, 4);
         ensureNavLink(*folder, "Search Logical Files", "/WsDfu/DFUSearch", "Search for Logical Files using a variety of search criteria", NULL, NULL, 5);
-        ensureNavLink(*folder, "Browse Logical Files", "/WsDfu/DFUQuery", "Browse a list of Logical Files", NULL, NULL, 6);
+        ensureNavLink(*folder, "Browse Logical Files", "/esp/files/stub.htm?Widget=DFUWUQueryWidget", "Browse a list of Logical Files", NULL, NULL, 6);
         ensureNavLink(*folder, "Browse Files by Scope", "/WsDfu/DFUFileView", "Browse a list of Logical Files by Scope", NULL, NULL, 7);
         ensureNavLink(*folder, "Spray Fixed", "/FileSpray/SprayFixedInput", "Spray a fixed width file", NULL, NULL, 8);
         ensureNavLink(*folder, "Spray CSV", "/FileSpray/SprayVariableInput?submethod=csv", "Spray a comma separated value file", NULL, NULL, 9);

+ 1 - 1
esp/services/ws_workunits/ws_workunitsService.hpp

@@ -135,7 +135,7 @@ public:
         {
             IPropertyTree *folder = ensureNavFolder(data, "ECL", "Run Ecl code and review Ecl workunits", NULL, false, 2);
             ensureNavLink(*folder, "Search Workunits", "/WsWorkunits/WUQuery?form_", "Search Workunits", NULL, NULL, 1);
-            ensureNavLink(*folder, "Browse Workunits", "/WsWorkunits/WUQuery", "Browse Workunits", NULL, NULL, 2);
+            ensureNavLink(*folder, "Browse Workunits", "/esp/files/stub.htm?Widget=WUQueryWidget", "Browse Workunits", NULL, NULL, 2);
             ensureNavLink(*folder, "ECL Playground", "/esp/files/stub.htm?Widget=ECLPlaygroundWidget", "ECL Editor, Executor, Graph and Result Viewer", NULL, NULL, 4);
 
             IPropertyTree *folderQueryset = ensureNavFolder(data, "Queries", NULL, NULL, false, 3);