瀏覽代碼

Merge pull request #3740 from GordonSmith/HPCC-7984

HPCC-7984 ECLWatch 4.0

Reviewed-By: Miguel Vazquez <miguel.vazquez@lexisnexis.com>
Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 12 年之前
父節點
當前提交
cb0eda5faf
共有 49 個文件被更改,包括 3028 次插入795 次删除
  1. 2 1
      esp/eclwatch/ws_XSLT/dfu.xslt
  2. 1 1
      esp/eclwatch/ws_XSLT/dfu_workunits.xslt
  3. 1 5
      esp/eclwatch/ws_XSLT/workunits.xslt
  4. 0 12
      esp/eclwatch/ws_XSLT/wuidcommon.xslt
  5. 161 51
      esp/files/css/hpcc.css
  6. 3 0
      esp/files/scripts/CMakeLists.txt
  7. 239 0
      esp/files/scripts/DFUSearchWidget.js
  8. 313 0
      esp/files/scripts/DFUWUDetailsWidget.js
  9. 8 7
      esp/files/scripts/ECLPlaygroundWidget.js
  10. 4 7
      esp/files/scripts/ECLSourceWidget.js
  11. 217 0
      esp/files/scripts/ESPDFUWorkunit.js
  12. 134 0
      esp/files/scripts/ESPLogicalFile.js
  13. 22 4
      esp/files/scripts/ESPResult.js
  14. 161 112
      esp/files/scripts/ESPWorkunit.js
  15. 85 0
      esp/files/scripts/FilePartsWidget.js
  16. 39 50
      esp/files/scripts/GraphPageWidget.js
  17. 52 34
      esp/files/scripts/GraphWidget.js
  18. 123 0
      esp/files/scripts/GraphsWidget.js
  19. 78 36
      esp/files/scripts/InfoGridWidget.js
  20. 254 0
      esp/files/scripts/LFDetailsWidget.js
  21. 13 5
      esp/files/scripts/LogsWidget.js
  22. 150 0
      esp/files/scripts/ResultWidget.js
  23. 0 206
      esp/files/scripts/ResultsControl.js
  24. 92 69
      esp/files/scripts/ResultsWidget.js
  25. 6 0
      esp/files/scripts/TargetSelectWidget.js
  26. 13 6
      esp/files/scripts/TimingGridWidget.js
  27. 30 1
      esp/files/scripts/TimingPageWidget.js
  28. 37 37
      esp/files/scripts/TimingTreeMapWidget.js
  29. 66 49
      esp/files/scripts/WUDetailsWidget.js
  30. 114 0
      esp/files/scripts/WsDfu.js
  31. 114 0
      esp/files/scripts/WsFileSpray.js
  32. 69 0
      esp/files/scripts/WsTopology.js
  33. 4 3
      esp/files/scripts/WsWorkunits.js
  34. 4 2
      esp/files/stub.js
  35. 1 0
      esp/files/templates/CMakeLists.txt
  36. 83 0
      esp/files/templates/DFUSearchWidget.html
  37. 138 0
      esp/files/templates/DFUWUDetailsWidget.html
  38. 1 1
      esp/files/templates/ECLPlaygroundWidget.html
  39. 2 2
      esp/files/templates/ECLSourceWidget.html
  40. 4 0
      esp/files/templates/FilePartsWidget.html
  41. 2 3
      esp/files/templates/GraphPageWidget.html
  42. 4 0
      esp/files/templates/GraphsWidget.html
  43. 13 1
      esp/files/templates/InfoGridWidget.html
  44. 84 0
      esp/files/templates/LFDetailsWidget.html
  45. 13 0
      esp/files/templates/ResultWidget.html
  46. 1 11
      esp/files/templates/ResultsWidget.html
  47. 2 8
      esp/files/templates/TimingGridWidget.html
  48. 2 4
      esp/files/templates/TimingTreeMapWidget.html
  49. 69 67
      esp/files/templates/WUDetailsWidget.html

+ 2 - 1
esp/eclwatch/ws_XSLT/dfu.xslt

@@ -82,7 +82,7 @@
             <xsl:text disable-output-escaping="yes"><![CDATA[
           function DFUFilePopup(query, filename, cluster, replicate, roxiecluster, browsedata, PosId) {
             function detailsDFUFile() {
-              document.location.href='/WsDfu/DFUInfo?Name='+ escape(filename) + '&Cluster=' + cluster;
+              document.location.href='/esp/files/stub.htm?Widget=LFDetailsWidget&Name=' + escape(filename) + '&Cluster=' + cluster;
                       }
                         function browseDFUData() {
                           document.location.href='/WsDfu/DFUGetDataColumns?OpenLogicalName='+filename;
@@ -663,6 +663,7 @@
             <xsl:value-of select="$popup"/>
           </xsl:variable>
           <img id="mn{position()}" class="menu1" src="/esp/files/img/menu1.png" onclick="{$popup}"></img>
+          <a href="javascript:go('/esp/files/stub.htm?Widget=LFDetailsWidget&amp;Cluster={ClusterName}&amp;Name={Name}')">Details</a>
       </td>
             <td>
               <xsl:if test="isZipfile=1">

+ 1 - 1
esp/eclwatch/ws_XSLT/dfu_workunits.xslt

@@ -397,7 +397,7 @@
                 </xsl:if>
             </td>
             <td>
-                <a href="javascript:go('/FileSpray/GetDFUWorkunit?wuid={ID}')">
+                <a href="javascript:go('/esp/files/stub.htm?Widget=DFUWUDetailsWidget&amp;Wuid={ID}')">
                     <xsl:choose>
                         <xsl:when test="State=2 or State=3"><b><xsl:value-of select="ID"/></b></xsl:when>
                         <xsl:otherwise><xsl:value-of select="ID"/></xsl:otherwise>

+ 1 - 5
esp/eclwatch/ws_XSLT/workunits.xslt

@@ -474,7 +474,7 @@
          <td>
             <xsl:choose>
                 <xsl:when test="not(string-length($archived))">
-                    <a href="javascript:go('/WsWorkunits/WUInfo?Wuid={Wuid}&amp;&amp;IncludeExceptions=0&amp;IncludeGraphs=0&amp;IncludeSourceFiles=0&amp;IncludeResults=0&amp;IncludeVariables=0&amp;IncludeTimers=0&amp;IncludeDebugValues=0&amp;IncludeApplicationValues=0&amp;IncludeWorkflows&amp;SuppressResultSchemas=1')">
+                    <a href="javascript:go('/esp/files/stub.htm?Widget=WUDetailsWidget&amp;Wuid={Wuid}')">
                        <xsl:value-of select="Wuid"/>
                     </a>
                 </xsl:when>
@@ -484,10 +484,6 @@
                     </a>
                 </xsl:otherwise>
             </xsl:choose>
-           -
-           <a href="javascript:go('/esp/files/stub.htm?Widget=WUDetailsWidget&amp;Wuid={Wuid}')">
-             Show
-           </a>
          </td>
          <td>
          <xsl:choose>

+ 0 - 12
esp/eclwatch/ws_XSLT/wuidcommon.xslt

@@ -45,8 +45,6 @@
                   <xsl:value-of select="$wuid"/>
                   &nbsp;
                   <a href="/esp/iframe?esp_iframe_title=ECL Workunit XML - {$wuid}&amp;inner=/WsWorkunits/WUFile%3fWuid%3d{$wuid}%26Type%3dXML" >XML</a>
-                  &nbsp;
-                  <a href="/esp/iframe?esp_iframe_title=ECL Playground - {$wuid}&amp;inner=/esp/files/stub.htm%3fWidget%3dECLPlaygroundWidget%26Wuid%3d{$wuid}%26Target%3d{Cluster}" >ECL Playground</a>
                 </xsl:otherwise>
               </xsl:choose>
             </td>
@@ -398,8 +396,6 @@
                 <A href="javascript:void(0)" onclick="toggleElement('Results');" id="explinkresults" class="wusectionexpand">
                   Results: (<xsl:value-of select="ResultCount"/>)
                 </A>
-                &nbsp;-&nbsp;
-                <a href="/esp/iframe?esp_iframe_title=Results - {$wuid}&amp;inner=/esp/files/stub.htm%3fWidget%3dResultsWidget%26Wuid%3d{$wuid}" >Show</a>
               </div>
             </div>
             <div id="Results" class="wusectioncontent">
@@ -445,8 +441,6 @@
                 <A href="javascript:void(0)" onclick="toggleElement('SourceFiles');" id="explinksourcefiles" class="wusectionexpand">
                   Files: (<xsl:value-of select="SourceFileCount"/>)
                 </A>
-                &nbsp;-&nbsp;
-                <a href="/esp/iframe?esp_iframe_title=Results - {$wuid}&amp;inner=/esp/files/stub.htm%3fWidget%3dResultsWidget%26Wuid%3d{$wuid}%26SourceFiles%3dtrue" >Show</a>
               </div>
             </div>
 
@@ -526,8 +520,6 @@
                 <A href="javascript:void(0)" onclick="toggleElement('Graphs');" id="explinkgraphs" class="wusectionexpand">
                   Graphs: (<xsl:value-of select="GraphCount"/>)
                 </A>
-                &nbsp;-&nbsp;
-                <a href="/esp/iframe?esp_iframe_title=Graphs - {$wuid}&amp;inner=/esp/files/stub.htm%3fWidget%3dGraphPageWidget%26Wuid%3d{$wuid}" >Show</a>
               </div>
             </div>
           </div>
@@ -572,8 +564,6 @@
                 <A href="javascript:void(0)" onclick="toggleElement('Timers');" id="explinktimers" class="wusectionexpand">
                   Timings: (<xsl:value-of select="TimerCount"/>)
                 </A>
-                &nbsp;-&nbsp;
-                <a href="/esp/iframe?esp_iframe_title=Timers - {$wuid}&amp;inner=/esp/files/stub.htm%3fWidget%3dTimingPageWidget%26Wuid%3d{$wuid}" >Show</a>							
               </div>
             </div>
             <div id="Timers" class="wusectioncontent">
@@ -608,8 +598,6 @@
           <div class="wugroup">
               <div class="WuGroupHdrLeft">
                 <A href="javascript:void(0)" onclick="toggleElement('querysection');" id="explinkquerysection" class="wusectionexpand">Query: (1)</A>
-                &nbsp;-&nbsp;
-                <a href="/esp/iframe?esp_iframe_title=Query - {$wuid}&amp;inner=/esp/files/stub.htm%3fWidget%3dECLSourceWidget%26Wuid%3d{$wuid}" >Show</a>							
               </div>
           </div>
           <div id="querysection" class="wusectioncontent">

+ 161 - 51
esp/files/css/hpcc.css

@@ -29,11 +29,6 @@ html, body {
 }
 
 
-#borderContainer { width:100%; height:100% }
-
-#helpAction, #helpScope{
-width:12px; height:12px; }
-
 button {
     background-position: top;
     padding: 2px 8px 4px;
@@ -57,25 +52,92 @@ h1 {
     font-size: 1.5em;
 }
 
-.CodeMirror {
+#myProgressBar{
+    width:200px;
 }
-.CodeMirror-scroll {
-    position: absolute;
-    height: 100%;
-    top: 0;
-    bottom: 0;
-    left: 0;
-    right: 0;
+
+
+.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); ;
 }
 
-.claro .hpccApp .topPanel {
-    background-color: rgb(208, 233, 252);
+form {
+    margin:0;
+    padding:0;
+    width:100%;
 }
 
-.claro .hpccApp .edgePanel {
-    background-color: rgb(208, 233, 252);
+#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%;
+    margin: 0 15px 0 0;
+    text-align: left;
+    padding-top: 4px;
+    font-weight:bold;
+    height:20px;
 }
 
+form textarea{
+    font-size: 13px;
+    font-family: Arial;
+    width:auto;
+    height:auto;
+    float:left;
+}
+
+
+form ul{
+    list-style:none;
+    margin:0;
+    padding:0;
+}
+
+form li{
+    margin: 0;
+    padding: 6px 1% 9px 1%;
+    clear: both;
+    position: relative;
+    height:20px;
+}
+
+form div{
+    margin:4px 0 0 0;
+}
+
+form h2{
+    padding:5px 0;
+}
+
+#borderContainer {
+    width:100%;
+    height:100%;
+}
+
+#helpAction, #helpScope{
+    width:12px; 
+    height:12px;
+}
+
+
 #appLayout {
     height: 100%;
 }
@@ -104,7 +166,6 @@ h1 {
     overflow: hidden;
 }
 
-
 /*start styles for WUDetails*/
     #container{
         width:960px;
@@ -120,58 +181,113 @@ h1 {
         padding-left:10px;
     }
 
-    table{
-        margin-left:5px;
-    }
+   
+.CodeMirror {
+}
+.CodeMirror-scroll {
+    position: absolute;
+    height: 100%;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+}
 
+.claro .hpccApp .topPanel {
+    background-color: rgb(208, 233, 252);
+}
 
-   table tr td:first-child{
-    padding : 10px 20px 10px 0px;
-    font-size:13px;
-    font-weight:normal;
+.claro .hpccApp .edgePanel {
+    background-color: rgb(208, 233, 252);
 }
 
 
+.dijitValidationTextBoxLabel, .dijitInputField {
+    width:170px;
+    text-align: left;
 
+}
 
-form {
-    margin-left:10px;
+.iconAlign{
+    vertical-align: middle;
 }
 
-form textarea{
-    font-size: 13px;
-    font-family: Arial;
-    width:170px;}
+.iconRefresh {
+    background-image: url("../img/refresh2.png"); 
+    width: 16px;
+    height: 16px;
+}
 
+.iconLogicalFile {
+    background-image: url("../img/folder_table.png"); 
+    width: 16px;
+    height: 16px;
+}
 
 
-form div{
-    padding:5px 0px 10px 0px;  
+
+/*STATES*/
+.iconWorkunit {
+    background-image: url("../img/workunit.png"); 
+    width: 16px;
+    height: 16px;
+    display: inline-block;
 }
 
-form h2{
-    padding:5px 0px;
+
+.iconCompiled, .iconCompleted{
+    background-image: url("../img/workunit_completed.png"); 
+    width: 16px;
+    height: 16px;
+    display: inline-block;
+
 }
 
+.iconRunning, .iconCompiling, .iconDebugRunning {
+    background-image: url("../img/workunit_running.png"); 
+    width: 16px;
+    height: 16px; 
+    display: inline-block;  
+}
+
+.iconFailed, .iconStateAborted{
+    background-image: url("../img/workunit_failed.png"); 
+    width: 16px;
+    height: 16px;
+    display: inline-block;
+}
 
-.dijitValidationTextBoxLabel, .dijitInputField {
-    width:170px;
-    text-align: left;
 
+.iconArchived, .iconBlocked, .iconScheduled, .iconWait, .iconUploadingFiles, .iconDebugPaused{
+    background-image: url("../img/workunit_warning.png"); 
+    width: 16px;
+    height: 16px;
+    display: inline-block;    
 }
 
+.iconAborting{
+    background-image: url("../img/workunit_aborting.png"); 
+    width: 16px;
+    height: 16px;
+    display: inline-block;
+}
 
-.iconAlign{
-    vertical-align: middle;
+.iconSubmitted{
+    background-image: url("../img/workunit_submitted.png"); 
+    width: 16px;
+    height: 16px;
+    display: inline-block;
 }
 
-.iconRefresh {
-	background-image: url("../img/refresh2.png"); 
-	width: 16px;
-	height: 16px;
+.iconDeleted{
+    background-image: url("../img/workunit_deleted.png"); 
+    width: 16px;
+    height: 16px;
+    display: inline-block;
 }
 
-/*dijit specific styles*/
+
+
 
 .ErrorCell{
 background: red;
@@ -182,12 +298,6 @@ color: white;
 background: yellow;
 }
 
-.showDescription{
-    padding:10px;
-    height:100px;   
-}
-
-
 
 /* CAN WE MOVE AND REPLACE Prompt with this instead?.bold{
 

+ 3 - 0
esp/files/scripts/CMakeLists.txt

@@ -27,13 +27,16 @@ set ( SCRIPTS_FILES
     ${CMAKE_CURRENT_SOURCE_DIR}/effects.js
     ${CMAKE_CURRENT_SOURCE_DIR}/ESPBase.js
     ${CMAKE_CURRENT_SOURCE_DIR}/espdefault.js
+    ${CMAKE_CURRENT_SOURCE_DIR}/ESPLogicalFile.js
     ${CMAKE_CURRENT_SOURCE_DIR}/ESPResult.js
     ${CMAKE_CURRENT_SOURCE_DIR}/ESPWorkunit.js
+    ${CMAKE_CURRENT_SOURCE_DIR}/ESPDFUWorkunit.js
     ${CMAKE_CURRENT_SOURCE_DIR}/fixedTables.js
     ${CMAKE_CURRENT_SOURCE_DIR}/graphgvc.js
     ${CMAKE_CURRENT_SOURCE_DIR}/GraphPageWidget.js
     ${CMAKE_CURRENT_SOURCE_DIR}/GraphWidget.js
     ${CMAKE_CURRENT_SOURCE_DIR}/InfoGridWidget.js
+    ${CMAKE_CURRENT_SOURCE_DIR}/LFDetailsWidget.js
     ${CMAKE_CURRENT_SOURCE_DIR}/LogsWidget.js
     ${CMAKE_CURRENT_SOURCE_DIR}/multiselect.js
     ${CMAKE_CURRENT_SOURCE_DIR}/objtree.js

+ 239 - 0
esp/files/scripts/DFUSearchWidget.js

@@ -0,0 +1,239 @@
+/*##############################################################################
+#   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/xhr",
+    "dojo/dom",
+
+    "dijit/layout/_LayoutWidget",
+    "dijit/_TemplatedMixin",
+    "dijit/_WidgetsInTemplateMixin",
+    "dijit/layout/BorderContainer",
+    "dijit/layout/TabContainer",
+    "dijit/layout/ContentPane",
+    "dijit/Toolbar",
+    "dijit/form/Textarea",
+    "dijit/TitlePane",
+    "dijit/registry",
+
+    "hpcc/ECLSourceWidget",
+    "hpcc/TargetSelectWidget",
+    "hpcc/SampleSelectWidget",
+    "hpcc/GraphWidget",
+    "hpcc/ResultsWidget",
+    "hpcc/InfoGridWidget",
+    "hpcc/ESPWorkunit",
+
+    "dojo/text!../templates/DFUSearchWidget.html"
+], function (declare, xhr, dom,
+                _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, BorderContainer, TabContainer, ContentPane, Toolbar, Textarea, TitlePane, registry,
+                EclSourceWidget, TargetSelectWidget, SampleSelectWidget, GraphWidget, ResultsWidget, InfoGridWidget, Workunit,
+                template) {
+    return declare("DFUSearchWidget", [_LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
+        templateString: template,
+        baseClass: "DFUSearchWidget",
+        borderContainer: null,
+        tabContainer: null,
+        resultsWidget: null,
+        resultsWidgetLoaded: false,
+        filesWidget: null,
+        filesWidgetLoaded: false,
+        timersWidget: null,
+        timersWidgetLoaded: false,
+        graphsWidget: null,
+        graphsWidgetLoaded: false,
+        sourceWidget: null,
+        sourceWidgetLoaded: false,
+        playgroundWidget: null,
+        playgroundWidgetLoaded: false,
+        xmlWidget: null,
+        xmlWidgetLoaded: false,
+
+        wu: null,
+        loaded: false,
+
+        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.resultsWidget = registry.byId(this.id + "Results");
+            //this.filesWidget = registry.byId(this.id + "Files");
+            //this.timersWidget = registry.byId(this.id + "Timers");
+           // this.graphsWidget = registry.byId(this.id + "Graphs");
+            //this.sourceWidget = registry.byId(this.id + "Source");
+            //this.playgroundWidget = registry.byId(this.id + "Playground");
+            //this.xmlWidget = registry.byId(this.id + "XML");
+            //this.infoGridWidget = registry.byId(this.id + "InfoContainer");
+            var context = this;
+           /* this.tabContainer.watch("selectedChildWidget", function (name, oval, nval) {
+                if (nval.id == context.id + "Results" && !context.resultsWidgetLoaded) {
+                    context.resultsWidgetLoaded = true;
+                    context.resultsWidget.init({
+                        Wuid: context.wu.wuid
+                    });
+                } else if (nval.id == context.id + "Files" && !context.filesWidgetLoaded) {
+                    context.filesWidgetLoaded = true;
+                    context.filesWidget.init({
+                        Wuid: context.wu.wuid,
+                        SourceFiles: true
+                    });
+                } else if (nval.id == context.id + "Timers" && !context.timersWidgetLoaded) {
+                    context.timersWidgetLoaded = true;
+                    context.timersWidget.init({
+                        Wuid: context.wu.wuid
+                    });
+                } else if (nval.id == context.id + "Graphs" && !context.graphsWidgetLoaded) {
+                    context.graphsWidgetLoaded = true;
+                    context.graphsWidget.init({
+                        Wuid: context.wu.wuid
+                    });
+                } else if (nval.id == context.id + "Source" && !context.sourceWidgetLoaded) {
+                    context.sourceWidgetLoaded = true;
+                    context.sourceWidget.init({
+                        Wuid: context.wu.wuid
+                    });
+                } else if (nval.id == context.id + "Playground" && !context.playgroundWidgetLoaded) {
+                    context.playgroundWidgetLoaded = true;
+                    context.playgroundWidget.init({
+                        Wuid: context.wu.wuid
+                    });
+                } else if (nval.id == context.id + "XML" && !context.xmlWidgetLoaded) {
+                    context.xmlWidgetLoaded = true;
+                    context.xmlWidget.init({
+                        Wuid: context.wu.wuid
+                    });
+                }
+            });*/
+
+            
+        },
+
+        startup: function (args) {
+            this.inherited(arguments);
+        },
+
+        resize: function (args) {
+            this.inherited(arguments);
+            this.borderContainer.resize();
+        },
+
+        layout: function (args) {
+            this.inherited(arguments);
+        },
+
+        //  Hitched actions  ---
+        _onSave: function (event) {
+        },
+        _onReset: function (event) {
+        },
+        _onClone: function (event) {
+        },
+        _onDelete: function (event) {
+        },
+        _onAbort: function (event) {
+        },
+        _onResubmit: function (event) {
+        },
+        _onRestart: function (event) {
+        },
+        _onPublish: function (event) {
+        },
+
+        //  Implementation  ---
+        init: function (params) {
+            //dom.byId("showWuid").innerHTML = params.Wuid;
+            if (params.Wuid) {
+                //dom.byId(this.id + "Wuid").innerHTML = params.Wuid;
+                this.wu = new Workunit({
+                    wuid: params.Wuid
+                });
+                var context = this;
+                this.wu.monitor(function (workunit) {
+                    context.monitorWorkunit(workunit);
+                });
+            }
+           // this.infoGridWidget.init(params);
+        },
+
+        resetPage: function () {
+        },
+
+        objectToText: function (obj) {
+            var text = ""
+            for (var key in obj) {
+                text += "<tr><td>" + key + ":</td>";
+                if (typeof obj[key] == "object") {
+                    text += "[<br>";
+                    for (var i = 0; i < obj[key].length; ++i) {
+                        text += this.objectToText(obj[key][i]);
+                    }
+                    text += "<br>]<br>";
+                } else {
+                    text += "<td>" + obj[key] + "</td></tr>";
+
+                }
+            }
+            return text;
+
+        },
+
+        monitorWorkunit: function (response) {
+            if (!this.loaded) {
+                //dom.byId(this.id + "WUInfoResponse").innerHTML = this.objectToText(response);             
+                //dom.byId("showStateIdImage").src = this.wu.getStateImage();
+                //dom.byId("showStateIdImage").title = response.State;
+                //dom.byId("showStateReadOnly").innerHTML = response.State;
+                //dom.byId("showAction").innerHTML = response.ActionId;
+               // dom.byId("showOwner").innerHTML = response.Owner;
+                //dom.byId("showScope").value = response.Scope;
+                //dom.byId("showJobName").value = response.Jobname;
+                //dom.byId("showCluster").innerHTML = response.Cluster;
+                
+                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) {
+                        //dom.byId(context.id + "WUInfoResponse").innerHTML = context.objectToText(response);
+
+                    }
+                });
+            }
+        }
+    });
+});

+ 313 - 0
esp/files/scripts/DFUWUDetailsWidget.js

@@ -0,0 +1,313 @@
+/*##############################################################################
+#   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/xhr",
+    "dojo/dom",
+
+    "dijit/layout/_LayoutWidget",
+    "dijit/_TemplatedMixin",
+    "dijit/_WidgetsInTemplateMixin",
+    "dijit/layout/BorderContainer",
+    "dijit/layout/TabContainer",
+    "dijit/layout/ContentPane",
+    "dijit/Toolbar",
+    "dijit/form/Textarea",
+    "dijit/TitlePane",
+    "dijit/registry",
+    "dijit/ProgressBar",
+
+    "hpcc/ECLSourceWidget",
+    "hpcc/TargetSelectWidget",
+    "hpcc/SampleSelectWidget",
+    "hpcc/GraphWidget",
+    "hpcc/ResultsWidget",
+    "hpcc/InfoGridWidget",
+    "hpcc/ESPDFUWorkunit",
+
+    "dojo/text!../templates/DFUWUDetailsWidget.html"
+], function (declare, xhr, dom,
+                _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, BorderContainer, TabContainer, ContentPane, Toolbar, Textarea, TitlePane, registry, ProgressBar,
+                EclSourceWidget, TargetSelectWidget, SampleSelectWidget, GraphWidget, ResultsWidget, InfoGridWidget, DFUWorkunit,
+                template) {
+    return declare("DFUWUDetailsWidget", [_LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
+        templateString: template,
+        baseClass: "DFUWUDetailsWidget",
+        borderContainer: null,
+        tabContainer: null,
+        resultsWidget: null,
+        resultsWidgetLoaded: false,
+        filesWidget: null,
+        filesWidgetLoaded: false,
+        timersWidget: null,
+        timersWidgetLoaded: false,
+        graphsWidget: null,
+        graphsWidgetLoaded: false,
+        sourceWidget: null,
+        sourceWidgetLoaded: false,
+        playgroundWidget: null,
+        playgroundWidgetLoaded: false,
+        xmlWidget: null,
+        xmlWidgetLoaded: false,
+        legacyPane: null,
+        legacyPaneLoaded: false,
+
+        wu: null,
+        loaded: false,
+
+        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.legacyPane = registry.byId(this.id + "Legacy");
+            this.xmlWidget = registry.byId(this.id + "XML");
+
+
+            var context = this;
+            this.tabContainer.watch("selectedChildWidget", function (name, oval, nval) {
+                if (nval.id == context.id + "Content" && !context.resultWidgetLoaded) {
+                    context.resultWidgetLoaded = true;
+                    context.resultWidget.init({
+                        result: context.logicalFile.result
+                    });
+                } else if (nval.id == context.id + "Source" && !context.sourceWidgetLoaded) {
+                    context.sourceWidgetLoaded = true;
+                    context.sourceWidget.init({
+                        ECL: context.logicalFile.DFUInfoResponse.Ecl
+                    });
+                } else if (nval.id == context.id + "DEF" && !context.defWidgetLoaded) {
+                    context.logicalFile.fetchDEF(function (response) {
+                        context.defWidgetLoaded = true;
+                        context.defWidget.init({
+                            ECL: response
+                        });
+                    });
+                } else if (nval.id == context.id + "XML" && !context.xmlWidgetLoaded) {
+                    context.wu.fetchXML(function (response) {
+                        context.xmlWidgetLoaded = true;
+                        context.xmlWidget.init({
+                            ECL: response
+                        });
+                    });
+                } else if (nval.id == context.id + "FileParts" && !context.filePartsWidgetLoaded) {
+                    context.filePartsWidgetLoaded = true;
+                    context.filePartsWidget.init({
+                        fileParts: lang.exists("logicalFile.DFUInfoResponse.DFUFileParts.DFUPart", context) ? context.logicalFile.DFUInfoResponse.DFUFileParts.DFUPart : []
+                    });
+                } else if (nval.id == context.id + "Workunit" && !context.workunitWidgetLoaded) {
+                    context.workunitWidgetLoaded = true;
+                    context.workunitWidget.init({
+                        Wuid: context.logicalFile.DFUInfoResponse.Wuid
+                    });
+                } else if (nval.id == context.id + "DFUWorkunit" && !context.workunitWidgetLoaded) {
+                    context.dfuWorkunitWidgetLoaded = true;
+                    context.dfuWorkunitWidget.init({
+                        Wuid: context.logicalFile.DFUInfoResponse.Wuid
+                    });
+                } else if (nval.id == context.id + "Legacy" && !context.legacyPaneLoaded) {
+                    context.legacyPaneLoaded = true;
+                    context.legacyPane.set("content", dojo.create("iframe", {
+                        src: "/FileSpray/GetDFUWorkunit?wuid=" + context.wu.Wuid,
+                        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);
+            this.borderContainer.resize();
+        },
+
+        layout: function (args) {
+            this.inherited(arguments);
+        },
+
+        //  Hitched actions  ---
+        _onSave: function (event) {
+        },
+
+        _onDelete: function (event) {
+        },
+
+        //  Implementation  ---
+        init: function (params) {
+            //dom.byId("showWuid").innerHTML = params.Wuid;
+            if (params.Wuid) {
+                registry.byId(this.id + "Summary").set("title", params.Wuid);
+                dom.byId(this.id + "Wuid").innerHTML = params.Wuid;
+
+                this.wu = new DFUWorkunit({
+                    Wuid: params.Wuid
+                });
+                var context = this;
+                this.wu.monitor(function (workunit) {
+                    context.monitorDFUWorkunit(workunit);
+                });
+            }
+           // this.infoGridWidget.init(params);
+        },
+
+        resetPage: function () {
+        },
+
+        objectToText: function (obj) {
+            var text = ""
+            for (var key in obj) {
+                text += "<tr><td>" + key + ":</td>";
+                if (typeof obj[key] == "object") {
+                    text += "[<br>";
+                    for (var i = 0; i < obj[key].length; ++i) {
+                        text += this.objectToText(obj[key][i]);
+                    }
+                    text += "<br>]<br>";
+                } else {
+                    text += "<td>" + obj[key] + "</td></tr>";
+
+                }
+            }
+            return text;
+
+        },
+
+        _onSave: function (event) { 
+            var protectedCheckbox = registry.byId(this.id + "Protected");
+            var context = this;
+            this.wu.update({
+                //Description: dom.byId(context.id + "Description").value,
+                //obname: dom.byId(context.id + "JobName").value,
+                Protected: protectedCheckbox.get("value")
+            }, null, {
+                load: function (response) {
+                    context.monitor();
+                }
+            });
+        },
+
+        _onAbort: function (event) {
+            var context = this;
+            this.wu.abort({
+                load: function (response) {
+                    context.monitor();
+                }
+            });
+        },
+         _onResubmit: function (event) {
+            var context = this;
+            this.wu.resubmit({
+                load: function (response) {
+                    context.monitor();
+                }
+            });
+        },
+         _onModify: function (event) {
+            var context = this;
+            this.wu.resubmit({
+                load: function (response) {
+                    context.monitor();
+                }
+            });
+        },
+
+        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;
+            }
+
+
+
+            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) {
+                        
+
+                    }
+                });
+            }
+        }
+    });
+});

+ 8 - 7
esp/files/scripts/ECLPlaygroundWidget.js

@@ -92,8 +92,8 @@ define([
                 this.hideTitle();
             }
 
-            this.wuid = params.Wuid;
-            this.targetSelectWidget.setValue(params.Target);
+            this.Wuid = params.Wuid;
+            this.targetSelectWidget.init(params);
 
             this.initEditor();
             this.editorControl.init(params);
@@ -102,10 +102,10 @@ define([
             this.initGraph();
             if (params.Wuid) {
                 this.wu = new Workunit({
-                    wuid: params.Wuid
+                    Wuid: params.Wuid
                 });
                 this.wu.monitor(function () {
-                    context.monitorEclPlayground();
+                    context.monitorWorkunit();
                 });
             } else {
                 this.initSamples();
@@ -155,12 +155,12 @@ define([
             this.resultsWidget.clear();
         },
 
-        monitorEclPlayground: function () {
+        monitorWorkunit: function () {
             dom.byId(this.id + "Status").innerHTML = this.wu.state;
             var context = this;
             if (this.wu.isComplete()) {
                 this.wu.getInfo({
-                    onGetExceptions: function (exceptions) {
+                    onGetWUExceptions: function (exceptions) {
                         context.displayExceptions(exceptions);
                     },
                     onGetResults: function (results) {
@@ -218,10 +218,11 @@ define([
                 },
                 onSubmit: function () {
                     context.wu.monitor(function () {
-                        context.monitorEclPlayground();
+                        context.monitorWorkunit();
                     });
                 }
             });
+            this.wu.create();
         }
     });
 });

+ 4 - 7
esp/files/scripts/ECLSourceWidget.js

@@ -15,11 +15,6 @@
 ############################################################################## */
 define([
     "dojo/_base/declare",
-    "dojo/aspect",
-    "dojo/has",
-    "dojo/dom",
-    "dojo/dom-construct",
-    "dojo/dom-class",
 
     "dijit/layout/_LayoutWidget",
     "dijit/_TemplatedMixin",
@@ -34,7 +29,7 @@ define([
 
     "dijit/Toolbar", "dijit/ToolbarSeparator", "dijit/form/Button"
 ],
-    function (declare, aspect, has, dom, domConstruct, domClass,
+    function (declare,
             _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, BorderContainer, ContentPane, registry,
             ESPWorkunit,
             template) {
@@ -85,7 +80,7 @@ define([
                 var context = this;
                 if (params.Wuid) {
                     this.wu = new ESPWorkunit({
-                        wuid: params.Wuid
+                        Wuid: params.Wuid
                     });
                     if (this.WUXml) {
                         this.wu.fetchXML(function (xml) {
@@ -97,6 +92,8 @@ define([
                             context.editor.setValue(text);
                         });
                     }
+                } else if (params.ECL) {
+                    context.editor.setValue(params.ECL);
                 }
             },
 

+ 217 - 0
esp/files/scripts/ESPDFUWorkunit.js

@@ -0,0 +1,217 @@
+/*##############################################################################
+#    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",
+    "hpcc/ESPResult",
+    "hpcc/ESPBase"
+], function (declare, lang, xhr, ESPResult, ESPBase) {
+    return declare(ESPBase, {
+        Wuid: "",
+
+        stateID: 0,
+        state: "",
+
+        text: "",
+
+        resultCount: 0,
+        results: [],
+
+        graphs: [],
+
+        exceptions: [],
+        timers: [],
+
+        onCreate: function () {
+        },
+        onUpdate: function () {
+        },
+        onSubmit: function () {
+        },
+        constructor: function (args) {
+            declare.safeMixin(this, args);
+        },
+        isComplete: function () {
+            switch (this.stateID) {
+                case 6:	//DFUStateFinished:
+                    return true;
+            }
+            return false;
+        },
+        monitor: function (callback, monitorDuration) {
+            if (!monitorDuration)
+                monitorDuration = 0;
+            var request = {
+            		wuid: this.Wuid
+            };
+            //	request['rawxml_'] = "1";
+
+            var context = this;
+            xhr.post({
+                url: this.getBaseURL("FileSpray") + "/GetDFUWorkunit.json",
+                handleAs: "json",
+                content: request,
+                load: function (response) {
+                	var workunit = response.GetDFUWorkunitResponse.result;
+                    context.stateID = workunit.State;
+                    context.state = workunit.StateMessage;
+                    if (callback) {
+                        callback(workunit);
+                    }
+
+                    if (!context.isComplete()) {
+                        var timeout = 30;	// Seconds
+
+                        if (monitorDuration < 5) {
+                            timeout = 1;
+                        } else if (monitorDuration < 10) {
+                            timeout = 2;
+                        } else if (monitorDuration < 30) {
+                            timeout = 5;
+                        } else if (monitorDuration < 60) {
+                            timeout = 10;
+                        } else if (monitorDuration < 120) {
+                            timeout = 20;
+                        }
+                        setTimeout(function () {
+                            context.monitor(callback, monitorDuration + timeout);
+                        }, timeout * 1000);
+                    }
+                },
+                error: function () {
+                    done = true;
+                }
+            });
+        },
+        fetchStructure: function (format, onFetchStructure) {
+            var request = {
+                Name: this.logicalName,
+                Format: format,
+                rawxml_: true
+            };
+
+            var context = this;
+            xhr.post({
+                url: this.getBaseURL("FileSpray") + "/DFUWUFile",
+                handleAs: "text",
+                content: request,
+                load: function (response) {
+                    onFetchStructure(response);
+                },
+                error: function (e) {
+                }
+            });
+        },
+        
+        fetchDEF: function (onFetchXML) {
+            this.fetchStructure("def", onFetchXML);
+        },
+        
+        fetchXML: function (onFetchXML) {
+            var request = {                
+                Wuid: this.Wuid
+            };
+
+            var context = this;
+            xhr.post({
+                url: this.getBaseURL("FileSpray") + "/DFUWUFile",
+                handleAs: "text",
+                content: request,
+                load: function (response) {
+                    onFetchXML(response);
+                },
+                error: function (e) {
+                    var d = 0;
+                }
+            });
+        },
+
+        create: function (ecl) {
+        },
+        
+        update: function (request, appData, callback) {
+        },
+        
+        submit: function (target) {
+        },
+        
+        _resubmit: function (clone, resetWorkflow, callback) {
+        },
+        
+        clone: function (callback) {
+            this._resubmit(true, false, callback);
+        },
+        
+        resubmit: function (callback) {
+            this._resubmit(false, false, callback);
+        },
+        
+        restart: function (callback) {
+            this._resubmit(false, true, callback);
+        },
+        
+        _action: function (action, callback) {
+        },
+        
+        abort: function (callback) {
+            this._action("Abort", callback);
+        },
+        
+        doDelete: function (callback) {
+            this._action("Delete", callback);
+        },
+        
+        getInfo: function (args) {
+            var request = {
+            	wuid: this.Wuid
+            };
+
+            var context = this;
+            xhr.post({
+                url: this.getBaseURL("FileSpray") + "/GetDFUWorkunit.json",
+                handleAs: "json",
+                content: request,
+                load: function (response) {
+                	var workunit = response.GetDFUWorkunitResponse.result;
+                    context.GetDFUWorkunitResponse = workunit;
+
+                    if (args.onGetAll) {
+                        args.onGetAll(workunit);
+                    }
+                },
+                error: function (e) {
+                }
+            });
+        },
+        getState: function () {
+            return this.state;
+        },
+        getProtectedImage: function () {
+            if (this.protected) {
+                return "img/locked.png"
+            }
+            return "img/unlocked.png"
+        },
+        getStateImage: function () {
+            switch (this.stateID) {
+                case 6:
+                    return "img/workunit_completed.png";
+            }
+            return "img/workunit.png";
+        }
+    });
+});

+ 134 - 0
esp/files/scripts/ESPLogicalFile.js

@@ -0,0 +1,134 @@
+/*##############################################################################
+#    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",
+
+    "hpcc/ESPResult",
+    "hpcc/ESPBase"
+], function (declare, lang, xhr,
+        ESPResult, ESPBase) {
+    return declare(ESPBase, {
+        cluster: "",
+        logicalName: "",
+        result: [],
+
+        constructor: function (args) {
+            declare.safeMixin(this, args);
+            this.DFUInfoResponse = {
+                Name: this.logicalName,
+                Cluster: this.cluster
+            };
+        },
+        save: function (description, args) {
+            //WsDfu/DFUInfo?FileName=progguide%3A%3Aexampledata%3A%3Akeys%3A%3Apeople.lastname.firstname&UpdateDescription=true&FileDesc=%C2%A0123&Save+Description=Save+Description
+            var request = {
+                FileName: this.logicalName,
+                Cluster: this.cluster,
+                UpdateDescription: true,
+                FileDesc: description
+            };
+
+            var context = this;
+            xhr.post({
+                url: this.getBaseURL("WsDfu") + "/DFUInfo.json",
+                handleAs: "json",
+                content: request,
+                load: function (response) {
+                    if (response.DFUInfoResponse) {
+                        context.processDFUInfoResponse(response.DFUInfoResponse, args);
+                    }
+                },
+                error: function (e) {
+                }
+            });
+        },
+        getInfo: function (args) {
+            //WsDfu/DFUInfo?Name=progguide::exampledata::keys::people.state.city.zip.lastname.firstname.payload&Cluster=hthor__myeclagent HTTP/1.1
+            var request = {
+                Name: this.logicalName,
+                Cluster: this.cluster
+            };
+
+            var context = this;
+            xhr.post({
+                url: this.getBaseURL("WsDfu") + "/DFUInfo.json",
+                handleAs: "json",
+                content: request,
+                load: function (response) {
+                    if (response.DFUInfoResponse) {
+                        context.processDFUInfoResponse(response.DFUInfoResponse, args);
+                    }
+                },
+                error: function (e) {
+                    var d = 0;
+                }
+            });
+        },
+        processDFUInfoResponse: function(dfuInfoResponse, args) {
+            var fileDetail = dfuInfoResponse.FileDetail;
+            this.DFUInfoResponse = fileDetail;
+            this.result = new ESPResult(fileDetail);
+
+            if (args.onGetAll) {
+                args.onGetAll(fileDetail);
+            }
+        },
+        fetchStructure: function (format, onFetchStructure) {
+            var request = {
+                Name: this.logicalName,
+                Format: format,
+                rawxml_: true
+            };
+
+            var context = this;
+            xhr.post({
+                url: this.getBaseURL("WsDfu") + "/DFUDefFile",
+                handleAs: "text",
+                content: request,
+                load: function (response) {
+                    onFetchStructure(response);
+                },
+                error: function (e) {
+                }
+            });
+        },
+        fetchDEF: function (onFetchXML) {
+            this.fetchStructure("def", onFetchXML);
+        },
+        fetchXML: function (onFetchXML) {
+            var request = {
+                Name: this.logicalName,
+                Format: "xml",
+                rawxml_: true
+            };
+
+            var context = this;
+            xhr.post({
+                url: this.getBaseURL("WsDfu") + "/DFUDefFile",
+                handleAs: "text",
+                content: request,
+                load: function (response) {
+                    onFetchXML(response);
+                },
+                error: function (e) {
+                    var d = 0;
+                }
+            });
+        }
+    });
+});

+ 22 - 4
esp/files/scripts/ESPResult.js

@@ -16,6 +16,7 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/Deferred",
+    "dojo/_base/lang",
     "dojo/data/ObjectStore",
     "dojo/dom-construct",
 
@@ -25,7 +26,7 @@ define([
 
     "hpcc/WsWorkunits",
     "hpcc/ESPBase"
-], function (declare, Deferred, ObjectStore, domConstruct,
+], function (declare, Deferred, lang, ObjectStore, domConstruct,
             parser, DomParser, entities,
             WsWorkunits, ESPBase) {
     return declare(ESPBase, {
@@ -36,13 +37,14 @@ define([
             declare.safeMixin(this, args);
             if (this.Sequence != null) {
                 this.store = new WsWorkunits.WUResult({
-                    wuid: this.wuid,
+                    wuid: this.Wuid,
                     sequence: this.Sequence,
                     isComplete: this.isComplete()
                 });
             } else {
                 this.store = new WsWorkunits.WUResult({
-                    wuid: this.wuid,
+                    wuid: this.Wuid,
+                    cluster: this.Cluster,
                     name: this.Name,
                     isComplete: true
                 });
@@ -64,6 +66,15 @@ define([
             return this.Total != "-1";
         },
 
+        canShowResults: function () {
+            if (lang.exists("Sequence", this)) { //  Regular WU result
+                return true;
+            } else if (lang.exists("RecordCount", this) && this.RecordCount != "") { //  DFU Sprayed CSV File will fail here
+                return true;
+            }
+            return false;
+        },
+
         getFirstSchemaNode: function (node, name) {
             if (node && node.attributes) {
                 if ((node.baseName && node.baseName == name) || (node.localName && node.localName == name) || (typeof (node.getAttribute) != "undefined" && node.getAttribute("name") == name)) {
@@ -189,7 +200,7 @@ define([
                     cells: [
                         [
                             {
-                                name: "##", field: this.store.idProperty, width: "40px", classes: "resultGridCell"
+                                name: "##", field: this.store.idProperty, width: "6", classes: "resultGridCell"
                             }
                         ]
                     ]
@@ -290,6 +301,13 @@ define([
             });
         },
 
+        getLoadingMessage: function () {
+            if (lang.exists("wu.state", this)) {
+                return "<span class=\'dojoxGridWating\'>[" + this.wu.state + "]</span>";
+            }
+            return "<span class=\'dojoxGridWating\'>[unknown]</span>";
+        },
+
         getECLRecord: function () {
             var retVal = "RECORD\n";
             for (var i = 0; i < this.ECLSchemas.ECLSchemaItem.length; ++i) {

+ 161 - 112
esp/files/scripts/ESPWorkunit.js

@@ -21,7 +21,7 @@ define([
     "hpcc/ESPBase"
 ], function (declare, lang, xhr, ESPResult, ESPBase) {
     return declare(ESPBase, {
-        wuid: "",
+        Wuid: "",
 
         stateID: 0,
         state: "",
@@ -36,6 +36,8 @@ define([
         exceptions: [],
         timers: [],
 
+        WUInfoResponse: {},
+
         onCreate: function () {
         },
         onUpdate: function () {
@@ -44,9 +46,10 @@ define([
         },
         constructor: function (args) {
             declare.safeMixin(this, args);
-
-            if (!this.wuid) {
-                this.create();
+            if (this.Wuid) {
+                this.WUInfoResponse = {
+                    Wuid: this.Wuid
+                }
             }
         },
         isComplete: function () {
@@ -67,41 +70,56 @@ define([
         monitor: function (callback, monitorDuration) {
             if (!monitorDuration)
                 monitorDuration = 0;
-            var request = {};
-            request['Wuid'] = this.wuid;
-            request['rawxml_'] = "1";
+            var request = {
+                Wuid: this.Wuid,
+                TruncateEclTo64k: true,
+                IncludeExceptions: false,
+                IncludeGraphs: false,
+                IncludeSourceFiles: false,
+                IncludeResults: false,
+                IncludeResultsViewNames: false,
+                IncludeVariables: false,
+                IncludeTimers: false,
+                IncludeDebugValues: false,
+                IncludeApplicationValues: false,
+                IncludeWorkflows: false,
+                IncludeXmlSchemas: false,
+                SuppressResultSchemas: true
+            };
 
             var context = this;
             xhr.post({
-                url: this.getBaseURL() + "/WUQuery.json",
+                url: this.getBaseURL() + "/WUInfo.json",
                 handleAs: "json",
                 content: request,
                 load: function (response) {
-                    var workunit = response.WUQueryResponse.Workunits.ECLWorkunit[0];
-                    context.stateID = workunit.StateID;
-                    context.state = workunit.State;
-                    context.protected = workunit.Protected;
-                    if (callback) {
-                        callback(workunit);
-                    }
+                    if (lang.exists("WUInfoResponse.Workunit", response)) {
+                        context.WUInfoResponse = response.WUInfoResponse.Workunit;
+                        context.stateID = context.WUInfoResponse.StateID;
+                        context.state = context.WUInfoResponse.State;
+                        context.protected = context.WUInfoResponse.Protected;
+                        if (callback) {
+                            callback(context.WUInfoResponse);
+                        }
 
-                    if (!context.isComplete()) {
-                        var timeout = 30;	// Seconds
+                        if (!context.isComplete()) {
+                            var timeout = 30;	// Seconds
 
-                        if (monitorDuration < 5) {
-                            timeout = 1;
-                        } else if (monitorDuration < 10) {
-                            timeout = 2;
-                        } else if (monitorDuration < 30) {
-                            timeout = 5;
-                        } else if (monitorDuration < 60) {
-                            timeout = 10;
-                        } else if (monitorDuration < 120) {
-                            timeout = 20;
+                            if (monitorDuration < 5) {
+                                timeout = 1;
+                            } else if (monitorDuration < 10) {
+                                timeout = 2;
+                            } else if (monitorDuration < 30) {
+                                timeout = 5;
+                            } else if (monitorDuration < 60) {
+                                timeout = 10;
+                            } else if (monitorDuration < 120) {
+                                timeout = 20;
+                            }
+                            setTimeout(function () {
+                                context.monitor(callback, monitorDuration + timeout);
+                            }, timeout * 1000);
                         }
-                        setTimeout(function () {
-                            context.monitor(callback, monitorDuration + timeout);
-                        }, timeout * 1000);
                     }
                 },
                 error: function () {
@@ -119,7 +137,7 @@ define([
                 handleAs: "json",
                 content: request,
                 load: function (response) {
-                    context.wuid = response.WUCreateResponse.Workunit.Wuid;
+                    context.Wuid = response.WUCreateResponse.Workunit.Wuid;
                     context.onCreate();
                 },
                 error: function () {
@@ -128,7 +146,7 @@ define([
         },
         update: function (request, appData, callback) {
             lang.mixin(request, {
-                Wuid: this.wuid,
+                Wuid: this.Wuid,
                 rawxml_: true
             });
             if (this.WUInfoResponse) {
@@ -173,7 +191,7 @@ define([
         },
         submit: function (target) {
             var request = {
-                Wuid: this.wuid,
+                Wuid: this.Wuid,
                 Cluster: target
             };
             request['rawxml_'] = "1";
@@ -192,7 +210,7 @@ define([
         },
         _resubmit: function (clone, resetWorkflow, callback) {
             var request = {
-                Wuids: this.wuid,
+                Wuids: this.Wuid,
                 CloneWorkunit: clone,
                 ResetWorkflow: resetWorkflow,
                 rawxml_: true
@@ -226,7 +244,7 @@ define([
         },
         _action: function (action, callback) {
             var request = {
-                Wuids: this.wuid,
+                Wuids: this.Wuid,
                 ActionType: action,
                 rawxml_: true
             };
@@ -256,7 +274,7 @@ define([
         },
         publish: function (jobName) {
             var request = {
-                Wuid: this.wuid,
+                Wuid: this.Wuid,
                 JobName: jobName,
                 Activate: 1,
                 UpdateWorkUnitName: 1,
@@ -277,9 +295,9 @@ define([
         },
         getInfo: function (args) {
             var request = {
-                Wuid: this.wuid,
+                Wuid: this.Wuid,
                 TruncateEclTo64k: args.onGetText ? false : true,
-                IncludeExceptions: args.onGetExceptions ? true : false,
+                IncludeExceptions: args.onGetWUExceptions ? true : false,
                 IncludeGraphs: args.onGetGraphs ? true : false,
                 IncludeSourceFiles: args.onGetSourceFiles ? true : false,
                 IncludeResults: args.onGetResults ? true : false,
@@ -300,92 +318,92 @@ define([
                 handleAs: "json",
                 content: request,
                 load: function (response) {
-                    //var workunit = context.getValue(xmlDom, "Workunit", ["ECLException", "ECLResult", "ECLGraph", "ECLTimer", "ECLSchemaItem", "ApplicationValue"]);
-                    var workunit = response.WUInfoResponse.Workunit;
-                    context.WUInfoResponse = workunit;
+                    if (lang.exists("WUInfoResponse.Workunit", response)) {
+                        context.WUInfoResponse = response.WUInfoResponse.Workunit;
 
-                    if (args.onGetText && workunit.Query.Text) {
-                        context.text = workunit.Query.Text;
-                        args.onGetText(context.text);
-                    }
-                    if (args.onGetExceptions && workunit.Exceptions && workunit.Exceptions.ECLException) {
-                        context.exceptions = [];
-                        for (var i = 0; i < workunit.Exceptions.ECLException.length; ++i) {
-                            context.exceptions.push(workunit.Exceptions.ECLException[i]);
+                        if (args.onGetText && lang.exists("Query.Text", context.WUInfoResponse)) {
+                            context.text = context.WUInfoResponse.Query.Text;
+                            args.onGetText(context.text);
                         }
-                        args.onGetExceptions(context.exceptions);
-                    }
-                    if (args.onGetApplicationValues && workunit.ApplicationValues && workunit.ApplicationValues.ApplicationValue) {
-                        context.applicationValues = workunit.ApplicationValues.ApplicationValue;
-                        args.onGetApplicationValues(context.applicationValues)
-                    }
-                    if (args.onGetVariables && workunit.Variables && workunit.Variables.ECLResult) {
-                        context.variables = [];
-                        var variables = workunit.Variables.ECLResult;
-                        for (var i = 0; i < variables.length; ++i) {
-                            context.variables.push(lang.mixin({
-                                ColumnType: variables[i].ECLSchemas && variables[i].ECLSchemas.ECLSchemaItem.length ? variables[i].ECLSchemas.ECLSchemaItem[0].ColumnType : "unknown"
-                            }, variables[i]));
+                        if (args.onGetWUExceptions && lang.exists("Exceptions.ECLException", context.WUInfoResponse)) {
+                            context.exceptions = [];
+                            for (var i = 0; i < context.WUInfoResponse.Exceptions.ECLException.length; ++i) {
+                                context.exceptions.push(context.WUInfoResponse.Exceptions.ECLException[i]);
+                            }
+                            args.onGetWUExceptions(context.exceptions);
                         }
-                        args.onGetVariables(context.variables);
-                    }
-                    if (args.onGetResults && workunit.Results && workunit.Results.ECLResult) {
-                        context.results = [];
-                        var results = workunit.Results.ECLResult;
-                        for (var i = 0; i < results.length; ++i) {
-                            context.results.push(new ESPResult(lang.mixin({ wuid: context.wuid }, results[i])));
+                        if (args.onGetApplicationValues && lang.exists("ApplicationValues.ApplicationValue", context.WUInfoResponse)) {
+                            context.applicationValues = context.WUInfoResponse.ApplicationValues.ApplicationValue;
+                            args.onGetApplicationValues(context.applicationValues)
                         }
-                        args.onGetResults(context.results);
-                    }
-                    if (args.onGetSourceFiles && workunit.SourceFiles && workunit.SourceFiles.ECLSourceFile) {
-                        context.sourceFiles = [];
-                        var sourceFiles = workunit.SourceFiles.ECLSourceFile;
-                        for (var i = 0; i < sourceFiles.length; ++i) {
-                            context.sourceFiles.push(new ESPResult(lang.mixin({ wuid: context.wuid }, sourceFiles[i])));
+                        if (args.onGetVariables && lang.exists("Variables.ECLResult", context.WUInfoResponse)) {
+                            context.variables = [];
+                            var variables = context.WUInfoResponse.Variables.ECLResult;
+                            for (var i = 0; i < variables.length; ++i) {
+                                context.variables.push(lang.mixin({
+                                    ColumnType: variables[i].ECLSchemas && variables[i].ECLSchemas.ECLSchemaItem.length ? variables[i].ECLSchemas.ECLSchemaItem[0].ColumnType : "unknown"
+                                }, variables[i]));
+                            }
+                            args.onGetVariables(context.variables);
                         }
-                        args.onGetSourceFiles(context.sourceFiles);
-                    }
-                    if (args.onGetTimers && workunit.Timers && workunit.Timers.ECLTimer) {
-                        context.timers = [];
-                        for (var i = 0; i < workunit.Timers.ECLTimer.length; ++i) {
-                            var timeParts = workunit.Timers.ECLTimer[i].Value.split(":");
-                            var secs = 0;
-                            for (var j = 0; j < timeParts.length; ++j) {
-                                secs = secs * 60 + timeParts[j] * 1;
+                        if (args.onGetResults && lang.exists("Results.ECLResult", context.WUInfoResponse)) {
+                            context.results = [];
+                            var results = context.WUInfoResponse.Results.ECLResult;
+                            for (var i = 0; i < results.length; ++i) {
+                                context.results.push(new ESPResult(lang.mixin({ wu: context, Wuid: context.Wuid }, results[i])));
+                            }
+                            args.onGetResults(context.results);
+                        }
+                        if (args.onGetSourceFiles && lang.exists("SourceFiles.ECLSourceFile", context.WUInfoResponse)) {
+                            context.sourceFiles = [];
+                            var sourceFiles = context.WUInfoResponse.SourceFiles.ECLSourceFile;
+                            for (var i = 0; i < sourceFiles.length; ++i) {
+                                context.sourceFiles.push(new ESPResult(lang.mixin({ wu: context, Wuid: context.Wuid }, sourceFiles[i])));
                             }
+                            args.onGetSourceFiles(context.sourceFiles);
+                        }
+                        if (args.onGetTimers && lang.exists("Timers.ECLTimer", context.WUInfoResponse)) {
+                            context.timers = [];
+                            for (var i = 0; i < context.WUInfoResponse.Timers.ECLTimer.length; ++i) {
+                                var timeParts = context.WUInfoResponse.Timers.ECLTimer[i].Value.split(":");
+                                var secs = 0;
+                                for (var j = 0; j < timeParts.length; ++j) {
+                                    secs = secs * 60 + timeParts[j] * 1;
+                                }
 
-                            context.timers.push(lang.mixin(workunit.Timers.ECLTimer[i], {
-                                Seconds: Math.round(secs * 1000) / 1000,
-                                HasSubGraphId: workunit.Timers.ECLTimer[i].SubGraphId && workunit.Timers.ECLTimer[i].SubGraphId != "" ? true : false
-                            }));
+                                context.timers.push(lang.mixin(context.WUInfoResponse.Timers.ECLTimer[i], {
+                                    Seconds: Math.round(secs * 1000) / 1000,
+                                    HasSubGraphId: context.WUInfoResponse.Timers.ECLTimer[i].SubGraphId && context.WUInfoResponse.Timers.ECLTimer[i].SubGraphId != "" ? true : false
+                                }));
+                            }
+                            args.onGetTimers(context.timers);
                         }
-                        args.onGetTimers(context.timers);
-                    }
-                    if (args.onGetGraphs && workunit.Graphs && workunit.Graphs.ECLGraph) {
-                        context.graphs = workunit.Graphs.ECLGraph;
-                        if (context.timers || context.applicationValues) {
-                            for (var i = 0; i < context.graphs.length; ++i) {
-                                if (context.timers) {
-                                    context.graphs[i].Time = 0;
-                                    for (var j = 0; j < context.timers.length; ++j) {
-                                        if (context.timers[j].GraphName == context.graphs[i].Name) {
-                                            context.graphs[i].Time += context.timers[j].Seconds;
+                        if (args.onGetGraphs && lang.exists("Graphs.ECLGraph", context.WUInfoResponse)) {
+                            context.graphs = context.WUInfoResponse.Graphs.ECLGraph;
+                            if (context.timers || context.applicationValues) {
+                                for (var i = 0; i < context.graphs.length; ++i) {
+                                    if (context.timers) {
+                                        context.graphs[i].Time = 0;
+                                        for (var j = 0; j < context.timers.length; ++j) {
+                                            if (context.timers[j].GraphName == context.graphs[i].Name) {
+                                                context.graphs[i].Time += context.timers[j].Seconds;
+                                            }
+                                            context.graphs[i].Time = Math.round(context.graphs[i].Time * 1000) / 1000;
                                         }
-                                        context.graphs[i].Time = Math.round(context.graphs[i].Time * 1000) / 1000;
                                     }
-                                }
-                                if (context.applicationValues) {
-                                    var idx = context.getApplicationValueIndex("ESPWorkunit.js", context.graphs[i].Name + "_SVG");
-                                    if (idx >= 0) {
-                                        context.graphs[i].svg = context.applicationValues[idx].Value;
+                                    if (context.applicationValues) {
+                                        var idx = context.getApplicationValueIndex("ESPWorkunit.js", context.graphs[i].Name + "_SVG");
+                                        if (idx >= 0) {
+                                            context.graphs[i].svg = context.applicationValues[idx].Value;
+                                        }
                                     }
                                 }
                             }
+                            args.onGetGraphs(context.graphs)
+                        }
+                        if (args.onGetAll) {
+                            args.onGetAll(context.WUInfoResponse);
                         }
-                        args.onGetGraphs(context.graphs)
-                    }
-                    if (args.onGetAll) {
-                        args.onGetAll(workunit);
                     }
                 },
                 error: function (e) {
@@ -411,6 +429,35 @@ define([
         getState: function () {
             return this.state;
         },
+        getStateIconClass: function () {
+            switch (this.stateID) {
+                case 1:
+                case 3:
+                    return "iconCompleted";
+                case 2:
+                case 11:
+                case 15:
+                    return "iconRunning";                
+                case 4:
+                case 7:
+                    return "iconFailed";
+                case 5:
+                case 8:
+                case 10:
+                case 12:
+                case 13:
+                case 14:
+                case 16:
+                    return "iconArchived";
+                case 6:
+                    return "iconAborting";                                
+                case 9:
+                    return "iconSubmitted";                
+                case 999:
+                    return "iconDeleted";
+            }
+            return "iconWorkunit";
+        },
         getStateImage: function () {
             switch (this.stateID) {
                 case 1:
@@ -443,6 +490,8 @@ define([
                     return "img/workunit_warning.png";
                 case 15:
                     return "img/workunit_running.png";
+                case 16:
+                    return "img/workunit_warning.png";
                 case 999:
                     return "img/workunit_deleted.png";
             }
@@ -471,7 +520,7 @@ define([
             }
 
             var request = {
-                Wuid: this.wuid,
+                Wuid: this.Wuid,
                 Type: "XML"
             };
 
@@ -526,7 +575,7 @@ define([
         },
         fetchGraphXgmml: function (idx, onFetchGraphXgmml) {
             var request = {};
-            request['Wuid'] = this.wuid;
+            request['Wuid'] = this.Wuid;
             request['GraphName'] = this.graphs[idx].Name;
             request['rawxml_'] = "1";
 

+ 85 - 0
esp/files/scripts/FilePartsWidget.js

@@ -0,0 +1,85 @@
+/*##############################################################################
+#    Copyright (C) 2011 HPCC Systems.
+#
+#    All rights reserved. This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    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/>.
+############################################################################## */
+define([
+    "dojo/_base/declare",
+    "dojo/_base/array",
+    "dojo/store/Memory",
+    "dojo/data/ObjectStore",
+
+    "dijit/registry",
+    "dijit/layout/_LayoutWidget",
+    "dijit/_TemplatedMixin",
+    "dijit/_WidgetsInTemplateMixin",
+
+    "dojo/text!../templates/FilePartsWidget.html",
+
+    "dojox/grid/DataGrid"
+
+],
+    function (declare, array, Memory, ObjectStore,
+            registry, _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin,
+            template) {
+        return declare("FilePartsWidget", [_LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
+            templateString: template,
+            baseClass: "FilePartsWidget",
+            filePartsGrid: null,
+
+            dataStore: null,
+
+            lastSelection: null,
+
+            buildRendering: function (args) {
+                this.inherited(arguments);
+            },
+
+            postCreate: function (args) {
+                this.inherited(arguments);
+                this.filePartsGrid = registry.byId(this.id + "FilePartsGrid");
+
+                var context = this;
+                this.filePartsGrid.setStructure([
+                    { name: "Number", field: "Id", width: 4 },
+                    { name: "IP", field: "Ip", width: 15 },
+                    { name: "Size", field: "Partsize", width: 12 },
+                    { name: "Actual Size", field: "ActualSize", width: 12 }
+                ]);
+            },
+
+            startup: function (args) {
+                this.inherited(arguments);
+            },
+
+            resize: function (args) {
+                this.inherited(arguments);
+                this.filePartsGrid.resize();
+            },
+
+            layout: function (args) {
+                this.inherited(arguments);
+            },
+
+            //  Plugin wrapper  ---
+            init: function (params) {
+                var memory = new Memory({ data: params.fileParts });
+                this.store = new ObjectStore({ objectStore: memory });
+                this.filePartsGrid.setStore(this.store);
+                this.filePartsGrid.setQuery({
+                    Copy: "1"
+                });
+            }
+        });
+    });

+ 39 - 50
esp/files/scripts/GraphPageWidget.js

@@ -15,11 +15,13 @@
 ############################################################################## */
 define([
     "dojo/_base/declare",
+    "dojo/_base/lang",
     "dojo/_base/sniff",
     "dojo/_base/array",
     "dojo/dom",
     "dojo/dom-construct",
     "dojo/on",
+    "dojo/has",
     "dojo/store/Memory",
     "dojo/data/ObjectStore",
 
@@ -41,9 +43,8 @@ define([
 
     "dojo/text!../templates/GraphPageWidget.html",
 
-    "dijit/form/Select",
     "dijit/form/TextBox"
-], function (declare, sniff, array, dom, domConstruct, on, Memory, ObjectStore,
+], function (declare, lang, sniff, array, dom, domConstruct, on, has, Memory, ObjectStore,
             _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, BorderContainer, TabContainer, ContentPane, registry, Dialog,
             DataGrid, GraphWidget, ESPWorkunit, TimingGridWidget, TimingTreeMapWidget,
             template) {
@@ -58,7 +59,6 @@ define([
         main: null,
         overview: null,
         local: null,
-        graphSelect: null,
         timingGrid: null,
         timingTreeMap: null,
         verticesGrid: null,
@@ -67,6 +67,7 @@ define([
         findText: "",
         found: [],
         foundIndex: 0,
+        initalized: false,
 
         buildRendering: function (args) {
             this.inherited(arguments);
@@ -89,13 +90,6 @@ define([
             this.main.watchSplitter(splitter);
             this.overview.watchSplitter(splitter);
             this.local.watchSplitter(splitter);
-
-            this.main.watchSelect(this.graphSelect);
-            this.overview.watchSelect(this.graphSelect);
-            this.local.watchSelect(this.graphSelect);
-
-            this.overview.watchStyleChange();
-            this.local.watchStyleChange();
         },
 
         resize: function (args) {
@@ -113,7 +107,6 @@ define([
             this.rightBorderContainer = registry.byId(this.id + "RightBorderContainer");
             this.findField = registry.byId(this.id + "FindField");
             this._initGraphControls();
-            this._initGraphSelect()
             this._initTimings();
             this._initVertices();
             this._initEdges();
@@ -148,17 +141,6 @@ define([
             };
         },
 
-        _initGraphSelect: function () {
-            this.graphSelect = registry.byId(this.id + "GraphSelect");
-            var context = this;
-            this.graphSelect.onChange = function () {
-                context.graphName = this.getValue();
-                context.loadGraph(context.wu, context.graphName);
-                context.timingGrid.setQuery(context.graphName);
-                context.timingTreeMap.setQuery(context.graphName);
-            }
-        },
-
         _initTimings: function () {
             this.timingGrid = registry.byId(this.id + "TimingsGrid");
 
@@ -178,7 +160,7 @@ define([
                 context.syncSelectionFrom(context.timingTreeMap);
             }
             this.timingTreeMap.onDblClick = function (value) {
-                var mainItem = context.main.getItem(value.subGraphId);
+                var mainItem = context.main.getItem(value.SubGraphId);
                 context.main.centerOnItem(mainItem, true);
             }
         },
@@ -266,10 +248,36 @@ define([
             this._doFind(true);
         },
 
+        _onAbout: function () {
+            myDialog = new Dialog({
+                title: "About HPCC Systems Graph Control",
+                content: "Version:  " + this.main.getVersion() + "<br>"
+                + this.main.getResourceLinks(),
+                style: "width: 320px"
+            });
+            if (has("chrome")) {
+                this.main.hide();
+                this.overview.hide();
+                this.local.hide();
+
+                var context = this;
+                myDialog.connect(myDialog, "hide", function (e) {
+                    context.main.show();
+                    context.overview.show();
+                    context.local.show();
+                });
+            }
+            myDialog.show();
+        },
+
         init: function (params) {
+            if (this.initalized) {
+                return;
+            }
+            this.initalized = true;
             this.graphName = params.GraphName;
             this.wu = new ESPWorkunit({
-                wuid: params.Wuid
+                Wuid: params.Wuid
             });
 
             var firstLoad = true;
@@ -281,7 +289,7 @@ define([
                     onGetGraphs: function (graphs) {
                         if (firstLoad == true) {
                             firstLoad = false;
-                            context.loadGraphSelect(graphs);
+                            context.loadGraph(context.wu, context.graphName);
                         } else {
                             context.refreshGraph(context.wu, context.graphName);
                         }
@@ -289,24 +297,14 @@ define([
                 });
             });
 
-            this.timingGrid.init(params);
-            this.timingGrid.setQuery(this.graphName);
+            this.timingGrid.init(lang.mixin({
+                query: this.graphName
+            }, params));
 
-            this.timingTreeMap.init(params);
-        },
+            this.timingTreeMap.init(lang.mixin({
+                query: this.graphName
+            }, params));
 
-        loadGraphSelect: function (graphs) {
-            this.graphSelect.options = [];
-            for (var i = 0; i < graphs.length; ++i) {
-                if (!this.graphName) {
-                    this.graphName = graphs[i].Name;
-                }
-                this.graphSelect.options.push({
-                    label: graphs[i].Name + (graphs[i].Time ? " (" + graphs[i].Time + ")" : ""),
-                    value: graphs[i].Name
-                });
-            }
-            this.graphSelect.setValue(this.graphName);
         },
 
         loadGraph: function (wu, graphName) {
@@ -465,15 +463,6 @@ define([
             }
         },
 
-        showHelpAbout: function () {
-            myDialog = new Dialog({
-                title: "About Graph sourceControl",
-                content: "Version:  " + main.getVersion(),
-                style: "width: 300px"
-            });
-            myDialog.show();
-        },
-
         resetPage: function () {
             this.main.clear();
         },

+ 52 - 34
esp/files/scripts/GraphWidget.js

@@ -77,6 +77,7 @@ require([
                 this.inherited(arguments);
                 this._isPluginInstalled = this.isPluginInstalled();
                 this.createPlugin();
+                this.watchStyleChange();
             },
 
             resize: function (args) {
@@ -96,6 +97,7 @@ require([
             },
 
             loadXGMML: function (xgmml, merge) {
+                this.registerEvents();
                 if (this.plugin && this.xgmml != xgmml) {
                     this.setMessage("Loading Data...");
                     if (merge)
@@ -109,6 +111,7 @@ require([
             },
 
             mergeXGMML: function (xgmml) {
+                this.registerEvents();
                 if (this.plugin && this.xgmml != xgmml) {
                     this.plugin.mergeXGMML(xgmml);
                     this.xgmml = xgmml;
@@ -116,10 +119,12 @@ require([
             },
 
             loadDOT: function (dot) {
+                this.registerEvents();
                 this.load(dot, "dot");
             },
 
             load: function (dot, layout) {
+                this.registerEvents();
                 if (this.plugin && this.xgmml != xgmml) {
                     this.setMessage("Loading Data...");
                     this.plugin.loadDOT(dot);
@@ -270,21 +275,22 @@ require([
                         }
                         this.plugin = dom.byId(pluginID);
                         var context = this;
-                        setTimeout(function () {
-                            context.registerEvents();
-                        }, 20);
                     } else {
                         domConstruct.create("div", {
                             innerHTML: "<h4>Graph View</h4>" +
                                         "<p>To enable graph views, please install the Graph View Control plugin:</p>" +
-                                        "<a href=\"http://graphcontrol.hpccsystems.com/stable/SetupGraphControl.msi\">Internet Explorer + Firefox (32bit)</a><br>" +
-                                        "<a href=\"http://graphcontrol.hpccsystems.com/stable/SetupGraphControl64.msi\">Internet Explorer + Firefox (64bit)</a><br>" +
-                                        "<a href=\"https://github.com/hpcc-systems/GraphControl\">Linux/Other (sources)</a>"
+                                        this.getResourceLinks()
                         }, this.graphContentPane.domNode);
                     }
                 }
             },
 
+            getResourceLinks: function () {
+                return "<a href=\"http://hpccsystems.com/download/free-community-edition/graph-control\" target=\"_blank\">Binary Installs</a><br>" +
+                "<a href=\"https://github.com/hpcc-systems/GraphControl\" target=\"_blank\">Source Code</a><br><br>" + 
+                "<a href=\"http://hpccsystems.com\" target=\"_blank\">HPCC Systems</a>"
+            },
+
             setMessage: function (message) {
                 if (this.plugin) {
                     return this.plugin.setMessage(message);
@@ -355,6 +361,20 @@ require([
                 return null;
             },
 
+            hide: function () {
+                if (this.plugin) {
+                    dojo.style(this.plugin, "width", "1px");
+                    dojo.style(this.plugin, "height", "1px");
+                }
+            },
+
+            show: function () {
+                if (this.plugin) {
+                    dojo.style(this.plugin, "width", "100%");
+                    dojo.style(this.plugin, "height", "100%");
+                }
+            },
+
             watchSplitter: function (splitter) {
                 if (has("chrome")) {
                     //  Chrome can ignore splitter events
@@ -362,16 +382,10 @@ require([
                 }
                 var context = this;
                 dojo.connect(splitter, "_startDrag", function () {
-                    if (context.plugin) {
-                        dojo.style(context.plugin, "width", "1px");
-                        dojo.style(context.plugin, "height", "1px");
-                    }
+                    context.hide();
                 });
                 dojo.connect(splitter, "_stopDrag", function (evt) {
-                    if (context.plugin) {
-                        dojo.style(context.plugin, "width", "100%");
-                        dojo.style(context.plugin, "height", "100%");
-                    }
+                    context.show();
                 });
             },
 
@@ -380,43 +394,47 @@ require([
                     //  Only chrome needs to monitor select drop downs.
                     var context = this;
                     select.watch("_opened", function () {
-                        if (context.plugin) {
-                            if (select._opened) {
-                                dojo.style(context.plugin, "width", "1px");
-                                dojo.style(context.plugin, "height", "1px");
-                            } else {
-                                dojo.style(context.plugin, "width", "100%");
-                                dojo.style(context.plugin, "height", "100%");
-                            }
+                        if (select._opened) {
+                            context.hide();
+                        } else {
+                            context.show();
                         }
                     });
                 }
             },
 
             watchStyleChange: function () {
+                //  When chrome hides the plugin it destroys it.  To prevent this it is just made very small.  
                 if (has("chrome")) {
+                    var watchList = [];
                     var context = this;
+                    var domNode = this.domNode;
+
+                    //  There are many places that may cause the plugin to be hidden, the possible places are calculated by walking the hierarchy upwards. 
+                    while (domNode) {
+                        if (domNode.id) {
+                            watchList[domNode.id] = false;
+                        }
+                        domNode = domNode.parentElement;
+                    }
+
+                    //  Hijack the dojo style class replacement call and monitor for elements in our watchList. 
                     aspect.around(domClass, "replace", function (origFunc) {
                         return function (node, addStyle, removeStyle) {
-                            if (node.id == context.id) {
+                            if (node.id in watchList) {
                                 if (addStyle == "dijitHidden") {
-                                    context.hiddenBySelf = true;
+                                    watchList[node.id] = true;
                                     dojo.style(node, "width", "1px");
                                     dojo.style(node, "height", "1px");
-                                } else if (addStyle == "dijitVisible" && context.hiddenBySelf) {
-                                    context.hiddenBySelf = false;
+                                    return;
+                                } else if (addStyle == "dijitVisible" && watchList[node.id] == true) {
+                                    watchList[node.id] = false;
                                     dojo.style(node, "width", "100%");
                                     dojo.style(node, "height", "100%");
-                                } else {
-                                    var deferred = origFunc(node, addStyle, removeStyle);
-                                    //  alternative:  return origFunc.apply(this, arguments);
-                                    return deferred;
+                                    return;
                                 }
-                            } else {
-                                var deferred = origFunc(node, addStyle, removeStyle);
-                                //  alternative:  return origFunc.apply(this, arguments);
-                                return deferred;
                             }
+                            return origFunc(node, addStyle, removeStyle);
                         }
                     });
                 }

+ 123 - 0
esp/files/scripts/GraphsWidget.js

@@ -0,0 +1,123 @@
+/*##############################################################################
+#    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/dom",
+
+    "dijit/layout/_LayoutWidget",
+    "dijit/_TemplatedMixin",
+    "dijit/_WidgetsInTemplateMixin",
+    "dijit/registry",
+
+    "hpcc/ESPWorkunit",
+    "hpcc/GraphPageWidget",
+
+    "dojo/text!../templates/GraphsWidget.html",
+
+    "dijit/layout/TabContainer"
+], function (declare, lang, dom, 
+                _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, registry,
+                ESPWorkunit, GraphPageWidget,
+                template) {
+    return declare("GraphsWidget", [_LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
+        templateString: template,
+        baseClass: "GraphsWidget",
+
+        //borderContainer: null,
+        tabContainer: null,
+        tabMap: [],
+        selectedTab: null,
+
+        buildRendering: function (args) {
+            this.inherited(arguments);
+        },
+
+        postCreate: function (args) {
+            this.inherited(arguments);
+            this._initControls();
+        },
+
+        startup: function (args) {
+            this.inherited(arguments);
+        },
+
+        resize: function (args) {
+            this.inherited(arguments);
+            this.tabContainer.resize();
+        },
+
+        layout: function (args) {
+            this.inherited(arguments);
+        },
+
+        //  Implementation  ---
+        onErrorClick: function (line, col) {
+        },
+
+        _initControls: function () {
+            var context = this;
+            this.tabContainer = registry.byId(this.id + "TabContainer");
+
+            var context = this;
+            this.tabContainer.watch("selectedChildWidget", function (name, oval, nval) {
+                if (!nval.initalized) {
+                    nval.init(nval.params);
+                }
+                context.selectedTab = nval;
+            });
+        },
+
+        ensurePane: function (id, params) {
+            var retVal = this.tabMap[id];
+            if (!retVal) {
+                if (lang.exists("graph", params)) {
+                    retVal = new GraphPageWidget({
+                        id: id,
+                        Wuid: this.wu.Wuid,
+                        GraphName: params.graph.Name,
+                        title: params.graph.Name
+                    });
+                }
+                this.tabMap[id] = retVal;
+                this.tabContainer.addChild(retVal);
+            }
+        },
+
+        init: function (params) {
+            if (params.Wuid) {
+                this.wu = new ESPWorkunit({
+                    Wuid: params.Wuid
+                });
+                var monitorCount = 4;
+                var context = this;
+                this.wu.monitor(function () {
+                    if (context.wu.isComplete() || ++monitorCount % 5 == 0) {
+                        context.wu.getInfo({
+                            onGetGraphs: function (graphs) {
+                                for (var i = 0; i < graphs.length; ++i) {
+                                    context.ensurePane(context.id + "graph_" + i, {
+                                        graph: graphs[i]
+                                    });
+                                }
+                            }
+                        });
+                    }
+                });
+            }
+        }
+    });
+});

+ 78 - 36
esp/files/scripts/InfoGridWidget.js

@@ -17,29 +17,36 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/array",
-    "dojo/store/Memory",
-    "dojo/data/ObjectStore",
 
     "dijit/registry",
     "dijit/layout/_LayoutWidget",
     "dijit/_TemplatedMixin",
     "dijit/_WidgetsInTemplateMixin",
 
-    "dojox/grid/DataGrid",
+    "dojox/data/AndOrReadStore",
 
     "hpcc/ESPWorkunit",
 
-    "dojo/text!../templates/InfoGridWidget.html"
+    "dojo/text!../templates/InfoGridWidget.html",
+
+    "dijit/layout/BorderContainer",
+    "dijit/layout/ContentPane",
+    "dijit/form/CheckBox",
+    "dojox/grid/DataGrid"
 ],
-    function (declare, array, Memory, ObjectStore,
-            registry, _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin,
-            DataGrid,
+    function (declare, array, 
+            registry, _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, 
+            AndOrReadStore,
             ESPWorkunit,
             template) {
         return declare("InfoGridWidget", [_LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
             templateString: template,
             baseClass: "InfoGridWidget",
+            borderContainer: null,
             infoGrid: null,
+            errorsCheck: null,
+            warningsCheck: null,
+            infoCheck: null,
 
             dataStore: null,
 
@@ -64,21 +71,30 @@ define([
 
             postCreate: function (args) {
                 this.inherited(arguments);
+                this.borderContainer = registry.byId(this.id + "BorderContainer");
                 this.infoGrid = registry.byId(this.id + "InfoGrid");
+                this.errorsCheck = registry.byId(this.id + "Errors");
+                this.warningsCheck = registry.byId(this.id + "Warnings");
+                this.infoCheck = registry.byId(this.id + "Info");
 
                 var context = this;
                 this.infoGrid.setStructure([
                     { name: "Severity", field: "Severity", width: 8, formatter: context.test },
-                    { name: "Source", field: "Source", width: 10 },
+                    { name: "Source", field: "Source", width: 8 },
                     { name: "Code", field: "Code", width: 4 },
-                    { name: "Message", field: "Message", width: "100%" }
+                    { name: "Message", field: "Message", width: "40" },
+                    { name: "Col", field: "Column", width: 3 },
+                    { name: "Line", field: "LineNo", width: 3 },
+                    { name: "FileName", field: "FileName", width: "40" }
                 ]);
-
+                
                 this.infoGrid.on("RowClick", function (evt) {
-                });
-
-                this.infoGrid.on("RowDblClick", function (evt) {
-                });
+                    var idx = evt.rowIndex;
+                    var item = this.getItem(idx);
+                    var line = parseInt(this.store.getValue(item, "LineNo"), 10);
+                    var col = parseInt(this.store.getValue(item, "Column"), 10);
+                    context.onErrorClick(line, col);
+                }, true);
             },
 
             startup: function (args) {
@@ -87,13 +103,28 @@ define([
 
             resize: function (args) {
                 this.inherited(arguments);
-                this.infoGrid.resize();
+                this.borderContainer.resize();
             },
 
             layout: function (args) {
                 this.inherited(arguments);
             },
 
+            onErrorClick: function(line, col) {
+            },
+
+            _onErrors: function (args) {
+                this.refreshFilter();
+            },
+
+            _onWarnings: function (args) {
+                this.refreshFilter();
+            },
+
+            _onInfo: function (args) {
+                this.refreshFilter();
+            },
+
             //  Plugin wrapper  ---
             _onStyleRow: function (row) {
                 var item = this.infoGrid.getItem(row.index);
@@ -109,38 +140,45 @@ define([
                 this.infoGrid.edit.styleRow(row);
             },
 
-            onClick: function (items) {
-            },
-
-            onDblClick: function (item) {
-            },
-
             init: function (params) {
+                if (params.onErrorClick) {
+                    this.onErrorClick = params.onErrorClick;
+                }
+                
                 this.wu = new ESPWorkunit({
-                    wuid: params.Wuid
+                    Wuid: params.Wuid
                 });
 
                 var context = this;
                 this.wu.monitor(function () {
                     context.wu.getInfo({
-                        onGetExceptions: function (exceptions) {
+                        onGetWUExceptions: function (exceptions) {
                             context.loadExceptions(exceptions);
                         }
                     });
                 });
             },
 
-            setQuery: function (graphName) {
-                if (!graphName || graphName == "*") {
-                    this.infoGrid.setQuery({
-                        GraphName: "*"
-                    });
-                } else {
-                    this.infoGrid.setQuery({
-                        GraphName: graphName,
-                        HasSubGraphId: true
-                    });
+            refreshFilter: function (graphName) {
+                var filter = "";
+                if (this.errorsCheck.get("checked")) {
+                    filter = "Severity: 'Error'";
                 }
+                if (this.warningsCheck.get("checked")) {
+                    if (filter.length) {
+                        filter += " OR ";
+                    }
+                    filter += "Severity: 'Warning'";
+                }
+                if (this.infoCheck.get("checked")) {
+                    if (filter.length) {
+                        filter += " OR ";
+                    }
+                    filter += "Severity: 'Info'";
+                }
+                this.infoGrid.setQuery({
+                    complexQuery: filter
+                });
             },
 
             getSelected: function () {
@@ -155,10 +193,14 @@ define([
             },
 
             loadExceptions: function (exceptions) {
-                var memory = new Memory({ data: exceptions });
-                this.store = new ObjectStore({ objectStore: memory });
+                var data = {
+                    'items': exceptions
+                };
+                this.store = new AndOrReadStore({
+                    data: data
+                });
                 this.infoGrid.setStore(this.store);
-                this.setQuery("*");
+                this.refreshFilter();
             }
         });
     });

+ 254 - 0
esp/files/scripts/LFDetailsWidget.js

@@ -0,0 +1,254 @@
+/*##############################################################################
+#	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/dom",
+    "dojo/dom-class",
+
+    "dijit/layout/_LayoutWidget",
+    "dijit/_TemplatedMixin",
+    "dijit/_WidgetsInTemplateMixin",
+    "dijit/layout/BorderContainer",
+    "dijit/layout/TabContainer",
+    "dijit/layout/ContentPane",
+    "dijit/Toolbar",
+    "dijit/TooltipDialog",
+    "dijit/form/SimpleTextarea",
+    "dijit/form/Button",
+    "dijit/TitlePane",
+    "dijit/registry",
+
+    "hpcc/ResultWidget",
+    "hpcc/ECLSourceWidget",
+    "hpcc/FilePartsWidget",
+    "hpcc/WUDetailsWidget",
+    "hpcc/DFUWUDetailsWidget",
+
+    "hpcc/ESPLogicalFile",
+
+    "dojo/text!../templates/LFDetailsWidget.html"
+], function (declare, lang, dom, domClass, 
+                _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, BorderContainer, TabContainer, ContentPane, Toolbar, TooltipDialog, SimpleTextarea, Button, TitlePane, registry,
+                ResultWidget, EclSourceWidget, FilePartsWidget, WUDetailsWidget, DFUWUDetailsWidget,
+                ESPLogicalFile,
+                template) {
+    return declare("LFDetailsWidget", [_LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
+        templateString: template,
+        baseClass: "LFDetailsWidget",
+        borderContainer: null,
+        tabContainer: null,
+        resultWidget: null,
+        resultWidgetLoaded: false,
+        sourceWidget: null,
+        sourceWidgetLoaded: false,
+        defWidget: null,
+        defWidgetLoaded: false,
+        xmlWidget: null,
+        xmlWidgetLoaded: false,
+        filePartsWidget: null,
+        filePartsWidgetLoaded: false,
+        workunitWidget: null,
+        workunitWidgetLoaded: false,
+        dfuWorkunitWidget: null,
+        dfuWorkunitWidgetLoaded: false,
+        legacyPane: null,
+        legacyPaneLoaded: false,
+
+        logicalFile: null,
+        prevState: "",
+        initiated: false,
+
+        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.resultWidget = registry.byId(this.id + "Content");
+            this.sourceWidget = registry.byId(this.id + "Source");
+            this.defWidget = registry.byId(this.id + "DEF");
+            this.xmlWidget = registry.byId(this.id + "XML");
+            this.filePartsWidget = registry.byId(this.id + "FileParts");
+            this.workunitWidget = registry.byId(this.id + "Workunit");
+            this.dfuWorkunitWidget = registry.byId(this.id + "DFUWorkunit");
+            this.legacyPane = registry.byId(this.id + "Legacy");
+
+            var context = this;
+            this.tabContainer.watch("selectedChildWidget", function (name, oval, nval) {
+                if (nval.id == context.id + "Content" && !context.resultWidgetLoaded) {
+                    context.resultWidgetLoaded = true;
+                    context.resultWidget.init({
+                        result: context.logicalFile.result
+                    });
+                } else if (nval.id == context.id + "Source" && !context.sourceWidgetLoaded) {
+                    context.sourceWidgetLoaded = true;
+                    context.sourceWidget.init({
+                        ECL: context.logicalFile.DFUInfoResponse.Ecl
+                    });
+                } else if (nval.id == context.id + "DEF" && !context.defWidgetLoaded) {
+                    context.logicalFile.fetchDEF(function (response) {
+                        context.defWidgetLoaded = true;
+                        context.defWidget.init({
+                            ECL: response
+                        });
+                    });
+                } else if (nval.id == context.id + "XML" && !context.xmlWidgetLoaded) {
+                    context.logicalFile.fetchXML(function (response) {
+                        context.xmlWidgetLoaded = true;
+                        context.xmlWidget.init({
+                            ECL: response
+                        });
+                    });
+                } else if (nval.id == context.id + "FileParts" && !context.filePartsWidgetLoaded) {
+                    context.filePartsWidgetLoaded = true;
+                    context.filePartsWidget.init({
+                        fileParts: lang.exists("logicalFile.DFUInfoResponse.DFUFileParts.DFUPart", context) ? context.logicalFile.DFUInfoResponse.DFUFileParts.DFUPart : []
+                    });
+                } else if (nval.id == context.id + "Workunit" && !context.workunitWidgetLoaded) {
+                    context.workunitWidgetLoaded = true;
+                    context.workunitWidget.init({
+                        Wuid: context.logicalFile.DFUInfoResponse.Wuid
+                    });
+                } else if (nval.id == context.id + "DFUWorkunit" && !context.workunitWidgetLoaded) {
+                    context.dfuWorkunitWidgetLoaded = true;
+                    context.dfuWorkunitWidget.init({
+                        Wuid: context.logicalFile.DFUInfoResponse.Wuid
+                    });
+                } 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,
+                        style: "border: 0; width: 100%; height: 100%"
+                    }));
+                }
+            });
+        },
+
+        startup: function (args) {
+            this.inherited(arguments);
+        },
+
+        resize: function (args) {
+            this.inherited(arguments);
+            this.borderContainer.resize();
+        },
+
+        layout: function (args) {
+            this.inherited(arguments);
+        },
+
+        //  Hitched actions  ---
+        _onSave: function (event) {
+            var context = this;
+            this.logicalFile.save(dom.byId(context.id + "Description").value, {
+                onGetAll: function (response) {
+                    context.refreshFileDetails(response);
+                }
+            });
+        },
+        _onRename: function (event) {
+            var context = this;
+            this.logicalFile.rename(dom.byId(this.id + "LogicalFileName2").innerHTML, {
+                onGetAll: function (response) {
+                    context.refreshFileDetails(response);
+                }
+            });
+        },
+        _onDelete: function (event) {
+            this.logicalFile.doDelete({
+                load: function (response) {
+                    //TODO
+                }
+            });
+        },
+        _onCopy: function (event) {
+            this.logicalFile.copy({
+                load: function (response) {
+                    //TODO
+                }
+            });
+        },
+        _onDespray: function (event) {
+            var context = this;
+            this.logicalFile.despray({
+                load: function (response) {
+                }
+            });
+        },
+
+        //  Implementation  ---
+        init: function (params) {
+            if (!this.initiated) {
+                this.initiated = true;
+                if (params.Name) {
+                    dom.byId(this.id + "LogicalFileName").innerHTML = params.Name;
+                    //dom.byId(this.id + "LogicalFileName2").value = params.Name;
+                    this.logicalFile = new ESPLogicalFile({
+                        cluster: params.Cluster,
+                        logicalName: params.Name
+                    });
+                    this.refreshPage();
+                }
+            }
+        },
+
+        showMessage: function (msg) {
+        },
+
+        /*isComplete: function () {
+            return true;
+        },*/
+
+        refreshPage: function () {
+            var context = this;
+            this.logicalFile.getInfo({
+                onGetAll: function (response) {
+                    context.refreshFileDetails(response);
+                }
+            });
+        },
+        refreshFileDetails: function (fileDetails) {
+            if (fileDetails.Wuid && fileDetails.Wuid[0] == "D" && this.workunitWidget) {
+                this.tabContainer.removeChild(this.workunitWidget);
+                this.workunitWidget.destroyRecursive();
+                this.workunitWidget = null;
+            } else if (this.dfuWorkunitWidget) {
+                this.tabContainer.removeChild(this.dfuWorkunitWidget);
+                this.dfuWorkunitWidget.destroyRecursive();
+                this.dfuWorkunitWidget = null;
+            }
+            registry.byId(this.id + "Summary").set("title", fileDetails.Filename);
+            //registry.byId(this.id + "Summary").set("iconClass", "iconRefresh");
+            //domClass.remove(this.id + "Test");
+            //domClass.add(this.id + "Test", "iconRefresh");
+            dom.byId(this.id + "Owner").innerHTML = fileDetails.Owner;
+            dom.byId(this.id + "Description").value = fileDetails.Description;
+            dom.byId(this.id + "JobName").innerHTML = fileDetails.JobName;
+            dom.byId(this.id + "Wuid").innerHTML = fileDetails.Wuid;
+            dom.byId(this.id + "Modification").innerHTML = fileDetails.Modified + " (UTC/GMT)";
+            dom.byId(this.id + "Directory").innerHTML = fileDetails.Dir;
+            dom.byId(this.id + "RecordSize").innerHTML = fileDetails.RecordSize;
+            dom.byId(this.id + "Count").innerHTML = fileDetails.RecordCount;
+            this.resultWidget.set("title", "Content " + "(" + fileDetails.RecordCount + ")");
+            dom.byId(this.id + "Filesize").innerHTML = fileDetails.Filesize;
+            dom.byId(this.id + "Pathmask").innerHTML = fileDetails.PathMask;
+        }
+
+    });
+});

+ 13 - 5
esp/files/scripts/LogsWidget.js

@@ -105,18 +105,21 @@ define([
                             var parts = selection[i].Orig.Name.split("/");
                             if (parts.length) {
                                 var leaf = parts[parts.length - 1];
-                                params = "/WUFile/" + leaf + "?Wuid=" + this.wu.wuid + "&Name=" + selection[i].Orig.Name + "&Type=" + selection[i].Orig.Type;
+                                params = "/WUFile/" + leaf + "?Wuid=" + this.wu.Wuid + "&Name=" + selection[i].Orig.Name + "&Type=" + selection[i].Orig.Type;
                             }
                             break;
                         case "res":
-                            params = "/WUFile/res.txt?Wuid=" + this.wu.wuid + "&Type=" + selection[i].Orig.Type;
+                            params = "/WUFile/res.txt?Wuid=" + this.wu.Wuid + "&Type=" + selection[i].Orig.Type;
                             break;
                         case "ThorLog":
                         case "EclAgentLog":
-                            params = "/WUFile/" + selection[i].Type + "?Wuid=" + this.wu.wuid + "&Process=" + selection[i].Orig.Description + "&Type=" + selection[i].Orig.Type;
+                            params = "/WUFile/" + selection[i].Type + "?Wuid=" + this.wu.Wuid + "&Process=" + selection[i].Orig.Description + "&Type=" + selection[i].Orig.Type;
                             break;
                         case "ThorSlaveLog":
-                            params = "/WUFile?Wuid=" + this.wu.wuid + "&Process=" + selection[i].Orig.ProcessName + "&ClusterGroup=" + selection[i].Orig.ProcessName + "&LogDate=" + selection[i].Orig.LogDate + "&SlaveNumber=" + selection[i].Orig.SlaveNumber + "&Type=" + selection[i].Type;
+                            params = "/WUFile?Wuid=" + this.wu.Wuid + "&Process=" + selection[i].Orig.ProcessName + "&ClusterGroup=" + selection[i].Orig.ProcessName + "&LogDate=" + selection[i].Orig.LogDate + "&SlaveNumber=" + selection[i].Orig.SlaveNumber + "&Type=" + selection[i].Type;
+                            break;
+                        case "Archive Query":
+                            params = "/WUFile/ArchiveQuery?Wuid=" + this.wu.Wuid + "&Name=ArchiveQuery&Type=ArchiveQuery";
                             break;
                     }
 
@@ -137,7 +140,7 @@ define([
             //  Plugin wrapper  ---
             init: function (params) {
                 this.wu = new ESPWorkunit({
-                    wuid: params.Wuid
+                    Wuid: params.Wuid
                 });
 
                 var context = this;
@@ -145,6 +148,11 @@ define([
                     context.wu.getInfo({
                         onGetAll: function (response) {
                             context.logData = [];
+                            if (response.HasArchiveQuery) {
+                                context.logData.push({
+                                    Type: "Archive Query"
+                                });
+                            }
                             if (response.Helpers && response.Helpers.ECLHelpFile) {
                                 context.loadHelpers(response.Helpers.ECLHelpFile);
                             }

+ 150 - 0
esp/files/scripts/ResultWidget.js

@@ -0,0 +1,150 @@
+/*##############################################################################
+#    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/dom",
+    "dojo/request/iframe",
+
+    "dijit/layout/_LayoutWidget",
+    "dijit/_TemplatedMixin",
+    "dijit/_WidgetsInTemplateMixin",
+    "dijit/registry",
+
+    "dojox/grid/enhanced/plugins/Pagination",
+
+    "hpcc/ESPBase",
+
+    "dojo/text!../templates/ResultWidget.html",
+
+    "dijit/layout/BorderContainer",
+    "dijit/Toolbar",
+    "dijit/form/Button",
+    "dijit/ToolbarSeparator",
+    "dojox/grid/EnhancedGrid"
+], function (declare, lang, dom, iframe,
+                _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, registry,
+                Pagination,
+                ESPBase,
+                template) {
+    return declare("ResultWidget", [_LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
+        templateString: template,
+        baseClass: "ResultWidget",
+
+        borderContainer: null,
+        grid: null,
+
+        initalized: false,
+        loaded: false,
+
+        buildRendering: function (args) {
+            this.inherited(arguments);
+        },
+
+        postCreate: function (args) {
+            this.inherited(arguments);
+            this.borderContainer = registry.byId(this.id + "BorderContainer");
+            this.grid = registry.byId(this.id + "Grid");
+        },
+
+        startup: function (args) {
+            this.inherited(arguments);
+        },
+
+        resize: function (args) {
+            this.inherited(arguments);
+            this.borderContainer.resize();
+        },
+
+        layout: function (args) {
+            this.inherited(arguments);
+        },
+
+        destroy: function (args) {
+            this.inherited(arguments);
+        },
+
+        _doDownload: function (type) {
+            //TODO Fix
+            var base = new ESPBase();
+            if (lang.exists("result.Sequence", this)) {
+                var sequence = this.result.Sequence;
+                var downloadPdfIframeName = "downloadIframe_" + sequence;
+                var frame = iframe.create(downloadPdfIframeName);
+                var url = base.getBaseURL() + "/WUResultBin?Format=" + type + "&Wuid=" + this.result.Wuid + "&Sequence=" + sequence;
+                iframe.setSrc(frame, url, true);
+            } else if (lang.exists("result.Name", this)) {
+                var logicalName = this.result.Name;
+                var downloadPdfIframeName = "downloadIframe_" + logicalName;
+                var frame = iframe.create(downloadPdfIframeName);
+                var url = base.getBaseURL() + "/WUResultBin?Format=" + type + "&Wuid=" + this.result.Wuid + "&LogicalName=" + logicalName;
+                iframe.setSrc(frame, url, true);
+            }
+        },
+
+        _onDownloadZip: function (args) {
+            this._doDownload("zip");
+        },
+
+        _onDownloadGZip: function (args) {
+            this._doDownload("gzip");
+        },
+
+        _onDownloadXLS: function (args) {
+            this._doDownload("xls");
+        },
+
+        _onFileDetails: function (args) {
+            alert("todo");
+        },
+
+        //  Implementation  ---
+        onErrorClick: function (line, col) {
+        },
+
+        init: function (params) {
+            if (this.initalized) {
+                return;
+            }
+            this.initalized = true;
+            this.result = params.result;
+            //TODO:  Encapsulate this IF into ESPResult.js
+            if (params.result && params.result.canShowResults()) {
+                this.grid.setStructure(params.result.getStructure());
+                this.grid.setStore(params.result.getObjectStore());
+                this.refresh();
+            } else {
+                this.grid.setStructure([
+                            {
+                                name: "##", width: "6"
+                            }
+                ]);
+                this.grid.showMessage("[undefined]");
+            }
+        },
+
+        refresh: function () {
+            if (this.result && !this.result.isComplete()) {
+                this.grid.showMessage(this.result.getLoadingMessage());
+            } else if (!this.loaded) {
+                this.loaded = true;
+                this.grid.setQuery({
+                    id: "*"
+                });
+            }
+        }
+    });
+});

+ 0 - 206
esp/files/scripts/ResultsControl.js

@@ -1,206 +0,0 @@
-/*##############################################################################
-#    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/store/Memory",
-    "dojo/data/ObjectStore",
-
-    "dijit/registry",
-    "dijit/layout/ContentPane",
-
-    "dojox/grid/DataGrid",
-    "dojox/grid/EnhancedGrid",
-    "dojox/grid/enhanced/plugins/Pagination",
-    "dojox/grid/enhanced/plugins/Filter",
-    "dojox/grid/enhanced/plugins/NestedSorting"
-
-], function (declare, Memory, ObjectStore,
-    registry, ContentPane,
-    DataGrid, EnhancedGrid, Pagination, Filter, NestedSorting) {
-    return declare(null, {
-        workunit: null,
-        paneNum: 0,
-        id: "",
-        dataGridSheet: {},
-        resultIdStoreMap: [],
-        resultIdGridMap: [],
-        delayLoad: [],
-        selectedResult: null,
-
-        //  Callbacks
-        onErrorClick: function (line, col) {
-        },
-
-        // The constructor    
-        constructor: function (args) {
-            declare.safeMixin(this, args);
-
-            this.dataGridSheet = registry.byId(this.id);
-            var context = this;
-            this.dataGridSheet.watch("selectedChildWidget", function (name, oval, nval) {
-                if (nval.id in context.delayLoad) {
-                    context.selectedResult = context.delayLoad[nval.id].result;
-                    if (!context.selectedResult.isComplete()) {
-                        context.delayLoad[nval.id].loadingMessage = context.getLoadingMessage();
-                    }
-                    context.delayLoad[nval.id].placeAt(nval.containerNode, "last");
-                    context.delayLoad[nval.id].startup();
-                    nval.resize();
-                    delete context.delayLoad[nval.id];
-                }
-            });
-        },
-
-        clear: function () {
-            this.delayLoad = [];
-            this.resultIdStoreMap = [];
-            this.resultIdGridMap = [];
-            var tabs = this.dataGridSheet.getChildren();
-            for (var i = 0; i < tabs.length; ++i) {
-                this.dataGridSheet.removeChild(tabs[i]);
-            }
-        },
-
-        getNextPaneID: function () {
-            return this.id + "Pane_" + ++this.paneNum;
-        },
-
-        addTab: function (label, paneID) {
-            if (paneID == null) {
-                paneID = this.getNextPaneID();
-            }
-            var pane = new ContentPane({
-                title: label,
-                id: paneID,
-                style: {
-                    overflow: "hidden",
-                    padding: 0
-                }
-            });
-            this.dataGridSheet.addChild(pane);
-            return pane;
-        },
-
-        addResultTab: function (result) {
-            var paneID = this.getNextPaneID();
-
-            var grid = EnhancedGrid({
-                result: result,
-                store: result.getObjectStore(),
-                query: { id: "*" },
-                structure: result.getStructure(),
-                canSort: function (col) {
-                    return false;
-                },
-                plugins: {
-                    pagination: {
-                        pageSizes: [25, 50, 100, "All"],
-                        defaultPageSize: 50,
-                        description: true,
-                        sizeSwitch: true,
-                        pageStepper: true,
-                        gotoButton: true,
-                        maxPageStep: 4,
-                        position: "bottom"
-                    }
-                }
-            });
-            this.delayLoad[paneID] = grid;
-            this.resultIdStoreMap[result.getID()] = result.store;
-            this.resultIdGridMap[result.getID()] = grid;
-            return this.addTab(result.getName(), paneID);
-        },
-
-        refresh: function (wu) {
-            if (this.workunit != wu) {
-                this.clear();
-                this.workunit = wu;
-            }
-            this.addExceptionTab(this.workunit.exceptions);
-            this.addResultsTab(this.workunit.results);
-        },
-
-        refreshSourceFiles: function (wu) {
-            if (this.workunit != wu) {
-                this.clear();
-                this.workunit = wu;
-            }
-            this.addResultsTab(this.workunit.sourceFiles);
-        },
-
-        addResultsTab: function (results) {
-            for (var i = 0; i < results.length; ++i) {
-                var result = results[i];
-                if (result.getID() in this.resultIdStoreMap) {
-                    this.resultIdStoreMap[result.getID()].isComplete = result.isComplete();
-                } else {
-                    pane = this.addResultTab(result);
-                    if (this.sequence != null && this.sequence == result.getID()) {
-                        this.dataGridSheet.selectChild(pane);
-                    } else if (this.name != null && this.name == result.getID()) {
-                        this.dataGridSheet.selectChild(pane);
-                    }
-                }
-                if (!result.isComplete()) {
-                    this.resultIdGridMap[result.getID()].showMessage(this.getLoadingMessage());
-                }
-            }
-        },
-
-        getLoadingMessage: function () {
-            return "<span class=\'dojoxGridWating\'>[" + this.workunit.state + "]</span>";
-        },
-
-        addExceptionTab: function (exceptions) {
-            var hasErrorWarning = false;
-            for (var i = 0; i < exceptions.length; ++i) {
-                if (exceptions[i].Severity == "Error" || exceptions[i].Severity == "Warning") {
-                    hasErrorWarning = true;
-                    break;
-                }
-            }
-
-            if (hasErrorWarning) {
-                var resultNode = this.addTab("Error/Warning(s)");
-                store = new Memory({ data: exceptions });
-                dataStore = new ObjectStore({ objectStore: store });
-
-                grid = new DataGrid({
-                    store: dataStore,
-                    query: { id: "*" },
-                    structure: [
-                        { name: "Severity", field: "Severity" },
-                        { name: "Line", field: "LineNo" },
-                        { name: "Column", field: "Column" },
-                        { name: "Code", field: "Code" },
-                        { name: "Message", field: "Message", width: "auto" }
-                    ]
-                });
-                grid.placeAt(resultNode.containerNode, "last");
-                grid.startup();
-
-                var context = this;
-                grid.on("RowClick", function (evt) {
-                    var idx = evt.rowIndex;
-                    var item = this.getItem(idx);
-                    var line = parseInt(this.store.getValue(item, "LineNo"), 10);
-                    var col = parseInt(this.store.getValue(item, "Column"), 10);
-                    context.onErrorClick(line, col);
-                }, true);
-            }
-        }
-    });
-});

+ 92 - 69
esp/files/scripts/ResultsWidget.js

@@ -16,31 +16,30 @@
 define([
     "dojo/_base/declare",
     "dojo/_base/lang",
-    "dojo/_base/xhr",
     "dojo/dom",
-    "dojo/request/iframe",
 
     "dijit/layout/_LayoutWidget",
     "dijit/_TemplatedMixin",
     "dijit/_WidgetsInTemplateMixin",
-    "dijit/layout/TabContainer",
     "dijit/registry",
 
-    "hpcc/ESPBase",
     "hpcc/ESPWorkunit",
-    "hpcc/ResultsControl",
-    "dojo/text!../templates/ResultsWidget.html"
-], function (declare, lang, xhr, dom, iframe,
-                _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, TabContainer, registry,
-                ESPBase, ESPWorkunit, ResultsControl,
+
+    "dojo/text!../templates/ResultsWidget.html",
+
+    "dijit/layout/TabContainer"
+], function (declare, lang, dom, 
+                _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, registry,
+                ESPWorkunit, 
                 template) {
     return declare("ResultsWidget", [_LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
         templateString: template,
         baseClass: "ResultsWidget",
 
-        borderContainer: null,
-        resultsPane: null,
-        resultsControl: null,
+        //borderContainer: null,
+        tabContainer: null,
+        tabMap: [],
+        selectedTab: null,
 
         buildRendering: function (args) {
             this.inherited(arguments);
@@ -57,85 +56,100 @@ define([
 
         resize: function (args) {
             this.inherited(arguments);
-            this.borderContainer.resize();
+            //this.borderContainer.resize();
+            this.tabContainer.resize();
         },
 
         layout: function (args) {
             this.inherited(arguments);
         },
 
-        _doDownload: function (type) {
-            if (lang.exists("resultsControl.selectedResult.Sequence", this)) {
-                var sequence = this.resultsControl.selectedResult.Sequence;
-                var downloadPdfIframeName = "downloadIframe_" + sequence;
-                var frame = iframe.create(downloadPdfIframeName);
-                var url = this.wu.getBaseURL() + "/WUResultBin?Format=" + type + "&Wuid=" + this.wu.wuid + "&Sequence=" + sequence;
-                iframe.setSrc(frame, url, true);
-            } else if (lang.exists("resultsControl.selectedResult.Name", this)) {
-                var logicalName = this.resultsControl.selectedResult.Name;
-                var downloadPdfIframeName = "downloadIframe_" + logicalName;
-                var frame = iframe.create(downloadPdfIframeName);
-                var url = this.wu.getBaseURL() + "/WUResultBin?Format=" + type + "&Wuid=" + this.wu.wuid + "&LogicalName=" + logicalName;
-                iframe.setSrc(frame, url, true);
-            }
-        },
-
-        _onDownloadZip: function (args) {
-            this._doDownload("zip");
-        },
-
-        _onDownloadGZip: function (args) {
-            this._doDownload("gzip");
-        },
-
-        _onDownloadXLS: function (args) {
-            this._doDownload("xls");
-        },
-
-        _onFileDetails: function (args) {
-            alert("todo");
-        },
-
         //  Implementation  ---
         onErrorClick: function (line, col) {
         },
 
         _initControls: function () {
             var context = this;
-            this.borderContainer = registry.byId(this.id + "BorderContainer");
-            this.resultsPane = registry.byId(this.id + "ResultsPane");
+            //this.borderContainer = registry.byId(this.id + "BorderContainer");
+            this.tabContainer = registry.byId(this.id + "TabContainer");
 
             var context = this;
-            this.resultsControl = new ResultsControl({
-                id: this.id + "ResultsPane",
-                sequence: 0,
-                onErrorClick: function (line, col) {
-                    context.onErrorClick(line, col);
+            this.tabContainer.watch("selectedChildWidget", function (name, oval, nval) {
+                if (!nval.initalized) {
+                    nval.init(nval.params);
                 }
+                context.selectedTab = nval;
             });
         },
 
+        ensurePane: function (id, params) {
+            var retVal = this.tabMap[id];
+            if (!retVal) {
+                if (lang.exists("Name", params) && lang.exists("Cluster", params)) {
+                    retVal = new LFDetailsWidget({
+                        id: id,
+                        title: params.Name,
+                        params: params
+                    });
+                } else if (lang.exists("Wuid", params) && lang.exists("exceptions", params)) {
+                    retVal = new InfoGridWidget({
+                        id: id,
+                        title: "Errors/Warnings",
+                        params: params
+                    });
+                } else if (lang.exists("result", params)) {
+                    retVal = new ResultWidget({
+                        id: id,
+                        title: params.result.Name,
+                        params: params
+                    });
+                }
+                this.tabMap[id] = retVal;
+                this.tabContainer.addChild(retVal);
+            }
+        },
+
         init: function (params) {
             if (params.Wuid) {
                 this.wu = new ESPWorkunit({
-                    wuid: params.Wuid
+                    Wuid: params.Wuid
                 });
                 var monitorCount = 4;
                 var context = this;
                 this.wu.monitor(function () {
                     if (context.wu.isComplete() || ++monitorCount % 5 == 0) {
-                        if (params.SourceFiles) {
-                            context.wu.getInfo({
-                                onGetSourceFiles: function (sourceFiles) {
-                                    context.refreshSourceFiles(context.wu);
+                        context.wu.getInfo({
+                            onGetWUExceptions: function (exceptions) {
+                                if (params.ShowErrors && exceptions.length) {
+                                    context.ensurePane(context.id + "exceptions", {
+                                        Wuid: params.Wuid,
+                                        onErrorClick: context.onErrorClick,
+                                        exceptions: exceptions
+                                    });
+                                }
+                            },
+                            onGetSourceFiles: function (sourceFiles) {
+                                if (params.SourceFiles) {
+                                    for (var i = 0; i < sourceFiles.length; ++i) {
+                                        context.ensurePane(context.id + "logicalFile_" + i, {
+                                            Name: sourceFiles[i].Name,
+                                            Cluster: sourceFiles[i].FileCluster
+                                        });
+                                    }
                                 }
-                            });
-                        } else {
-                            context.wu.getInfo({
-                                onGetResults: function (results) {
-                                    context.refresh(context.wu);
+                            },
+                            onGetResults: function (results) {
+                                if (!params.SourceFiles) {
+                                    for (var i = 0; i < results.length; ++i) {
+                                        context.ensurePane(context.id + "result_" + i, {
+                                            result: results[i]
+                                        });
+                                    }
                                 }
-                            });
+                            }
+                        });
+                        if (context.selectedTab) {
+                            context.selectedTab.refresh();
                         }
                     }
                 });
@@ -143,15 +157,24 @@ define([
         },
 
         clear: function () {
-            this.resultsControl.clear();
+            var tabs = this.tabContainer.getChildren();
+            for (var i = 0; i < tabs.length; ++i) {
+                this.tabContainer.removeChild(tabs[i]);
+                tabs[i].destroyRecursive();
+            }
+            this.tabMap = [];
+            this.selectedTab = null;
         },
 
         refresh: function (wu) {
-            this.resultsControl.refresh(wu);
-        },
-
-        refreshSourceFiles: function (wu) {
-            this.resultsControl.refreshSourceFiles(wu);
+            if (this.workunit != wu) {
+                this.clear();
+                this.workunit = wu;
+                this.init({
+                    Wuid: wu.Wuid,
+                    ShowErrors: true
+                });
+            }
         }
     });
 });

+ 6 - 0
esp/files/scripts/TargetSelectWidget.js

@@ -56,6 +56,12 @@ require([
             this.targetSelectControl.onChange = function () {
                 context.onChange(this.get("value"));
             };
+        },
+
+        init: function (params) {
+            if (params.Target) {
+                this._value = params.Target;
+            }
             this.loadTargets();
         },
 

+ 13 - 6
esp/files/scripts/TimingGridWidget.js

@@ -25,15 +25,14 @@ define([
     "dijit/_TemplatedMixin",
     "dijit/_WidgetsInTemplateMixin",
 
-    "dojox/grid/DataGrid",
-
     "hpcc/ESPWorkunit",
 
-    "dojo/text!../templates/TimingGridWidget.html"
+    "dojo/text!../templates/TimingGridWidget.html",
+
+    "dojox/grid/DataGrid"
 ],
     function (declare, array, Memory, ObjectStore,
             registry, _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin,
-            DataGrid,
             ESPWorkunit,
             template) {
         return declare("TimingGridWidget", [_LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
@@ -52,6 +51,10 @@ define([
             postCreate: function (args) {
                 this.inherited(arguments);
                 this.timingGrid = registry.byId(this.id + "TimingGrid");
+                this.timingGrid.setStructure([
+                    { name: "Component", field: "Name", width: "auto" },
+                    { name: "Time (Seconds)", field: "Seconds", width: "auto" }
+                ]);
 
                 var context = this;
                 this.timingGrid.on("RowClick", function (evt) {
@@ -86,8 +89,12 @@ define([
             },
 
             init: function (params) {
+                this.defaultQuery = "*";
+                if (params.query) {
+                    this.defaultQuery = params.query;
+                }
                 this.wu = new ESPWorkunit({
-                    wuid: params.Wuid
+                    Wuid: params.Wuid
                 });
 
                 var context = this;
@@ -128,7 +135,7 @@ define([
                 var store = new Memory({ data: timers });
                 var dataStore = new ObjectStore({ objectStore: store });
                 this.timingGrid.setStore(dataStore);
-                this.setQuery("*");
+                this.setQuery(this.defaultQuery);
             }
         });
     });

+ 30 - 1
esp/files/scripts/TimingPageWidget.js

@@ -65,9 +65,38 @@ define([
 
             //  Plugin wrapper  ---
             init: function (params) {
+                var context = this;
                 this.timingGrid.init(params);
+                this.timingGrid.onClick = function (items) {
+                    context.syncSelectionFrom(context.timingGrid);
+                };
+
                 this.timingTreeMap.init(params);
-            }
+                this.timingTreeMap.onClick = function (value) {
+                    context.syncSelectionFrom(context.timingTreeMap);
+                }
+            },
 
+            syncSelectionFrom: function (sourceControl) {
+                var selItems = [];
+
+                //  Get Selected Items  ---
+                if (sourceControl == this.timingGrid || sourceControl == this.timingTreeMap) {
+                    var items = sourceControl.getSelected();
+                    for (var i = 0; i < items.length; ++i) {
+                        if (items[i].SubGraphId) {
+                            selItems.push(items[i].SubGraphId);
+                        }
+                    }
+                }
+
+                //  Set Selected Items  ---
+                if (sourceControl != this.timingGrid) {
+                    this.timingGrid.setSelected(selItems);
+                }
+                if (sourceControl != this.timingTreeMap) {
+                    this.timingTreeMap.setSelected(selItems);
+                }
+            }
         });
     });

+ 37 - 37
esp/files/scripts/TimingTreeMapWidget.js

@@ -16,13 +16,13 @@
 ############################################################################## */
 define([
     "dojo/_base/declare",
+    "dojo/_base/lang",
     "dojo/store/Memory",
 
     "dijit/registry",
     "dijit/layout/_LayoutWidget",
     "dijit/_TemplatedMixin",
     "dijit/_WidgetsInTemplateMixin",
-    "dijit/layout/ContentPane",
 
     "dojox/treemap/TreeMap",
 
@@ -30,20 +30,17 @@ define([
 
     "dojo/text!../templates/TimingTreeMapWidget.html"
 ],
-    function (declare, Memory,
-            registry, _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, ContentPane,
+    function (declare, lang, Memory,
+            registry, _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, 
             TreeMap,
             ESPWorkunit,
             template) {
         return declare("TimingTreeMapWidget", [_LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
             templateString: template,
             baseClass: "TimingTreeMapWidget",
-            contentPane: null,
             treeMap: null,
 
-            dataStore: null,
-
-            lastSelection: null,
+            store: null,
 
             buildRendering: function (args) {
                 this.inherited(arguments);
@@ -51,18 +48,14 @@ define([
 
             postCreate: function (args) {
                 this.inherited(arguments);
-                this.contentPane = registry.byId(this.id + "ContentPane");
                 this.treeMap = registry.byId(this.id + "TreeMap");
 
                 var context = this;
-                this.treeMap.on("change", function (e) {
-                    context.lastSelection = e.newValue;
-                });
                 this.treeMap.on("click", function (evt) {
-                    context.onClick(context.lastSelection);
+                    context.onClick(context.treeMap.selectedItems);
                 });
                 this.treeMap.on("dblclick", function (evt) {
-                    context.onDblClick(context.lastSelection);
+                    context.onDblClick(context.treeMap.selectedItem);
                 });
             },
 
@@ -72,7 +65,8 @@ define([
 
             resize: function (args) {
                 this.inherited(arguments);
-                this.contentPane.resize();
+                this.treeMap._dataChanged = true;
+                this.treeMap.resize(args);
             },
 
             layout: function (args) {
@@ -87,14 +81,19 @@ define([
             },
 
             init: function (params) {
+                this.defaultQuery = "*";
+                if (params.query) {
+                    this.defaultQuery = params.query;
+                }
+
                 var context = this;
                 if (params.Wuid) {
                     this.wu = new ESPWorkunit({
-                        wuid: params.Wuid
+                        Wuid: params.Wuid
                     });
                     this.wu.fetchTimers(function (timers) {
                         context.timers = timers;
-                        context.loadTimers(timers, "*");
+                        context.loadTimers(timers, context.defaultQuery);
                     });
                 }
             },
@@ -104,13 +103,20 @@ define([
             },
 
             getSelected: function () {
-                return [{
-                    SubGraphId: this.lastSelection.subGraphId
-                }];
+                return this.treeMap.selectedItems;
             },
 
             setSelected: function (selItems) {
-                //  TODO:  Not sure this possible...
+                if (this.store) {
+                    var selectedItems = [];
+                    for (var i = 0; i < selItems.length; ++i) {
+                        var item = this.store.get(selItems[i]);
+                        if (item) {
+                            selectedItems.push(item);
+                        }
+                    }
+                    this.treeMap.set("selectedItems", selectedItems);
+                }
             },
 
             loadTimers: function (timers, query) {
@@ -119,40 +125,34 @@ define([
                 if (timers) {
                     for (var i = 0; i < timers.length; ++i) {
                         if (timers[i].GraphName && timers[i].SubGraphId && (query == "*" || query == timers[i].GraphName)) {
-                            var value = timers[i].Seconds;
-                            timerData.push({
-                                graphName: timers[i].GraphName,
-                                subGraphId: timers[i].SubGraphId,
-                                label: timers[i].Name,
-                                value: value
-                            });
-                            if (this.largestValue < value * 1000) {
-                                this.largestValue = value * 1000;
+                            timerData.push(timers[i]);
+                            if (this.largestValue < timers[i].Seconds * 1000) {
+                                this.largestValue = timers[i].Seconds * 1000;
                             }
                         }
                     }
                 }
-                var dataStore = new Memory({
-                    idProperty: "sequenceNumber",
+                this.store = new Memory({
+                    idProperty: "SubGraphId",
                     data: timerData
                 });
 
                 var context = this;
+                this.treeMap.set("store", this.store);
+                this.treeMap.set("areaAttr", "Seconds");
                 this.treeMap.set("colorFunc", function (item) {
-                    var redness = 255 * (item.value * 1000 / context.largestValue);
+                    var redness = Math.floor(255 * (item.Seconds * 1000 / context.largestValue));
                     return {
                         r: 255,
                         g: 255 - redness,
                         b: 255 - redness
                     };
                 });
-                this.treeMap.set("areaAttr", "value");
+                this.treeMap.set("groupAttrs", ["GraphName"]);
+                this.treeMap.set("labelAttr", "Name");
                 this.treeMap.set("tooltipFunc", function (item) {
-                    return item.label + " " + item.value;
+                    return item.Name + " " + item.Seconds;
                 });
-                this.treeMap.set("groupAttrs", ["graphName"]);
-
-                this.treeMap.set("store", dataStore);
             }
         });
     });

+ 66 - 49
esp/files/scripts/WUDetailsWidget.js

@@ -15,37 +15,38 @@
 ############################################################################## */
 define([
     "dojo/_base/declare",
-    "dojo/_base/xhr",
     "dojo/dom",
+    "dojo/dom-class",
     "dojo/store/Memory",
     "dojo/data/ObjectStore",
 
     "dijit/layout/_LayoutWidget",
     "dijit/_TemplatedMixin",
     "dijit/_WidgetsInTemplateMixin",
-    "dijit/layout/BorderContainer",
-    "dijit/layout/TabContainer",
-    "dijit/layout/ContentPane",
-    "dijit/Toolbar",
-    "dijit/TooltipDialog",
-    "dijit/form/Textarea",
-    "dijit/form/Button",
-    "dijit/TitlePane",
     "dijit/registry",
 
     "hpcc/ECLSourceWidget",
     "hpcc/TargetSelectWidget",
     "hpcc/SampleSelectWidget",
-    "hpcc/GraphWidget",
+    "hpcc/GraphsWidget",
     "hpcc/ResultsWidget",
     "hpcc/InfoGridWidget",
     "hpcc/LogsWidget",
     "hpcc/ESPWorkunit",
 
-    "dojo/text!../templates/WUDetailsWidget.html"
-], function (declare, xhr, dom, Memory, ObjectStore,
-                _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, BorderContainer, TabContainer, ContentPane, Toolbar, TooltipDialog, Textarea, Button, TitlePane, registry,
-                EclSourceWidget, TargetSelectWidget, SampleSelectWidget, GraphWidget, ResultsWidget, InfoGridWidget, LogsWidget, Workunit,
+    "dojo/text!../templates/WUDetailsWidget.html",
+
+    "dijit/layout/BorderContainer",
+    "dijit/layout/TabContainer",
+    "dijit/layout/ContentPane",
+    "dijit/form/Textarea",
+    "dijit/form/Button",
+    "dijit/Toolbar",
+    "dijit/TooltipDialog",
+    "dijit/TitlePane"
+], function (declare, dom, domClass, Memory, ObjectStore,
+                _LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin, registry,
+                EclSourceWidget, TargetSelectWidget, SampleSelectWidget, GraphsWidget, ResultsWidget, InfoGridWidget, LogsWidget, Workunit,
                 template) {
     return declare("WUDetailsWidget", [_LayoutWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
         templateString: template,
@@ -68,6 +69,8 @@ define([
         playgroundWidgetLoaded: false,
         xmlWidget: null,
         xmlWidgetLoaded: false,
+        legacyPane: null,
+        legacyPaneLoaded: false,
 
         wu: null,
         prevState: "",
@@ -89,49 +92,58 @@ define([
             this.playgroundWidget = registry.byId(this.id + "Playground");
             this.xmlWidget = registry.byId(this.id + "XML");
             this.infoGridWidget = registry.byId(this.id + "InfoContainer");
+            this.legacyPane = registry.byId(this.id + "Legacy");
+
             var context = this;
             this.tabContainer.watch("selectedChildWidget", function (name, oval, nval) {
                 if (nval.id == context.id + "Results" && !context.resultsWidgetLoaded) {
                     context.resultsWidgetLoaded = true;
                     context.resultsWidget.init({
-                        Wuid: context.wu.wuid
+                        Wuid: context.wu.Wuid
                     });
                 } else if (nval.id == context.id + "Files" && !context.filesWidgetLoaded) {
                     context.filesWidgetLoaded = true;
                     context.filesWidget.init({
-                        Wuid: context.wu.wuid,
+                        Wuid: context.wu.Wuid,
                         SourceFiles: true
                     });
                 } else if (nval.id == context.id + "Timers" && !context.timersWidgetLoaded) {
                     context.timersWidgetLoaded = true;
                     context.timersWidget.init({
-                        Wuid: context.wu.wuid
+                        Wuid: context.wu.Wuid
                     });
                 } else if (nval.id == context.id + "Graphs" && !context.graphsWidgetLoaded) {
                     context.graphsWidgetLoaded = true;
                     context.graphsWidget.init({
-                        Wuid: context.wu.wuid
+                        Wuid: context.wu.Wuid
                     });
                 } else if (nval.id == context.id + "Source" && !context.sourceWidgetLoaded) {
                     context.sourceWidgetLoaded = true;
                     context.sourceWidget.init({
-                        Wuid: context.wu.wuid
+                        Wuid: context.wu.Wuid
                     });
                 } else if (nval.id == context.id + "Logs" && !context.logsWidgetLoaded) {
                     context.logsWidgetLoaded = true;
                     context.logsWidget.init({
-                        Wuid: context.wu.wuid
+                        Wuid: context.wu.Wuid
                     });
                 } else if (nval.id == context.id + "Playground" && !context.playgroundWidgetLoaded) {
                     context.playgroundWidgetLoaded = true;
                     context.playgroundWidget.init({
-                        Wuid: context.wu.wuid
+                        Wuid: context.wu.Wuid,
+                        Target: context.wu.WUInfoResponse.Cluster
                     });
                 } else if (nval.id == context.id + "XML" && !context.xmlWidgetLoaded) {
                     context.xmlWidgetLoaded = true;
                     context.xmlWidget.init({
-                        Wuid: context.wu.wuid
+                        Wuid: context.wu.Wuid
                     });
+                } else if (nval.id == context.id + "Legacy" && !context.legacyPaneLoaded) {
+                    context.legacyPaneLoaded = true;
+                    context.legacyPane.set("content", dojo.create("iframe", {
+                        src: "/WsWorkunits/WUInfo?Wuid=" + context.wu.Wuid + "&IncludeExceptions=0&IncludeGraphs=0&IncludeSourceFiles=0&IncludeResults=0&IncludeVariables=0&IncludeTimers=0&IncludeDebugValues=0&IncludeApplicationValues=0&IncludeWorkflows&SuppressResultSchemas=1",
+                        style: "border: 0; width: 100%; height: 100%"
+                    }));
                 }
             });
         },
@@ -151,11 +163,11 @@ define([
 
         //  Hitched actions  ---
         _onSave: function (event) {
-            var protectedCheckbox = registry.byId("showProtected");
+            var protectedCheckbox = registry.byId(this.id + "Protected");
             var context = this;
             this.wu.update({
-                Description: dom.byId("showDescription").value,
-                Jobname: dom.byId("showJobName").value,
+                Description: dom.byId(context.id + "Description").value,
+                Jobname: dom.byId(context.id + "JobName").value,
                 Protected: protectedCheckbox.get("value")
             }, null, {
                 load: function (response) {
@@ -205,16 +217,17 @@ define([
             });
         },
         _onPublish: function (event) {
-            this.wu.publish(dom.byId("showJobName2").value);
+            this.wu.publish(dom.byId(this.id + "JobName2").value);
         },
 
         //  Implementation  ---
         init: function (params) {
             if (params.Wuid) {
+                registry.byId(this.id + "Summary").set("title", params.Wuid);
+
                 dom.byId(this.id + "Wuid").innerHTML = params.Wuid;
-                dom.byId(this.id + "Wuid2").innerHTML = params.Wuid;
                 this.wu = new Workunit({
-                    wuid: params.Wuid
+                    Wuid: params.Wuid
                 });
                 this.monitor();
             }
@@ -225,7 +238,7 @@ define([
             var prevState = "";
             var context = this;
             this.wu.monitor(function (workunit) {
-                context.monitorEclPlayground(workunit);
+                context.monitorWorkunit(workunit);
             });
         },
 
@@ -250,7 +263,7 @@ define([
             return text;
         },
 
-        monitorEclPlayground: function (response) {
+        monitorWorkunit: function (response) {
             registry.byId(this.id + "Save").set("disabled", !this.wu.isComplete());
             //registry.byId(this.id + "Reload").set("disabled", this.wu.isComplete());
             registry.byId(this.id + "Clone").set("disabled", !this.wu.isComplete());
@@ -259,22 +272,22 @@ define([
             registry.byId(this.id + "Resubmit").set("disabled", !this.wu.isComplete());
             registry.byId(this.id + "Restart").set("disabled", !this.wu.isComplete());
             registry.byId(this.id + "Publish").set("disabled", !this.wu.isComplete());
+            
+            registry.byId(this.id + "JobName").set("readOnly", !this.wu.isComplete());
+            registry.byId(this.id + "Description").set("readOnly", !this.wu.isComplete());
+            registry.byId(this.id + "Protected").set("readOnly", !this.wu.isComplete());
 
-            registry.byId("showJobName").set("readOnly", !this.wu.isComplete());
-            registry.byId("showDescription").set("readOnly", !this.wu.isComplete());
-            registry.byId("showProtected").set("readOnly", !this.wu.isComplete());
+            registry.byId(this.id + "Summary").set("iconClass",this.wu.getStateIconClass());
+            domClass.remove(this.id + "StateIdImage");
+            domClass.add(this.id + "StateIdImage", this.wu.getStateIconClass());
 
-            dom.byId("showStateIdImage").src = this.wu.getStateImage();
-            dom.byId("showStateIdImage").title = response.State;
-            dom.byId("showStateIdImage2").src = this.wu.getStateImage();
-            dom.byId("showStateIdImage2").title = response.State;
-            dom.byId("showProtectedImage").src = this.wu.getProtectedImage();
-            dom.byId("showProtectedImage2").src = this.wu.getProtectedImage();
-            dom.byId("showState").innerHTML = response.State;
-            dom.byId("showOwner").innerHTML = response.Owner;
-            dom.byId("showJobName").value = response.Jobname;
-            dom.byId("showJobName2").value = response.Jobname;
-            dom.byId("showCluster").innerHTML = response.Cluster;
+            //dom.byId(this.id + "StateIdImage").title = response.State;
+            dom.byId(this.id + "ProtectedImage").src = this.wu.getProtectedImage();
+            dom.byId(this.id + "State").innerHTML = response.State;
+            dom.byId(this.id + "Owner").innerHTML = response.Owner;
+            dom.byId(this.id + "JobName").value = response.Jobname;
+            dom.byId(this.id + "JobName2").value = response.Jobname;
+            dom.byId(this.id + "Cluster").innerHTML = response.Cluster;
 
             var context = this;
             if (this.wu.isComplete() || this.prevState != response.State) {
@@ -327,7 +340,7 @@ define([
                             if (response[i].GraphName)
                                 continue;
                             if (response[i].Name == "Process")
-                                dom.byId("showTime").innerHTML = response[i].Value;
+                                dom.byId(context.id + "Time").innerHTML = response[i].Value;
                             if (tooltip != "")
                                 tooltip += "\n";
                             tooltip += response[i].Name;
@@ -358,12 +371,16 @@ define([
                         if (response.ThorLogList && response.ThorLogList.ThorLogInfo) {
                             helpersCount += response.ThorLogList.ThorLogInfo.length;
                         }
+                        if (response.HasArchiveQuery) {
+                            helpersCount += 1;
+                        }
+
                         context.logsWidget.set("title", "Helpers " + "(" + helpersCount + ")");
                         //dom.byId(context.id + "WUInfoResponse").innerHTML = context.objectToText(response);
-                        dom.byId("showDescription").value = response.Description;
-                        dom.byId("showAction").innerHTML = response.ActionEx;
-                        dom.byId("showScope").innerHTML = response.Scope;
-                        var protectedCheckbox = registry.byId("showProtected");
+                        dom.byId(context.id + "Description").value = response.Description;
+                        dom.byId(context.id + "Action").innerHTML = response.ActionEx;
+                        dom.byId(context.id + "Scope").innerHTML = response.Scope;
+                        var protectedCheckbox = registry.byId(context.id + "Protected");
                         protectedCheckbox.set("value", response.Protected);
                     }
                 });

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

@@ -0,0 +1,114 @@
+/*##############################################################################
+#    Copyright (C) 2011 HPCC Systems.
+#
+#    All rights reserved. This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    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/>.
+############################################################################## */
+define([
+	"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",
+
+		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);
+			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 context = this;
+			var parsedResults = results.then(function (domXml) {
+				data = context.getValues(domXml, "DFULogicalFile");
+				data.total = context.getValue(domXml, "NumFiles");
+				return data;
+			});
+
+			lang.mixin(parsedResults, {
+				total: Deferred.when(parsedResults, function (data) {
+					return data.total;
+				})
+			});
+	
+			return QueryResults(parsedResults);
+		}
+	});
+
+	var DFUFileView = declare(ESPBase, {
+		idProperty: "Wuid",
+
+		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);
+			request['rawxml_'] = "1";
+
+			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;
+			});
+
+			lang.mixin(parsedResults, {
+				total: Deferred.when(parsedResults, function (data) {
+					return data ? data.length : 0;
+				})
+			});
+	
+			return QueryResults(parsedResults);
+		}
+	});
+
+	return {
+		DFUQuery: DFUQuery,
+		DFUFileView: DFUFileView
+	};
+});
+

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

@@ -0,0 +1,114 @@
+/*##############################################################################
+#    Copyright (C) 2011 HPCC Systems.
+#
+#    All rights reserved. This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    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/>.
+############################################################################## */
+define([
+	"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 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);
+			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("FileSpray") + "/GetDFUWorkunits",
+				handleAs: "xml",
+				content: request
+			});
+
+			var context = this;
+			var parsedResults = results.then(function (domXml) {
+				data = context.getValues(domXml, "DFUWorkunit");
+				data.total = context.getValue(domXml, "NumWUs");
+				return data;
+			});
+
+			lang.mixin(parsedResults, {
+				total: Deferred.when(parsedResults, function (data) {
+					return data.total;
+				})
+			});
+
+			return QueryResults(parsedResults);
+		}
+	});
+
+	var FileList = declare(ESPBase, {
+		idProperty: "name",
+
+		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);
+			request['rawxml_'] = "1";
+
+			var results = xhr.get({
+				url: this.getBaseURL("FileSpray") + "/FileList",
+				handleAs: "xml",
+				content: request
+			});
+
+			var context = this;
+			var parsedResults = results.then(function (domXml) {
+				var debug = context.flattenXml(domXml);
+				var data = context.getValues(domXml, "PhysicalFileStruct");
+				return data;
+			});
+
+			lang.mixin(parsedResults, {
+				total: Deferred.when(parsedResults, function (data) {
+					return data.length;
+				})
+			});
+
+			return QueryResults(parsedResults);
+		}
+	});
+
+	return {
+		GetDFUWorkunits: GetDFUWorkunits,
+		FileList: FileList
+	};
+});

+ 69 - 0
esp/files/scripts/WsTopology.js

@@ -0,0 +1,69 @@
+/*##############################################################################
+#    Copyright (C) 2011 HPCC Systems.
+#
+#    All rights reserved. This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    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/>.
+############################################################################## */
+define([
+	"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 TpServiceQuery =  declare(ESPBase, {
+		idProperty: "Wuid",
+
+		constructor: function (options) {
+			declare.safeMixin(this, options);
+		},
+
+		getIdentity: function (object) {
+			return object[this.idProperty];
+		},
+
+		query: function (query, options) {
+			var request = {
+					Type: "ALLSERVICES"
+			};
+			lang.mixin(request, options.query);
+			request['rawxml_'] = "1";
+
+			var results = xhr.get({
+				url: this.getBaseURL("WsTopology") + "/TpServiceQuery",
+				handleAs: "xml",
+				content: request
+			});
+
+			var context = this;
+			var parsedResults = results.then(function (domXml) {
+				var data = context.getValues(domXml, "TpDropZone", ["TpMachine"]);
+				return data;
+			});
+
+			lang.mixin(parsedResults, {
+				total: Deferred.when(parsedResults, function (data) {
+					return data.length;
+				})
+			});
+	
+			return QueryResults(parsedResults);
+		}
+	});
+
+
+	return {
+		TpServiceQuery: TpServiceQuery
+	};
+});

+ 4 - 3
esp/files/scripts/WsWorkunits.js

@@ -87,10 +87,11 @@ define([
             if (this.isComplete == true) {
                 var request = {};
                 request['Wuid'] = this.wuid;
-                if (this.sequence != null) {
-                    request['Sequence'] = this.sequence;
-                } else {
+                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;

+ 4 - 2
esp/files/stub.js

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

+ 1 - 0
esp/files/templates/CMakeLists.txt

@@ -19,6 +19,7 @@ set ( TEMPLATES_FILES
     ${CMAKE_CURRENT_SOURCE_DIR}/GraphPageWidget.html
     ${CMAKE_CURRENT_SOURCE_DIR}/GraphWidget.html
     ${CMAKE_CURRENT_SOURCE_DIR}/InfoGridWidget.html
+    ${CMAKE_CURRENT_SOURCE_DIR}/LFDetailsWidget.html
     ${CMAKE_CURRENT_SOURCE_DIR}/LogsWidget.html
     ${CMAKE_CURRENT_SOURCE_DIR}/ResultsWidget.html
     ${CMAKE_CURRENT_SOURCE_DIR}/SampleSelectWidget.html

+ 83 - 0
esp/files/templates/DFUSearchWidget.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}ContentPane" data-dojo-props="region: 'center', tabPosition: 'top'" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.ContentPane">
+            <div style="width: 100%; height: 100%" data-dojo-type="dijit.layout.BorderContainer">
+                <div data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">                	                    
+                    <form>
+                    	<ul>
+                    		<li>
+		                    	<h2>Open DFU Workunit</h2>
+			                    <label for="WorkUnitId" class="Prompt">Workunit ID:</label>
+			                    <div><input name="FindDfuWu" type="text" data-dojo-type="dijit/form/TextBox" placeholder="enter workunit id"
+			                    data-dojo-props="trim:true, propercase:true"/>
+								</div>
+							</li>
+							<li>
+								<div>
+							<button data-dojo-type="dijit/form/Button" type="button">Load Below
+			                </button>
+			                	</div>
+			                </li>
+						</ul>	
+						<ul>
+							<li>			
+						<h2>Search DFU Workunits</h2>
+						<label for="Type" class="Prompt">Type:</label>
+						<div>
+							<select name="SelectType" data-dojo-type="dijit/form/Select">
+    							<option value="NA">Non&ndash;Archived Workunits</option>
+    							<option value="A" selected="Selected">Archived Workunits</option>    
+							</select>
+						</div>
+						</li>
+						<li>
+						<label for="Username" class="Prompt">Username:</label>
+						<div>
+							<input id="Username" data-dojo-type="dijit/form/TextBox" placeholder="enter username"
+                                data-dojo-props="trim:true, propercase:true">
+                        </div>
+                        </li>
+                        <li>
+                        <label for="Cluster" class="Prompt">Cluster:</label>
+                        <div>
+                        	<select name="SelectCluster" data-dojo-type="TargetSelectWidget">    								  
+							</select>
+						</div>
+						</li>
+						<li>
+						<label for="State" class="Prompt">State:</label>
+						<div>
+							<select name="SelectState" data-dojo-type="dijit/form/Select">
+	                            	<option>unknown</option>
+									<option>scheduled</option>
+									<option>compiled</option>
+									<option>running</option>
+									<option>finished</option>
+									<option>failed</option>
+									<option>aborting</option>
+									<option>aborted</option>
+									<option>blocked</option>
+									<option>monitoring</option>
+							</select>
+						</div>
+					</li>
+					<li>
+						<label for="Jobname" class="Prompt">Jobname:</label>
+						<div>
+							<input id="FindJobName" data-dojo-type="dijit/form/TextBox" placeholder="enter jobname"
+                                data-dojo-props="trim:true, propercase:true">
+                        </div>
+                    </li>
+                     <li>
+                        <div>
+                        	<button data-dojo-type="dijit/form/Button" type="button">Search
+                            </button>
+                        </div>
+                       </li>
+					</form>
+				</div>
+             	<div id="${id}InfoContainer" style="height: 35%" data-dojo-props="region: 'bottom', splitter: true, minSize: 120" data-dojo-type="InfoGridWidget">  </div>
+     		
+        </div>
+	</div>
+</div>

+ 138 - 0
esp/files/templates/DFUWUDetailsWidget.html

@@ -0,0 +1,138 @@
+<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}Summary" style="width: 100%; height: 100%" data-dojo-props='title:"Summary", iconClass:"iconWorkunit"' 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}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 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>
+                            <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>  
+                    </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>
+
+        </div>
+    </div>
+</div>

+ 1 - 1
esp/files/templates/ECLPlaygroundWidget.html

@@ -13,7 +13,7 @@
         </div>
         <div id="${id}Graphs" style="width: 240px;" data-dojo-props="minSize:120, region: 'right', splitter:true" data-dojo-type="GraphWidget">
         </div>
-        <div id="${id}Results" style="height: 240px; border-style: none; border-width: 0px" data-dojo-props="minSize:120, region: 'bottom', splitter:true" data-dojo-type="ResultsWidget">
+        <div id="${id}Results" style="height: 240px;" data-dojo-props="minSize:120, region: 'bottom', splitter:true" data-dojo-type="ResultsWidget">
         </div>
         <div id="${id}SubmitPane" class="edgePanel" data-dojo-props="region: 'bottom'" data-dojo-type="dijit.layout.ContentPane">
             <div style="display: inline-block; vertical-align: middle">

+ 2 - 2
esp/files/templates/ECLSourceWidget.html

@@ -1,7 +1,7 @@
 <div class="${baseClass}">
-    <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%; padding: 0px; overflow: hidden" data-dojo-props="splitter: false, gutters:false" data-dojo-type="dijit.layout.BorderContainer">
+    <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%; overflow: hidden" data-dojo-props="splitter: false" data-dojo-type="dijit.layout.BorderContainer">
         <div id="${id}EclContent" class="centerPanel" data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">
-            <textarea id="${id}EclCode">.</textarea>
+            <textarea id="${id}EclCode">...Loading...</textarea>
         </div>
     </div>
 </div>

+ 4 - 0
esp/files/templates/FilePartsWidget.html

@@ -0,0 +1,4 @@
+<div class="${baseClass}">
+    <div id="${id}FilePartsGrid" style="width: 100%; height: 100%" data-dojo-type="dojox.grid.DataGrid">
+    </div>
+</div>

+ 2 - 3
esp/files/templates/GraphPageWidget.html

@@ -1,15 +1,14 @@
 <div class="${baseClass}">
     <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.BorderContainer">
         <div id="${id}MainGraphWidget" data-dojo-props="region: 'center'" data-dojo-type="GraphWidget">
-            <div id="${id}GraphSelect" data-dojo-type="dijit.form.Select">
-            </div>
-            <span data-dojo-type="dijit.ToolbarSeparator"></span>
             <div id="${id}FindField" style="width: 120px" data-dojo-props="placeHolder:'find'" data-dojo-type="dijit.form.TextBox">Find</div>
             <div id="${id}Find" data-dojo-attach-event="onClick:_onFind" data-dojo-type="dijit.form.Button">F</div>
             <div id="${id}Previous" data-dojo-attach-event="onClick:_onFindPrevious" data-dojo-type="dijit.form.Button">&lt;</div>
             <div id="${id}Next" data-dojo-attach-event="onClick:_onFindNext" data-dojo-type="dijit.form.Button">&gt;</div>
             <span data-dojo-type="dijit.ToolbarSeparator"></span>
             <div id="${id}Layout" data-dojo-attach-event="onClick:_onLayout" data-dojo-type="dijit.form.Button">Layout</div>
+            <span data-dojo-type="dijit.ToolbarSeparator"></span>
+            <div id="${id}About" data-dojo-attach-event="onClick:_onAbout" data-dojo-type="dijit.form.Button">About</div>
         </div>
         <div id="${id}RightBorderContainer" style="width: 33%; padding: 0px; overflow: hidden" data-dojo-props="region: 'right', splitter:true, minSize: 120" data-dojo-type="dijit.layout.BorderContainer">
             <div id="${id}OverviewTabContainer" data-dojo-props="region: 'center', tabPosition: 'bottom'" data-dojo-type="dijit.layout.TabContainer">

+ 4 - 0
esp/files/templates/GraphsWidget.html

@@ -0,0 +1,4 @@
+<div class="${baseClass}">
+    <div id="${id}TabContainer" style="width: 100%; height: 100%" data-dojo-props="tabPosition: 'bottom'" data-dojo-type="dijit.layout.TabContainer">
+    </div>
+</div>

+ 13 - 1
esp/files/templates/InfoGridWidget.html

@@ -1,4 +1,16 @@
 <div class="${baseClass}">
-    <div id="${id}InfoGrid" style="width: 100%; height: 100%" data-dojo-type="dojox.grid.DataGrid">
+    <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.BorderContainer">
+        <div id="${id}InfoGrid" data-dojo-props="region: 'center'" data-dojo-type="dojox.grid.DataGrid">
+        </div>
+        <div id="${id}Filter" class="edgePanel" data-dojo-props="region: 'bottom'" data-dojo-type="dijit.layout.ContentPane">
+            <input id="${id}Errors" data-dojo-attach-event="onClick:_onErrors" data-dojo-props="checked: true" data-dojo-type="dijit.form.CheckBox" />
+            <label for="${id}Errors">Errors</label>
+            &nbsp;
+            <input id="${id}Warnings" data-dojo-attach-event="onClick:_onWarnings" data-dojo-props="checked: true" data-dojo-type="dijit.form.CheckBox" />
+            <label for="${id}Warnings">Warnings</label>
+            &nbsp;
+            <input id="${id}Info" data-dojo-attach-event="onClick:_onInfo" data-dojo-props="checked: true" data-dojo-type="dijit.form.CheckBox" />
+            <label for="${id}Info">Info</label>
+        </div>
     </div>
 </div>

+ 84 - 0
esp/files/templates/LFDetailsWidget.html

@@ -0,0 +1,84 @@
+<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}Summary" style="width: 100%; height: 100%" data-dojo-props='title:"Summary", iconClass:"iconLogicalFile"' 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}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}Clone" data-dojo-attach-event="onClick:_onCopy" data-dojo-type="dijit.form.Button">Copy</div>
+                    <div id="${id}Restart" data-dojo-attach-event="onClick:_onDespray" data-dojo-type="dijit.form.Button">Despray</div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                </div>
+                <div data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">
+                    <h2>
+                        <img class="iconAlign" src="img/folder_table.png" />&nbsp<span id="${id}LogicalFileName" class="bold">LogicalFileName</span>
+                    </h2>
+                    <form>
+                        <ul>
+                            <li> 
+                                <label for="${id}Wuid">Workunit: </label>
+                                <div id="${id}Wuid"></div>
+                            </li>
+                            <li> 
+                                <label for="Owner">Owner: </label>
+                                <div id="${id}Owner"></div>
+                            </li>
+                            <li> 
+                                <label for="Description">Description: </label>
+                                <div>
+                                    <input id="${id}Description" data-dojo-props="trim:true" data-dojo-type="dijit.form.SimpleTextarea" cols="55"
+                                    rows="4"/>
+                                </div>
+                            </li>                           
+                            <li>
+                                <label for="Job Name">Job Name:</label>
+                                <div id="${id}JobName"></div>                         
+                            </li>
+                            <li>
+                                <label for="Filesize">Filesize:</label>
+                                <div id="${id}Filesize"></div>                         
+                            </li>
+                            <li>
+                                <label for="Modification">Modification:</label>
+                                <div id="${id}Modification"></div>                         
+                            </li>
+                            <li>
+                                <label for="Directory">Directory:</label>
+                                <div id="${id}Directory"></div>                         
+                            </li>
+                            <li>
+                                <label for="Pathmask">Pathmask:</label>
+                                <div id="${id}Pathmask"></div>                         
+                            </li>
+                            <li>
+                                <label for="Record Size">Record Size:</label>
+                                <div id="${id}RecordSize"></div>                         
+                            </li>
+                            <li>
+                                <label for="Record Count">Record Count:</label>
+                                <div id="${id}Count"></div>                         
+                            </li> 
+                        </ul>
+                    </form>                                   
+                </div>
+            </div>
+            <div id="${id}Content" title="Contents" data-dojo-type="ResultWidget">
+            </div>
+            <div id="${id}Source" title="ECL" data-dojo-type="ECLSourceWidget">
+            </div>
+            <div id="${id}DEF" title="DEF" data-dojo-type="ECLSourceWidget">
+            </div>
+            <div id="${id}XML" title="XML" data-dojo-props="WUXml: true" data-dojo-type="ECLSourceWidget">
+            </div>
+            <div id="${id}FileParts" title="File Parts" data-dojo-type="FilePartsWidget">
+            </div>
+            <div id="${id}Workunit" title="Workunit" data-dojo-type="WUDetailsWidget">
+            </div>
+            <div id="${id}DFUWorkunit" title="Workunit" data-dojo-type="DFUWUDetailsWidget">
+            </div>
+            <div id="${id}Legacy" title="Legacy Web Page" data-dojo-type="dijit.layout.ContentPane">
+            </div>
+        </div>
+    </div>
+</div>

+ 13 - 0
esp/files/templates/ResultWidget.html

@@ -0,0 +1,13 @@
+<div class="${baseClass}">
+    <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%" data-dojo-props="splitter: false" data-dojo-type="dijit.layout.BorderContainer">
+        <div id="${id}Toolbar" class="topPanel" style="padding: 0px; overflow: hidden" data-dojo-props="region: 'top'" data-dojo-type="dijit.Toolbar">
+            <span class="bold">Download:</span>
+            <div data-dojo-attach-event="onClick:_onDownloadZip" data-dojo-type="dijit.form.Button">Zip</div>
+            <div data-dojo-attach-event="onClick:_onDownloadGZip" data-dojo-type="dijit.form.Button">GZip</div>
+            <div data-dojo-attach-event="onClick:_onDownloadXLS" data-dojo-type="dijit.form.Button">XLS</div>
+            <span data-dojo-type="dijit.ToolbarSeparator"></span>
+        </div>
+        <div id="${id}Grid" 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', } }" data-dojo-type="dojox.grid.EnhancedGrid">
+        </div>
+    </div>
+</div>

+ 1 - 11
esp/files/templates/ResultsWidget.html

@@ -1,14 +1,4 @@
 <div class="${baseClass}">
-    <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%" data-dojo-props="splitter: false" data-dojo-type="dijit.layout.BorderContainer">
-        <div id="${id}Toolbar" class="topPanel" style="padding: 0px; overflow: hidden" data-dojo-props="region: 'top'" data-dojo-type="dijit.Toolbar">
-            <span class="bold">Download:</span>
-            <div data-dojo-attach-event="onClick:_onDownloadZip" data-dojo-type="dijit.form.Button">Zip</div>
-            <div data-dojo-attach-event="onClick:_onDownloadGZip" data-dojo-type="dijit.form.Button">GZip</div>
-            <div data-dojo-attach-event="onClick:_onDownloadXLS" data-dojo-type="dijit.form.Button">XLS</div>
-            <span data-dojo-type="dijit.ToolbarSeparator"></span>
-            <div data-dojo-attach-event="onClick:_onFileDetails" data-dojo-type="dijit.form.Button">File Details</div>
-        </div>
-        <div id="${id}ResultsPane" style="padding: 0px; overflow: hidden" data-dojo-props="region: 'center', tabPosition: 'bottom'" data-dojo-type="dijit.layout.TabContainer">
-        </div>
+    <div id="${id}TabContainer" style="width: 100%; height: 100%" data-dojo-props="tabPosition: 'bottom'" data-dojo-type="dijit.layout.TabContainer">
     </div>
 </div>

+ 2 - 8
esp/files/templates/TimingGridWidget.html

@@ -1,10 +1,4 @@
 <div class="${baseClass}">
-    <table id="${id}TimingGrid" title="Timings" style="width: 100%; height: 100%" data-dojo-type="dojox.grid.DataGrid">
-        <thead>
-            <tr>
-                <th field="Name" width="auto">Component</th>
-                <th field="Seconds" width="auto">Time (Seconds)</th>
-            </tr>
-        </thead>
-    </table>
+    <div id="${id}TimingGrid" title="Timings" style="width: 100%; height: 100%" data-dojo-type="dojox.grid.DataGrid">
+    </div>
 </div>

+ 2 - 4
esp/files/templates/TimingTreeMapWidget.html

@@ -1,6 +1,4 @@
 <div class="${baseClass}">
-    <div id="${id}ContentPane" style="width: 100%; height: 100%; padding: 0px; overflow: hidden" data-dojo-type="dijit.layout.ContentPane">
-        <link rel="stylesheet" href="dojox/treemap/themes/TreeMap.css">
-        <div id="${id}TreeMap" data-dojo-type="dojox.treemap.TreeMap"></div>
-    </div>
+    <link rel="stylesheet" href="dojox/treemap/themes/TreeMap.css">
+    <div id="${id}TreeMap" style="width: 100%; height: 100%;" data-dojo-props="selectionMode: 'multiple'" data-dojo-type="dojox.treemap.TreeMap"></div>
 </div>

+ 69 - 67
esp/files/templates/WUDetailsWidget.html

@@ -1,73 +1,73 @@
 <div class="${baseClass}">
-    <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.BorderContainer">
-        <div id="${id}Toolbar" class="topPanel" data-dojo-props="region: 'top'" data-dojo-type="dijit.Toolbar">
-            <img id="showProtectedImage" class="iconAlign" src="img/unlocked.png"/>&nbsp<img id="showStateIdImage" class="iconAlign" src="img/workunit.png"/>&nbsp<span id="${id}Wuid" class="bold">WUID</span>
-            <span data-dojo-type="dijit.ToolbarSeparator"></span>
-            <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}Clone" data-dojo-attach-event="onClick:_onClone" data-dojo-type="dijit.form.Button">Clone</div>
-            <div id="${id}Resubmit" data-dojo-attach-event="onClick:_onResubmit" data-dojo-type="dijit.form.Button">Resubmit</div>
-            <div id="${id}Restart" data-dojo-attach-event="onClick:_onRestart" data-dojo-type="dijit.form.Button">Restart</div>
-            <span data-dojo-type="dijit.ToolbarSeparator"></span>
-            <div id="${id}Publish" data-dojo-type="dijit.form.DropDownButton">
-                <span>Publish</span>
-                <div data-dojo-type="dijit.TooltipDialog">
-                    <label class="Prompt" for="showJobName2">Job Name:</label>
-                    <input id="showJobName2" data-dojo-props="trim: true" data-dojo-type="dijit.form.TextBox"/>
-                    <button data-dojo-attach-event="onClick:_onPublish" data-dojo-type="dijit.form.Button">Submit</button>
-                </div>
-            </div>
-            <span data-dojo-type="dijit.ToolbarSeparator"></span>
-            <div id="${id}Reload" data-dojo-attach-event="onClick:_onReload" data-dojo-props="iconClass:'iconRefresh'" data-dojo-type="dijit.form.Button">Refresh</div>
-            <span data-dojo-type="dijit.ToolbarSeparator"></span>
-        </div>
+    <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 title="Summary" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.BorderContainer">
-                <div id="${id}Summary" data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">
+            <div id="${id}Summary" style="width: 100%; height: 100%" data-dojo-props='title:"Summary", iconClass:"iconWorkunit"' 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}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}Clone" data-dojo-attach-event="onClick:_onClone" data-dojo-type="dijit.form.Button">Clone</div>
+                    <div id="${id}Resubmit" data-dojo-attach-event="onClick:_onResubmit" data-dojo-type="dijit.form.Button">Resubmit</div>
+                    <div id="${id}Restart" data-dojo-attach-event="onClick:_onRestart" data-dojo-type="dijit.form.Button">Restart</div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                    <div id="${id}Publish" data-dojo-type="dijit.form.DropDownButton">
+                        <span>Publish</span>
+                        <div data-dojo-type="dijit.TooltipDialog">
+                            <label class="Prompt" for="${id}JobName2">Job Name:</label>
+                            <input id="${id}JobName2" data-dojo-props="trim: true" data-dojo-type="dijit.form.TextBox"/>
+                            <button data-dojo-attach-event="onClick:_onPublish" data-dojo-type="dijit.form.Button">Submit</button>
+                        </div>
+                    </div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                    <div id="${id}Reload" data-dojo-attach-event="onClick:_onReload" data-dojo-props="iconClass:'iconRefresh'" data-dojo-type="dijit.form.Button">Refresh</div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                </div>
+                <div data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">
                     <h2>
-                        <img id="showProtectedImage2" class="iconAlign" src="img/locked.png"/>&nbsp<img id="showStateIdImage2" class="iconAlign" src="img/workunit.png"/>&nbsp<span id="${id}Wuid2" class="bold">WUID</span>
+                        <img id="${id}ProtectedImage" src="img/locked.png"/>&nbsp<div id="${id}StateIdImage" class="iconWorkunit" ></div>&nbsp<span id="${id}Wuid" class="bold">WUID</span>
                     </h2>
-                    <table>
-                        <tr>
-                            <td><span class="Prompt">Action: </span></td>
-                            <td id="showAction"></td>
-                        </tr>
-                        <tr>
-                            <td><span class="Prompt">State:</span></td>
-                            <td id="showState"></td>
-                        </tr>
-                        <tr>
-                            <td><span class="Prompt">Owner:</span></td>
-                            <td id="showOwner"></td>
-                        </tr>
-                        <tr>
-                            <td><span class="Prompt">Scope: </span></td>
-                            <td id="showScope"></td>
-                        </tr>
-                        <tr>
-                            <td><span class="Prompt">Job Name:</span></td>
-                            <td><input id="showJobName" style="width: 220px" data-dojo-props="trim:true" data-dojo-type="dijit.form.TextBox"/></td>
-                        </tr>
-                        <tr>
-                            <td><span class="Prompt">Description:</span></td>
-                            <td><input id="showDescription" style="width: 220px" data-dojo-props="trim:true" data-dojo-type="dijit.form.TextBox"/></td>
-                        </tr>
-                        <tr>
-                            <td><span class="Prompt">Protected:</span></td>
-                            <td><input id="showProtected" data-dojo-type="dijit.form.CheckBox"/></td>
-                        </tr>
-                        <tr>
-                            <td><span class="Prompt">Cluster:</span></td>
-                            <td id="showCluster"></td>
-                        </tr>
-                        <tr>
-                            <td><span class="Prompt">Duration:</span></td>
-                            <td id="showTime"></td>
-                        </tr>
-                    </table>
+                    <form>
+                        <ul>
+                            <li> 
+                                <label class="Prompt" for="Action">Action:</label>
+                                <div id="${id}Action"></div>
+                            </li>
+                            <li>
+                                <label class="Prompt" for="State">State:</label>
+                                <div id="${id}State"></div>                         
+                            </li>
+                            <li>
+                                <label class="Prompt" for="Owner">Owner:</label>
+                                <div id="${id}Owner"></div>
+                            </li>
+                            <li>
+                                <label class="Prompt" for="Scope">Scope:</label>  
+                                <div id="${id}Scope"></div>
+                            </li>
+                            <li>
+                                <label class="Prompt" for="JobName">Job Name:</label>
+                                <div><input id="${id}JobName" data-dojo-props="trim:true" data-dojo-type="dijit.form.TextBox"/></div>
+                            </li>
+                            <li>
+                                <label class="Prompt" for="Description">Description:</label>
+                                <div><input id="${id}Description" data-dojo-props="trim:true" data-dojo-type="dijit.form.TextBox"/></div>
+                            </li>
+                            <li>
+                                <label class="Prompt" for="Protected">Protected:</label>
+                                <div><input id="${id}Protected" data-dojo-type="dijit.form.CheckBox"/></div>
+                            </li>
+                            <li>
+                                <label class="Prompt" for="Cluster">Cluster:</label>
+                                <div id="${id}Cluster"></div>
+                            </li>
+                            <li>    
+                                <label class="Prompt" for="Duration">Duration:</label>
+                                <div id="${id}Time"></div>
+                            </li>
+                        </ul>
+                    </form>
                 </div>
                 <div id="${id}InfoContainer" style="height: 33%" data-dojo-props="region: 'bottom', splitter: true, minSize: 120" data-dojo-type="InfoGridWidget">
                 </div>
@@ -82,7 +82,7 @@
             </div>
             <div id="${id}Timers" title="Timings" data-dojo-type="TimingPageWidget">
             </div>
-            <div id="${id}Graphs" title="Graphs" data-dojo-type="GraphPageWidget">
+            <div id="${id}Graphs" title="Graphs" data-dojo-type="GraphsWidget">
             </div>
             <div id="${id}Source" title="ECL" data-dojo-type="ECLSourceWidget">
             </div>
@@ -92,6 +92,8 @@
             </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>
         </div>
     </div>
 </div>