浏览代码

HPCC-8804 New ECL Watch homepage

Add new Activity page.
Add new Search Results page.
Enhance ensureNavLink to allow opening in a new page.
Add links to legacy pages.

Fixes HPCC-8804

Signed-off-by: Gordon Smith <gordon.smith@lexisnexis.com>
Gordon Smith 12 年之前
父节点
当前提交
8beff0da59
共有 49 个文件被更改,包括 1639 次插入63 次删除
  1. 369 5
      esp/files/css/hpcc.css
  2. 二进制
      esp/files/img/FolderSmart.png
  3. 二进制
      esp/files/img/Info.png
  4. 二进制
      esp/files/img/LZFolder.png
  5. 二进制
      esp/files/img/LandingZone.png
  6. 二进制
      esp/files/img/Operations.png
  7. 二进制
      esp/files/img/Targets.png
  8. 二进制
      esp/files/img/WUCog.png
  9. 二进制
      esp/files/img/dfu_icon.png
  10. 二进制
      esp/files/img/ecl_icon.png
  11. 二进制
      esp/files/img/files_icon.png
  12. 二进制
      esp/files/img/help_icon.png
  13. 二进制
      esp/files/img/hpcc_systems_logo.png
  14. 二进制
      esp/files/img/ops_icon.png
  15. 二进制
      esp/files/img/search_icon.png
  16. 二进制
      esp/files/img/user_icon.png
  17. 175 0
      esp/files/scripts/ActivityWidget.js
  18. 1 1
      esp/files/scripts/DFUQueryWidget.js
  19. 2 2
      esp/files/scripts/ESPDFUWorkunit.js
  20. 2 2
      esp/files/scripts/ESPLogicalFile.js
  21. 20 14
      esp/files/scripts/ESPRequest.js
  22. 24 11
      esp/files/scripts/ESPResult.js
  23. 12 0
      esp/files/scripts/ESPUtil.js
  24. 2 2
      esp/files/scripts/ESPWorkunit.js
  25. 2 2
      esp/files/scripts/FileSpray.js
  26. 1 1
      esp/files/scripts/GetDFUWorkunitsWidget.js
  27. 5 0
      esp/files/scripts/GridDetailsWidget.js
  28. 68 0
      esp/files/scripts/HPCCPlatformECLWidget.js
  29. 76 0
      esp/files/scripts/HPCCPlatformFilesWidget.js
  30. 69 0
      esp/files/scripts/HPCCPlatformMainWidget.js
  31. 103 0
      esp/files/scripts/HPCCPlatformOpsWidget.js
  32. 73 0
      esp/files/scripts/HPCCPlatformRoxieWidget.js
  33. 126 0
      esp/files/scripts/HPCCPlatformWidget.js
  34. 0 13
      esp/files/scripts/InfoGridWidget.js
  35. 274 0
      esp/files/scripts/SearchResultsWidget.js
  36. 1 1
      esp/files/scripts/WUQueryWidget.js
  37. 35 0
      esp/files/scripts/WsAccount.js
  38. 68 0
      esp/files/scripts/WsSMC.js
  39. 1 1
      esp/files/stub.htm
  40. 1 1
      esp/files/templates/DFUWUDetailsWidget.html
  41. 13 0
      esp/files/templates/HPCCPlatformECLWidget.html
  42. 17 0
      esp/files/templates/HPCCPlatformFilesWidget.html
  43. 13 0
      esp/files/templates/HPCCPlatformMainWidget.html
  44. 23 0
      esp/files/templates/HPCCPlatformOpsWidget.html
  45. 11 0
      esp/files/templates/HPCCPlatformRoxieWidget.html
  46. 42 0
      esp/files/templates/HPCCPlatformWidget.html
  47. 0 5
      esp/services/ws_fs/ws_fsBinding.hpp
  48. 2 1
      esp/services/ws_workunits/ws_workunitsService.hpp
  49. 8 1
      esp/xslt/nav.xsl

+ 369 - 5
esp/files/css/hpcc.css

@@ -75,7 +75,6 @@ form label{
     padding-top: 4px;
     font-weight:bold;
     height:20px;
-    color:rgb(71, 71, 71);
 }
 
 form textarea{
@@ -125,6 +124,174 @@ hr.dashedLine {
     margin-left:15px;
 }
 /*IDs************************/
+.claro .hpccMainpage {
+    margin: 0;
+    padding: 0;
+    width: 100%; 
+    height: 100%; 
+}
+
+.claro .hpccTitlebar{
+    height: 50px;
+    margin: 0;
+    padding: 0;
+    padding-left: 6px;
+    padding-right: 6px;
+    width:100%;
+    overflow: hidden;
+}
+
+.claro #stubStackController{
+    height: 32px;
+    margin-top: 6px;
+}
+
+.claro .glow :hover{
+    background-color:rgb(118, 157, 192);
+    cursor: pointer;
+}
+
+.claro .hpccTitlebar .dijitToggleButton .dijitButtonNode {
+    background: none;
+    border:none;
+    box-shadow: none;
+    margin:0;
+    align-content:center;
+}
+
+.claro .hpccTitlebar .dijitToggleButtonChecked .dijitButtonNode {
+    border-width: 1px;
+    border-style: solid;
+    border-color: #759dc0;
+    margin: 0px;
+    align-content:center;
+}
+
+.claro .hpccTitlebar .dijitDropDownButton .dijitButtonNode {
+    background: none;
+    border:none;
+    box-shadow: none;
+    margin:0;
+    align-content:center;
+}
+
+.claro .miniTitlebar {
+    background: rgb(200, 200, 200);
+    margin: 0px;
+    padding: 0px;
+    padding-left: 6px;
+    padding-right: 6px;
+    width:100%;
+    overflow: hidden;
+}
+
+.claro .miniTitlebar .dijitToggleButton .dijitButtonNode {
+    background: none;
+    border: none;
+    box-shadow: none;
+    margin: 0px;
+    padding: 2px;
+    cursor: pointer;
+}
+
+.claro .miniTitlebar .dijitToggleButtonChecked .dijitButtonNode {
+    border-width: 1px;
+    border-style: solid;
+    background-image: none;
+    border-color: #759dc0;
+    background-color: #ffffff;
+    margin: 0px;
+    padding: 0px;
+    cursor: pointer;
+}
+
+.claro #stubTitlebar .dijitToggleButton, .dijitButton, .dijitDropDownButton, .dijitComboButton{
+    margin:0;
+    cursor: pointer;
+}
+
+.claro .dijitPopup .dijitMenuPopup{
+    top:56px !important;
+}
+
+#stubTitlebar :focus {
+    outline: none;
+}
+
+#stubTitlebar .dijitStackController .dijitToggleButtonChecked *{
+    cursor: pointer;
+}
+
+#search-form{
+    padding:0;
+    margin:0;
+    float:left;
+    width:290px;
+    margin-top:12px;
+}
+
+#search-form :focus{
+    outline: none;
+}
+
+#search-form input{
+    color:#666;
+}
+
+.roundForm {
+    width:250px;
+    border-radius: 5px;
+    padding: 1px 1px 1px 1px;
+}
+
+#userAccount{
+    float:left;
+    text-align: right;
+    padding:5px 5px 0 0;
+    padding-top:10px;
+}
+
+#userAccount a{
+    color:rgb(164, 220, 245);
+}
+
+#userIcons{
+    float:left;
+    text-align: center;
+}
+
+#userIcons img{
+    border:none;
+    margin-top:8px;
+}
+
+#userIcons .dijitDropDownButton .dijitButtonNode {
+    border:none;
+    background: none;
+}
+
+#userIcons .holder span:nth-child(1) {
+    border:none;
+    margin:0 0 0 0;
+    padding:0;
+    outline: none;
+}
+
+#userIcons .dijitButtonText{
+    padding:0px;
+}
+
+#userIcons .dijitFocused{
+    float:left;
+    border:none;
+}
+
+.claro #stubMore{
+    padding:0;
+    margin:0;
+    height: 32px;
+    margin-top: 6px;
+}
 
 #myProgressBar{
     width:200px;
@@ -140,6 +307,63 @@ hr.dashedLine {
     height:12px;
 }
 
+.iconLogo{
+    background-image: url("../img/hpcc_systems_logo.png");
+    width: 180px;
+    height: 32px;
+    cursor: pointer;
+}
+
+.iconWu{
+    background-image: url("../img/WUCog.png");
+    width: 32px;
+    height: 32px;
+    cursor: pointer;
+}
+
+.iconDFU{
+    background-image: url("../img/FolderSmart.png");
+    width: 32px;
+    height: 32px;
+    cursor: pointer;
+}
+
+.iconGetDFU{
+    background-image: url("../img/LZFolder.png");
+    width: 32px;
+    height: 32px;
+    cursor: pointer;
+}
+
+.iconOperations{
+    background-image: url("../img/Operations.png");
+    width: 32px;
+    height: 32px;
+    cursor: pointer;
+}
+
+.iconLandingZone{
+    background-image: url("../img/LandingZone.png");
+    width: 32px;
+    height: 32px;
+    cursor: pointer;
+}
+
+.iconTargets{
+    background-image: url("../img/Targets.png");
+    width: 32px;
+    height: 32px;
+    cursor: pointer;
+}
+
+.iconFind{
+    background-image: url("../img/search_icon.png");
+    width: 32px;
+    height: 32px;
+    cursor: pointer;
+}
+
+/*###############################*/
 #appLayout {
     height: 100%;
 }
@@ -159,9 +383,9 @@ hr.dashedLine {
 }
 
 #loadingOverlay .loadingMessage {
-        padding: 25px 40px;
-        color: rgb(153, 153, 153);
-    }
+    padding: 25px 40px;
+    color: rgb(153, 153, 153);
+}
 
 #timings, #properties {
     padding: 0;
@@ -181,6 +405,146 @@ hr.dashedLine {
 }
 
 /*CLASSES******************/
+.claro #userIcons .dijitArrowButtonInner{
+    margin:5px auto 0 5px;
+}
+
+.holder :focus{
+    outline: none;
+}
+
+.holder{
+    width:40px;
+    height:60px;
+    float:left;
+}
+
+.seperator{
+    width:1px;
+    height:32px;
+    float:left;
+    margin-left: 4px;
+    margin-top: 9px;
+    margin-right: 12px;
+    margin-bottom: 9px;
+}
+
+.titleLowLite {
+    background-color: rgb(24, 59, 79);
+}
+
+/*  Primary colour palette */
+.hpccRed {
+    background-color: rgb(237, 28, 36);
+}
+
+.hpccBlack {
+    background-color: rgb(0, 0, 0);
+}
+
+.hpccWhite {
+    background-color: rgb(255, 255, 255);
+}
+/*  Secondart colour palette */
+.hpccGreyLight {
+    background-color: rgb(188, 190, 192);
+}
+
+.hpccGreyMedium {
+    background-color: rgb(147, 149, 152);
+}
+
+.hpccGreyDark {
+    background-color: rgb(109, 111, 113);
+}
+
+.hpccCyan {
+    background-color: rgb(0, 157, 219);
+}
+
+.hpccCyan70 {
+    background-color: rgb(77, 186, 230);
+}
+
+.hpccCyan50 {
+    background-color: rgb(128, 206, 237);
+}
+
+.hpccCyan30 {
+    background-color: rgb(179, 226, 244);
+}
+
+.hpccGreen {
+    background-color: rgb(119, 184, 0);
+}
+
+.hpccGreen70 {
+    background-color: rgb(160, 205, 77);
+}
+
+.hpccGreen50 {
+    background-color: rgb(187, 220, 128);
+}
+
+.hpccGreen30 {
+    background-color: rgb(214, 234, 179);
+}
+
+.hpccPurple {
+    background-color: rgb(143, 43, 140);
+}
+
+.hpccPurple70 {
+    background-color: rgb(177, 107, 175);
+}
+
+.hpccPurple50 {
+    background-color: rgb(199, 149, 198);
+}
+
+.hpccPurple30 {
+    background-color: rgb(221, 191, 221);
+}
+
+.grey{
+    background-color: rgb(80, 80, 80);
+}
+
+.white{
+    background-color:rgb(255,255,255);
+}
+
+.left{
+    float:left;
+}
+
+.right{
+    float:right;
+}
+
+.hidden{
+    color:rgb(214, 214, 214);
+    display: none !important;
+}
+
+.show{
+    display:block;
+}
+
+.hpccApp {
+    height: 100%;
+}
+
+.navBarLoggedin{
+    text-transform: uppercase;
+    color:rgb(255,255,255);
+    display: block;
+}
+
+.claro .hpccApp .hpccTitlebar {
+    background-color: rgb(0, 108, 204);
+}
+
 .hidden{
     color:rgb(214, 214, 214);
     display: none !important;
@@ -399,4 +763,4 @@ margin-left:-20px;
     left: 0;
     right: 0;
     height: auto;
-}
+}

二进制
esp/files/img/FolderSmart.png


二进制
esp/files/img/Info.png


二进制
esp/files/img/LZFolder.png


二进制
esp/files/img/LandingZone.png


二进制
esp/files/img/Operations.png


二进制
esp/files/img/Targets.png


二进制
esp/files/img/WUCog.png


二进制
esp/files/img/dfu_icon.png


二进制
esp/files/img/ecl_icon.png


二进制
esp/files/img/files_icon.png


二进制
esp/files/img/help_icon.png


二进制
esp/files/img/hpcc_systems_logo.png


二进制
esp/files/img/ops_icon.png


二进制
esp/files/img/search_icon.png


二进制
esp/files/img/user_icon.png


+ 175 - 0
esp/files/scripts/ActivityWidget.js

@@ -0,0 +1,175 @@
+/*##############################################################################
+#    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/array",
+    "dojo/on",
+
+    "dijit/form/Button",
+
+    "dgrid/OnDemandGrid",
+    "dgrid/Keyboard",
+    "dgrid/Selection",
+    "dgrid/selector",
+    "dgrid/extensions/ColumnResizer",
+    "dgrid/extensions/DijitRegistry",
+
+    "hpcc/GridDetailsWidget",
+    "hpcc/ESPWorkunit",
+    "hpcc/ESPDFUWorkunit",
+    "hpcc/WsSMC",
+    "hpcc/WsWorkunits",
+    "hpcc/FileSpray",
+    "hpcc/WsDfu",
+    "hpcc/WUDetailsWidget",
+    "hpcc/DFUWUDetailsWidget",
+    "hpcc/LFDetailsWidget",
+    "hpcc/SFDetailsWidget",
+    "hpcc/ESPUtil"
+
+], function (declare, lang, arrayUtil, on,
+                Button,
+                OnDemandGrid, Keyboard, Selection, selector, ColumnResizer, DijitRegistry,
+                GridDetailsWidget, ESPWorkunit, ESPDFUWorkunit, WsSMC, WsWorkunits, FileSpray, WsDfu, WUDetailsWidget, DFUWUDetailsWidget, LFDetailsWidget, SFDetailsWidget, ESPUtil) {
+    return declare("ActivityWidget", [GridDetailsWidget], {
+
+        gridTitle: "Activity",
+        idProperty: "Wuid",
+
+        doSearch: function (searchText) {
+            this.searchText = searchText;
+            this.selectChild(this.gridTab);
+            this.refreshGrid();
+        },
+
+        init: function (params) {
+            if (this.initalized)
+                return;
+            this.initalized = true;
+            this.refreshGrid();
+            this._refreshActionState();
+        },
+
+        createGrid: function (domID) {
+            var context = this;
+            var retVal = new declare([OnDemandGrid, Keyboard, Selection, ColumnResizer, DijitRegistry, ESPUtil.GridHelper])({
+                allowSelectAll: true,
+                deselectOnRefresh: false,
+                store: WsSMC.CreateActivityStore(),
+                columns: {
+                    col1: selector({ width: 27, selectorType: 'checkbox' }),
+                    Wuid: {
+                        label: "Active workunit", width: 180, sortable: true,
+                        formatter: function (Wuid, row) {
+                            var wu = row.Server === "DFUserver" ? ESPDFUWorkunit.Get(Wuid) : ESPWorkunit.Get(Wuid);
+                            return "<img src='../files/" + wu.getStateImage() + "'>&nbsp<a href=# class='" + context.id + "WuidClick'>" + Wuid + "</a>";
+                        }
+
+                    },
+                    ClusterName: { label: "Target", width: 108, sortable: true },
+                    State: {
+                        label: "State", width: 180, sortable: true, formatter: function (state, row) {
+                            return state + (row.Duration ? " (" + row.Duration + ")" : "");
+                        }
+                    },
+                    Owner: { label: "Owner", width: 90, sortable: true },
+                    Jobname: { label: "Job Name", sortable: true },
+                }
+            }, domID);
+
+            var context = this;
+            on(document, "." + this.id + "WuidClick:click", function (evt) {
+                if (context._onRowDblClick) {
+                    var row = retVal.row(evt).data;
+                    context._onRowDblClick(row);
+                }
+            });
+            return retVal;
+        },
+
+        createDetail: function (id, row, params) {
+            if (row.Server === "DFUserver") {
+                return new DFUWUDetailsWidget.fixCircularDependency({
+                    id: id,
+                    title: row.ID,
+                    closable: true,
+                    hpcc: {
+                        params: {
+                            Wuid: row.ID
+                        }
+                    }
+                });
+            } 
+            return new WUDetailsWidget({
+                id: id,
+                title: row.Wuid,
+                closable: true,
+                hpcc: {
+                    params: {
+                        Wuid: row.Wuid
+                    }
+                }
+            });
+        },
+
+        loadRunning: function (response) {
+            var items = lang.getObject("ActivityResponse.Running", false, response)
+            if (items) {
+                var context = this;
+                arrayUtil.forEach(items, function (item, idx) {
+                    context.store.add({
+                        id: "ActivityRunning" + idx,
+                        ClusterName: item.ClusterName,
+                        Wuid: item.Wuid,
+                        Owner: item.Owner,
+                        Jobname: item.Owner,
+                        Summary: item.Name + " (" + prefix + ")",
+                        _type: "LogicalFile",
+                        _name: item.Name
+                    });
+                });
+                return items.length;
+            }
+            return 0;
+        },
+
+        refreshGrid: function (args) {
+            var context = this;
+            this.grid.set("query", {
+            });
+            /*
+            WsSMC.Activity({
+                request: {
+                }
+            }).then(function (response) {
+                var items = lang.getObject("ActivityResponse.Running.ActiveWorkunit", false, response);
+                arrayUtil.forEach(items, function (item, idx) {
+                    lang.mixin(item, {
+                        State: item.State + " (" + item.Duration + ")"
+                    });
+                });
+                context.store.setData(items);
+                context.grid.refresh();
+            });
+            */
+        },
+
+        refreshActionState: function (selection) {
+            this.inherited(arguments);
+        }
+    });
+});

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

@@ -92,7 +92,6 @@ define([
         startup: function (args) {
             this.inherited(arguments);
             this.initContextMenu();
-            this.initWorkunitsGrid();
             this.initFilter();
         },
 
@@ -269,6 +268,7 @@ define([
                     registry.byId(context.id + "DesprayTargetPath").set("value", item.machine.Directory + "/");
                 }
             });
+            this.initWorkunitsGrid();
             this.selectChild(this.workunitsTab, true);
         },
 

+ 2 - 2
esp/files/scripts/ESPDFUWorkunit.js

@@ -32,8 +32,8 @@ define([
     var Store = declare([ESPRequest.Store], {
         service: "FileSpray",
         action: "GetDFUWorkunits",
-        responseQualifier: "results.DFUWorkunit",
-        responseTotalQualifier: "NumWUs",
+        responseQualifier: "GetDFUWorkunitsResponse.results.DFUWorkunit",
+        responseTotalQualifier: "GetDFUWorkunitsResponse.NumWUs",
         idProperty: "ID",
         startProperty: "PageStartFrom",
         countProperty: "PageSize",

+ 2 - 2
esp/files/scripts/ESPLogicalFile.js

@@ -36,8 +36,8 @@ define([
     var Store = declare([ESPRequest.Store], {
         service: "WsDfu",
         action: "DFUQuery",
-        responseQualifier: "DFULogicalFiles.DFULogicalFile",
-        responseTotalQualifier: "NumFiles",
+        responseQualifier: "DFUQueryResponse.DFULogicalFiles.DFULogicalFile",
+        responseTotalQualifier: "DFUQueryResponse.NumFiles",
         idProperty: "Name",
         startProperty: "PageStartFrom",
         countProperty: "PageSize",

+ 20 - 14
esp/files/scripts/ESPRequest.js

@@ -43,7 +43,7 @@ define([
         },
 
         getBaseURL: function (service) {
-            if (!service) {
+            if (service === undefined) {
                 service = "WsWorkunits";
             }
             if (this.serverIP)
@@ -105,7 +105,7 @@ define([
             dojo.publish("hpcc/standbyBackgroundShow");
             var handleAs = params.handleAs ? params.handleAs : "json";
             return this._send(service, action, params).then(function (response) {
-                if (handleAs == "json") {
+                if (!params.suppressExceptionToaster && handleAs == "json") {
                     var exceptionCode20080 = false; //  Deleted WU
                     if (lang.exists("Exceptions.Source", response)) {
                         var message = "<h3>" + response.Exceptions.Source + "</h3>";
@@ -270,19 +270,24 @@ define([
             },
 
             exists: function (id) {
-                return lang.exists(this.service + "." + this.action + "." + id, _StoreSingletons);
+                var item = lang.getObject(this.service + "." + this.action, false, _StoreSingletons);
+                if (item) {
+                    return item[id] !== undefined;
+                }
+                return false;
             },
 
-            get: function (id) {
+            get: function (id, item) {
                 if (!this.exists(id)) {
-                    var retVal = lang.getObject(this.service + "." + this.action + "." + id, true, _StoreSingletons);
-                    lang.mixin(retVal, this.create(id))
-                    return retVal;
+                    var newItem = lang.getObject(this.service + "." + this.action, true, _StoreSingletons);
+                    newItem[id] = this.create(id, item);
+                    return newItem[id];
                 }
-                return lang.getObject(this.service + "." + this.action + "." + id, false, _StoreSingletons);
+                var item = lang.getObject(this.service + "." + this.action, false, _StoreSingletons);
+                return item[id];
             },
 
-            create: function (id) {
+            create: function (id, item) {
                 var retVal = {
                 };
                 retVal[this.idProperty] = id;
@@ -294,11 +299,11 @@ define([
             },
 
             _hasResponseContent: function(response) {
-                return lang.exists(this.action + "Response." + this.responseQualifier, response);
+                return lang.exists(this.responseQualifier, response);
             },
 
             _getResponseContent: function(response) {
-                return lang.getObject(this.action + "Response." + this.responseQualifier, false, response);
+                return lang.getObject(this.responseQualifier, false, response);
             },
 
             query: function (query, options) {
@@ -329,7 +334,7 @@ define([
                 var context = this;
                 deferredResults.total = results.then(function (response) {
                     if (context.responseTotalQualifier) {
-                        return lang.getObject(context.action + "Response." + context.responseTotalQualifier, false, response);
+                        return lang.getObject(context.responseTotalQualifier, false, response);
                     } else if (context._hasResponseContent(response)) {
                         return context._getResponseContent(response).length;
                     }
@@ -339,13 +344,14 @@ define([
                     var items = [];
                     if (context._hasResponseContent(response)) {
                         if (context.preProcessResponse) {
-                            context.preProcessResponse(lang.getObject(context.action + "Response", false, response), request);
+                            var responseQualiferArray = context.responseQualifier.split(".");
+                            context.preProcessResponse(lang.getObject(responseQualiferArray[0], false, response), request);
                         }
                         arrayUtil.forEach(context._getResponseContent(response), function (item, index) {
                             if (context.preProcessRow) {
                                 context.preProcessRow(item);
                             }
-                            var storeItem = context.get(context.getIdentity(item));
+                            var storeItem = context.get(context.getIdentity(item), item);
                             context.update(context.getIdentity(item), item);
                             items.push(storeItem);
                         });

+ 24 - 11
esp/files/scripts/ESPResult.js

@@ -37,8 +37,8 @@ define([
     var Store = declare([ESPRequest.Store, ESPBase], {
         service: "WsWorkunits",
         action: "WUResult",
-        responseQualifier: "Result",
-        responseTotalQualifier: "Total",
+        responseQualifier: "WUResultResponse.Result",
+        responseTotalQualifier: "WUResultResponse.Total",
         idProperty: "rowNum",
         startProperty: "Start",
         countProperty: "Count",
@@ -174,27 +174,40 @@ define([
             return table;
         },
 
-        getRowStructureFromSchema: function (parentNode) {
-            var retVal = [];
+        getRowStructureFromSchema: function (parentNode, prefix) {
             var sequence = this.getFirstSequenceNode(parentNode, "sequence");
             if (!sequence)
-                return retVal;
+                return null;
 
+            var retVal = [];
             for (var i = 0; i < sequence.childNodes.length; ++i) {
                 var node = sequence.childNodes[i];
                 if (typeof (node.getAttribute) != "undefined") {
                     var name = node.getAttribute("name");
                     var type = node.getAttribute("type");
+                    var children = this.getRowStructureFromSchema(node, name + "_");
                     if (name && type) {
                         retVal.push({
                             label: name,
-                            field: name,
+                            field: prefix + name,
                             width: this.extractWidth(type, name) * 9,
                             className: "resultGridCell",
                             sortable: false
                         });
-                    }
-                    if (node.hasChildNodes()) {
+                    } else if (children) {
+                        var childWidth = 0;
+                        arrayUtil.forEach(children, function(item, idx) {
+                            childWidth += item.width;
+                        });
+                        /*
+                        retVal.push({
+                            label: name,
+                            children: children,
+                            width: childWidth,
+                            className: "resultGridCell",
+                            sortable: false
+                        });
+                        */
                         var context = this;
                         retVal.push({
                             label: name,
@@ -204,14 +217,14 @@ define([
                                 div.appendChild(context.rowToTable(cell));
                                 return div.innerHTML;
                             },
-                            width: this.getRowWidth(node) * 9,
+                            width: childWidth,
                             className: "resultGridCell",
                             sortable: false
                         });
                     }
                 }
             }
-            return retVal;
+            return retVal.length ? retVal : null;
         },
 
         getRowStructureFromData: function (rows) {
@@ -253,7 +266,7 @@ define([
 
             var dom = parser.parse(this.XmlSchema);
             var dataset = this.getFirstSchemaNode(dom, "Dataset");
-            var innerStruct = this.getRowStructureFromSchema(dataset);
+            var innerStruct = this.getRowStructureFromSchema(dataset, "");
             for (var i = 0; i < innerStruct.length; ++i) {
                 structure[0].cells[structure[0].cells.length - 1].push(innerStruct[i]);
             }

+ 12 - 0
esp/files/scripts/ESPUtil.js

@@ -167,6 +167,12 @@ define([
                 this.clearSelection();
                 var context = this;
                 arrayUtil.forEach(arrayOfIDs, function (item, idx) {
+                    if (idx === 0) {
+                        var row = context.row(item);
+                        if (row.element) {
+                            row.element.scrollIntoView();
+                        }
+                    }
                     context.select(item);
                 });
             },
@@ -175,6 +181,12 @@ define([
                 this.clearSelection();
                 var context = this;
                 arrayUtil.forEach(items, function (item, idx) {
+                    if (idx === 0) {
+                        var row = context.row(item);
+                        if (row.element) {
+                            row.element.scrollIntoView();
+                        }
+                    }
                     context.select(context.store.getIdentity(item));
                 });
             },

+ 2 - 2
esp/files/scripts/ESPWorkunit.js

@@ -34,8 +34,8 @@ define([
     var Store = declare([ESPRequest.Store], {
         service: "WsWorkunits",
         action: "WUQuery",
-        responseQualifier: "Workunits.ECLWorkunit",
-        responseTotalQualifier: "NumWUs",
+        responseQualifier: "WUQueryResponse.Workunits.ECLWorkunit",
+        responseTotalQualifier: "WUQueryResponse.NumWUs",
         idProperty: "Wuid",
         startProperty: "PageStartFrom",
         countProperty: "Count",

+ 2 - 2
esp/files/scripts/FileSpray.js

@@ -34,7 +34,7 @@ define([
     var FileListStore = declare([ESPRequest.Store], {
         service: "FileSpray",
         action: "FileList",
-        responseQualifier: "files.PhysicalFileStruct",
+        responseQualifier: "FileListResponse.files.PhysicalFileStruct",
         idProperty: "calculatedID",
         create: function (id) {
             var retVal = {
@@ -119,7 +119,7 @@ define([
     var LandingZonesStore = declare([ESPRequest.Store], {
         service: "FileSpray",
         action: "DropZoneFiles",
-        responseQualifier: "DropZones.DropZone",
+        responseQualifier: "DropZoneFilesResponse.DropZones.DropZone",
         idProperty: "calculatedID",
         constructor: function (options) {
             declare.safeMixin(this, options);

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

@@ -351,7 +351,7 @@ define([
                     },
                     ID: {
                         label: "ID",
-                        width: 162,
+                        width: 180,
                         formatter: function (ID, idx) {
                             var wu = ESPDFUWorkunit.Get(ID);
                             return "<img src='../files/" + wu.getStateImage() + "'>&nbsp<a href=# rowIndex=" + idx + " class='" + context.id + "IDClick'>" + ID + "</a>";

+ 5 - 0
esp/files/scripts/GridDetailsWidget.js

@@ -47,6 +47,11 @@ define([
         store: null,
         grid: null,
 
+        postCreate: function (args) {
+            this.inherited(arguments);
+            this.gridTab = registry.byId(this.id + "_Grid");
+        },
+
         startup: function (args) {
             this.inherited(arguments);
             var context = this;

+ 68 - 0
esp/files/scripts/HPCCPlatformECLWidget.js

@@ -0,0 +1,68 @@
+/*##############################################################################
+#	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",
+
+    "dijit/_TemplatedMixin",
+    "dijit/_WidgetsInTemplateMixin",
+    "dijit/registry",
+
+    "hpcc/_TabContainerWidget",
+    "hpcc/WUQueryWidget",
+    "hpcc/ECLPlaygroundWidget",
+
+    "dojo/text!../templates/HPCCPlatformECLWidget.html",
+
+    "dijit/layout/BorderContainer",
+    "dijit/layout/TabContainer",
+    "dijit/layout/ContentPane"
+
+], function (declare,
+                _TemplatedMixin, _WidgetsInTemplateMixin, registry,
+                _TabContainerWidget, WUQueryWidget, ECLPlaygroundWidget,
+                template) {
+    return declare("HPCCPlatformECLWidget", [_TabContainerWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
+        templateString: template,
+        baseClass: "HPCCPlatformECLWidget",
+
+        postCreate: function (args) {
+            this.inherited(arguments);
+        },
+
+        startup: function (args) {
+            this.inherited(arguments);
+        },
+
+        //  Hitched actions  ---
+
+        //  Implementation  ---
+        init: function (params) {
+            if (this.initalized)
+                return;
+            this.initalized = true;
+            this.initTab();
+        },
+
+        initTab: function () {
+            var currSel = this.getSelectedChild();
+            if (currSel && !currSel.initalized) {
+                if (currSel.init) {
+                    currSel.init(currSel.params);
+                }
+            }
+        }
+    });
+});

+ 76 - 0
esp/files/scripts/HPCCPlatformFilesWidget.js

@@ -0,0 +1,76 @@
+/*##############################################################################
+#	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",
+
+    "dijit/_TemplatedMixin",
+    "dijit/_WidgetsInTemplateMixin",
+    "dijit/registry",
+
+    "hpcc/_TabContainerWidget",
+    "hpcc/ESPRequest",
+    "hpcc/GetDFUWorkunitsWidget",
+    "hpcc/DFUQueryWidget",
+    "hpcc/LZBrowseWidget",
+
+    "dojo/text!../templates/HPCCPlatformFilesWidget.html",
+
+    "dijit/layout/BorderContainer",
+    "dijit/layout/TabContainer",
+    "dijit/layout/ContentPane"
+
+], function (declare,
+                _TemplatedMixin, _WidgetsInTemplateMixin, registry,
+                _TabContainerWidget, ESPRequest, GetDFUWorkunitsWidget, DFUQueryWidget, LZBrowseWidget,
+                template) {
+    return declare("HPCCPlatformFilesWidget", [_TabContainerWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
+        templateString: template,
+        baseClass: "HPCCPlatformFilesWidget",
+
+        postCreate: function (args) {
+            this.inherited(arguments);
+        },
+
+        startup: function (args) {
+            this.inherited(arguments);
+        },
+
+        //  Hitched actions  ---
+
+        //  Implementation  ---
+        init: function (params) {
+            if (this.initalized)
+                return;
+            this.initalized = true;
+            this.initTab();
+        },
+
+        initTab: function () {
+            var currSel = this.getSelectedChild();
+            if (currSel && !currSel.initalized) {
+                if (currSel.id === this.id + "_XRef") {
+                    currSel.set("content", dojo.create("iframe", {
+                        src: ESPRequest.getBaseURL("WsDFUXRef") + "/DFUXRefList",
+                        style: "border: 0; width: 100%; height: 100%"
+                    }));
+                } else if (currSel.init) {
+                    currSel.init(currSel.params);
+                }
+                currSel.initalized = true;
+            }
+        }
+    });
+});

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

@@ -0,0 +1,69 @@
+/*##############################################################################
+#	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",
+
+    "dijit/_TemplatedMixin",
+    "dijit/_WidgetsInTemplateMixin",
+    "dijit/registry",
+
+    "hpcc/_TabContainerWidget",
+
+    "dojo/text!../templates/HPCCPlatformMainWidget.html",
+
+    "dijit/layout/BorderContainer",
+    "dijit/layout/TabContainer",
+    "dijit/layout/ContentPane",
+
+    "hpcc/ActivityWidget",
+    "hpcc/SearchResultsWidget"
+
+], function (declare,
+                _TemplatedMixin, _WidgetsInTemplateMixin, registry,
+                _TabContainerWidget,
+                template) {
+    return declare("HPCCPlatformMainWidget", [_TabContainerWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
+        templateString: template,
+        baseClass: "HPCCPlatformMainWidget",
+
+        postCreate: function (args) {
+            this.inherited(arguments);
+        },
+
+        startup: function (args) {
+            this.inherited(arguments);
+        },
+
+        //  Hitched actions  ---
+
+        //  Implementation  ---
+        init: function (params) {
+            if (this.initalized)
+                return;
+            this.initalized = true;
+            this.initTab();
+        },
+
+        initTab: function () {
+            var currSel = this.getSelectedChild();
+            if (currSel && !currSel.initalized) {
+                if (currSel.init) {
+                    currSel.init(currSel.params);
+                }
+            }
+        }
+    });
+});

+ 103 - 0
esp/files/scripts/HPCCPlatformOpsWidget.js

@@ -0,0 +1,103 @@
+/*##############################################################################
+#	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",
+
+    "dijit/_TemplatedMixin",
+    "dijit/_WidgetsInTemplateMixin",
+    "dijit/registry",
+
+    "hpcc/_TabContainerWidget",
+    "hpcc/ESPRequest",
+
+    "dojo/text!../templates/HPCCPlatformOpsWidget.html",
+
+    "dijit/layout/BorderContainer",
+    "dijit/layout/TabContainer",
+    "dijit/layout/ContentPane"
+
+], function (declare,
+                _TemplatedMixin, _WidgetsInTemplateMixin, registry,
+                _TabContainerWidget, ESPRequest,
+                template) {
+    return declare("HPCCPlatformOpsWidget", [_TabContainerWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
+        templateString: template,
+        baseClass: "HPCCPlatformOpsWidget",
+
+        postCreate: function (args) {
+            this.inherited(arguments);
+        },
+
+        startup: function (args) {
+            this.inherited(arguments);
+        },
+
+        //  Hitched actions  ---
+
+        //  Implementation  ---
+        init: function (params) {
+            if (this.initalized)
+                return;
+            this.initalized = true;
+            this.initTab();
+        },
+
+        initTab: function () {
+            var currSel = this.getSelectedChild();
+            if (currSel && !currSel.initalized) {
+                if (currSel.id === this.id + "_Resources") {
+                    currSel.set("content", dojo.create("iframe", {
+                        src: ESPRequest.getBaseURL("WsSMC") + "/BrowseResources",
+                        style: "border: 0; width: 100%; height: 100%"
+                    }));
+                } else if (currSel.id === this.id + "_Users") {
+                    currSel.set("content", dojo.create("iframe", {
+                        src: ESPRequest.getBaseURL("ws_access") + "/Users",
+                        style: "border: 0; width: 100%; height: 100%"
+                    }));
+                } else if (currSel.id === this.id + "_Groups") {
+                    currSel.set("content", dojo.create("iframe", {
+                        src: ESPRequest.getBaseURL("ws_access") + "/Groups",
+                        style: "border: 0; width: 100%; height: 100%"
+                    }));
+                } else if (currSel.id === this.id + "_Permissions") {
+                    currSel.set("content", dojo.create("iframe", {
+                        src: ESPRequest.getBaseURL("ws_access") + "/Permissions",
+                        style: "border: 0; width: 100%; height: 100%"
+                    }));
+                } else if (currSel.id === this.id + "_TargetClusters") {
+                    currSel.set("content", dojo.create("iframe", {
+                        src: ESPRequest.getBaseURL("WsTopology") + "/TpTargetClusterQuery?Type=ROOT",
+                        style: "border: 0; width: 100%; height: 100%"
+                    }));
+                } else if (currSel.id === this.id + "_ClusterProcesses") {
+                    currSel.set("content", dojo.create("iframe", {
+                        src: ESPRequest.getBaseURL("WsTopology") + "/TpClusterQuery?Type=ROOT",
+                        style: "border: 0; width: 100%; height: 100%"
+                    }));
+                } else if (currSel.id === this.id + "_SystemServers") {
+                    currSel.set("content", dojo.create("iframe", {
+                        src: ESPRequest.getBaseURL("WsTopology") + "/TpServiceQuery?Type=ALLSERVICES",
+                        style: "border: 0; width: 100%; height: 100%"
+                    }));
+                } else if (currSel.init) {
+                    currSel.init(currSel.params);
+                }
+                currSel.initalized = true;
+            }
+        }
+    });
+});

+ 73 - 0
esp/files/scripts/HPCCPlatformRoxieWidget.js

@@ -0,0 +1,73 @@
+/*##############################################################################
+#	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",
+
+    "dijit/_TemplatedMixin",
+    "dijit/_WidgetsInTemplateMixin",
+    "dijit/registry",
+
+    "hpcc/_TabContainerWidget",
+    "hpcc/ESPRequest",
+
+    "dojo/text!../templates/HPCCPlatformRoxieWidget.html",
+
+    "dijit/layout/BorderContainer",
+    "dijit/layout/TabContainer",
+    "dijit/layout/ContentPane"
+
+], function (declare,
+                _TemplatedMixin, _WidgetsInTemplateMixin, registry,
+                _TabContainerWidget, ESPRequest,
+                template) {
+    return declare("HPCCPlatformRoxieWidget", [_TabContainerWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
+        templateString: template,
+        baseClass: "HPCCPlatformRoxieWidget",
+
+        postCreate: function (args) {
+            this.inherited(arguments);
+        },
+
+        startup: function (args) {
+            this.inherited(arguments);
+        },
+
+        //  Hitched actions  ---
+
+        //  Implementation  ---
+        init: function (params) {
+            if (this.initalized)
+                return;
+            this.initalized = true;
+            this.initTab();
+        },
+
+        initTab: function () {
+            var currSel = this.getSelectedChild();
+            if (currSel && !currSel.initalized) {
+                if (currSel.id === this.id + "_Queries") {
+                    currSel.set("content", dojo.create("iframe", {
+                        src: ESPRequest.getBaseURL() + "/WUQuerySets",
+                        style: "border: 0; width: 100%; height: 100%"
+                    }));
+                    currSel.initalized = true;
+                } else if (currSel.init) {
+                    currSel.init(currSel.params);
+                }
+            }
+        }
+    });
+});

+ 126 - 0
esp/files/scripts/HPCCPlatformWidget.js

@@ -0,0 +1,126 @@
+/*##############################################################################
+#   HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+############################################################################## */
+define([
+    "dojo/_base/declare",
+    "dojo/dom",
+
+    "dijit/_TemplatedMixin",
+    "dijit/_WidgetsInTemplateMixin",
+    "dijit/registry",
+    "dijit/Tooltip",
+
+    "hpcc/_TabContainerWidget",
+    "hpcc/ESPRequest",
+    "hpcc/WsAccount",
+
+    "dojo/text!../templates/HPCCPlatformWidget.html",
+
+    "dijit/layout/BorderContainer",
+    "dijit/layout/TabContainer",
+    "dijit/layout/StackContainer",
+    "dijit/layout/StackController",
+    "dijit/layout/ContentPane",
+    "dijit/form/DropDownButton",
+    "dijit/form/ComboButton",
+    "dijit/form/TextBox",
+    "dijit/Menu",
+    "dijit/MenuSeparator",
+    "dijit/Toolbar",
+    "dijit/TooltipDialog",
+
+    "hpcc/HPCCPlatformMainWidget",
+    "hpcc/HPCCPlatformECLWidget",
+    "hpcc/HPCCPlatformFilesWidget",
+    "hpcc/HPCCPlatformRoxieWidget",
+    "hpcc/HPCCPlatformOpsWidget"
+
+], function (declare, dom,
+                _TemplatedMixin, _WidgetsInTemplateMixin, registry, Tooltip,
+                _TabContainerWidget, ESPRequest, WsAccount,
+                template) {
+    return declare("HPCCPlatformWidget", [_TabContainerWidget, _TemplatedMixin, _WidgetsInTemplateMixin], {
+        templateString: template,
+        baseClass: "HPCCPlatformWidget",
+
+        postCreate: function (args) {
+            this.inherited(arguments);
+            this.searchText = registry.byId(this.id + "FindText");
+            this.searchPage = registry.byId(this.id + "_Main" + "_Search");
+            this.stackContainer = registry.byId(this.id + "TabContainer");
+            this.mainPage = registry.byId(this.id + "_Main");
+            this.mainStackContainer = registry.byId(this.mainPage.id + "TabContainer");
+            this.searchPage = registry.byId(this.id + "_Main" + "_Search");
+        },
+
+        startup: function (args) {
+            this.inherited(arguments);
+        },
+
+        //  Hitched actions  ---
+        _onFind: function (evt) {
+            this.stackContainer.selectChild(this.mainPage);
+            this.mainStackContainer.selectChild(this.searchPage);
+            this.searchPage.doSearch(this.searchText.get("value"));
+        },
+
+        _onOpenLegacy: function (evt) {
+            var win = window.open("\\", "_blank");
+            win.focus();
+        },
+
+        _onAbout: function (evt) {
+        },
+
+        createStackControllerTooltip: function (widgetID, text) {
+            return new Tooltip({
+                connectId: [this.id + "StackController_" + widgetID],
+                label: text,
+                showDelay: 1,
+                position: ["below"]
+            });
+        },
+
+        //  Implementation  ---
+        init: function (params) {
+            if (this.initalized)
+                return;
+            this.initalized = true;
+
+            var context = this;
+            WsAccount.MyAccount({
+            }).then(function (response) {
+                dom.byId(context.id + "UserID").innerHTML = response.MyAccountResponse.username;
+            },
+            function (error) {
+            });
+
+            this.createStackControllerTooltip(this.id + "_ECL", "ECL");
+            this.createStackControllerTooltip(this.id + "_Files", "Files");
+            this.createStackControllerTooltip(this.id + "_Queries", "Published Queries");
+            this.createStackControllerTooltip(this.id + "_OPS", "Operations");
+            this.initTab();
+        },
+
+        initTab: function () {
+            var currSel = this.getSelectedChild();
+            if (currSel && !currSel.initalized) {
+                if (currSel.init) {
+                    currSel.init(currSel.params);
+                }
+            }
+        }
+    });
+});

+ 0 - 13
esp/files/scripts/InfoGridWidget.js

@@ -67,19 +67,6 @@ define([
                 this.inherited(arguments);
             },
 
-            test: function (value, rowIdx, cell) {
-                switch (value) {
-                    case "Error":
-                        cell.customClasses.push("ErrorCell");
-                        break;
-
-                    case "Warning":
-                        cell.customClasses.push("WarningCell");
-                        break;
-                }
-                return value;
-            },
-
             postCreate: function (args) {
                 this.inherited(arguments);
                 this.borderContainer = registry.byId(this.id + "BorderContainer");

+ 274 - 0
esp/files/scripts/SearchResultsWidget.js

@@ -0,0 +1,274 @@
+/*##############################################################################
+#    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/array",
+    "dojo/on",
+
+    "dijit/form/Button",
+
+    "dgrid/OnDemandGrid",
+    "dgrid/Keyboard",
+    "dgrid/Selection",
+    "dgrid/selector",
+    "dgrid/extensions/ColumnResizer",
+    "dgrid/extensions/DijitRegistry",
+
+    "hpcc/GridDetailsWidget",
+    "hpcc/WsWorkunits",
+    "hpcc/FileSpray",
+    "hpcc/WsDfu",
+    "hpcc/WUDetailsWidget",
+    "hpcc/DFUWUDetailsWidget",
+    "hpcc/LFDetailsWidget",
+    "hpcc/SFDetailsWidget",
+    "hpcc/ESPUtil"
+
+], function (declare, lang, arrayUtil, on,
+                Button,
+                OnDemandGrid, Keyboard, Selection, selector, ColumnResizer, DijitRegistry,
+                GridDetailsWidget, WsWorkunits, FileSpray, WsDfu, WUDetailsWidget, DFUWUDetailsWidget, LFDetailsWidget, SFDetailsWidget, ESPUtil) {
+    return declare("SearchResultsWidget", [GridDetailsWidget], {
+
+        gridTitle: "Search Results",
+        idProperty: "id",
+
+        doSearch: function (searchText) {
+            this.searchText = searchText;
+            this.selectChild(this.gridTab);
+            this.refreshGrid();
+        },
+
+        init: function (params) {
+            if (this.initalized)
+                return;
+            this.initalized = true;
+
+            this._refreshActionState();
+        },
+
+        createGrid: function (domID) {
+            var context = this;
+            var retVal = new declare([OnDemandGrid, Keyboard, Selection, ColumnResizer, DijitRegistry, ESPUtil.GridHelper])({
+                allowSelectAll: true,
+                deselectOnRefresh: false,
+                store: this.store,
+                loadingMessage: "Loading data...",
+                noDataMessage: "No results found.",
+                columns: {
+                    col1: selector({ width: 27, selectorType: 'checkbox' }),
+                    Type: { label: "What", width: 108, sortable: true },
+                    Reason: { label: "Where", width: 108, sortable: true },
+                    Summary: {
+                        label: "Who", sortable: true,
+                        formatter: function (summary, idx) {
+                            return "<a href=# rowIndex=" + idx + " class='" + context.id + "SearchResultClick'>" + summary + "</a>";
+                        }
+                    }
+                }
+            }, domID);
+
+            var context = this;
+            on(document, "." + this.id + "SearchResultClick:click", function (evt) {
+                if (context._onRowDblClick) {
+                    var row = retVal.row(evt).data;
+                    context._onRowDblClick(row);
+                }
+            });
+            return retVal;
+        },
+
+        createDetail: function (id, row, params) {
+            switch (row._type) {
+                case "Wuid":
+                    return new WUDetailsWidget({
+                        id: id,
+                        title: row.Summary,
+                        closable: true,
+                        hpcc: {
+                            params: {
+                                Wuid: row._wuid
+                            }
+                        }
+                    });
+                    break;
+                case "DFUWuid":
+                    return new DFUWUDetailsWidget.fixCircularDependency({
+                        id: id,
+                        title: row.Summary,
+                        closable: true,
+                        hpcc: {
+                            params: {
+                                Wuid: row._wuid
+                            }
+                        }
+                    });
+                    break;
+                case "LogicalFile":
+                    if (row.isSuperfile) {
+                        return new SFDetailsWidget.fixCircularDependency({
+                            id: id,
+                            title: row.Summary,
+                            closable: true,
+                            hpcc: {
+                                params: {
+                                    Name: row._name
+                                }
+                            }
+                        });
+                    } else {
+                        return new LFDetailsWidget.fixCircularDependency({
+                            id: id,
+                            title: row.Summary,
+                            closable: true,
+                            hpcc: {
+                                params: {
+                                    Name: row._name
+                                }
+                            }
+                        });
+                    }
+                    break;
+                default:
+                    break;
+            }
+            return null;
+        },
+
+        loadWUQueryResponse: function(prefix, response) {
+            var workunits = lang.getObject("WUQueryResponse.Workunits.ECLWorkunit", false, response)
+            if (workunits) {
+                var idPrefix = prefix.split(" ").join("_");
+                var context = this;
+                arrayUtil.forEach(workunits, function (item, idx) {
+                    context.store.add({
+                        id: "WsWorkunitsWUQuery" + idPrefix + idx,
+                        Type: "ECL Workunit",
+                        Reason: prefix,
+                        Summary: item.Wuid,
+                        _type: "Wuid",
+                        _wuid: item.Wuid
+                    });
+                });
+                return workunits.length;
+            }
+            return 0;
+        },
+
+        loadGetDFUWorkunitsResponse: function (prefix, response) {
+            var workunits = lang.getObject("GetDFUWorkunitsResponse.results.DFUWorkunit", false, response)
+            if (workunits) {
+                var idPrefix = prefix.split(" ").join("_");
+                var context = this;
+                arrayUtil.forEach(workunits, function (item, idx) {
+                    context.store.add({
+                        id: "FileSprayGetDFUWorkunits" + idPrefix + idx,
+                        Type: "DFU Workunit",
+                        Reason: prefix,
+                        Summary: item.ID,
+                        _type: "DFUWuid",
+                        _wuid: item.ID
+                    });
+                });
+                return workunits.length;
+            }
+            return 0;
+        },
+
+        loadGetDFUWorkunitResponse: function (prefix, response) {
+            var workunit = lang.getObject("GetDFUWorkunitResponse.result", false, response)
+            if (workunit) {
+                var idPrefix = prefix.split(" ").join("_");
+                this.store.add({
+                    id: "FileSprayGetDFUWorkunits" + idPrefix + idx,
+                    Type: "DFU Workunit",
+                    Reason: prefix,
+                    Summary: workunit.ID,
+                    _type: "DFUWuid",
+                    _wuid: workunit.ID
+                });
+                return 1;
+            }
+            return 0;
+        },
+
+        loadDFUQueryResponse: function (prefix, response) {
+            var items = lang.getObject("DFUQueryResponse.DFULogicalFiles.DFULogicalFile", false, response)
+            if (items) {
+                var idPrefix = prefix.split(" ").join("_");
+                var context = this;
+                arrayUtil.forEach(items, function (item, idx) {
+                    context.store.add({
+                        id: "WsDfuDFUQuery" + idPrefix + idx,
+                        Type: "Logical File",
+                        Reason: prefix,
+                        Summary: item.Name,
+                        _type: "LogicalFile",
+                        _name: item.Name
+                    });
+                });
+                return items.length;
+            }
+            return 0;
+        },
+
+        refreshGrid: function (args) {
+            this.store.setData([]);
+            this.grid.refresh();
+            if (this.searchText) {
+                var context = this;
+                //  ECL WU  ---
+                WsWorkunits.WUQuery({ request: { Wuid: this.searchText }, suppressExceptionToaster: true }).then(function (response) {
+                    context.loadWUQueryResponse("Wuid", response);
+                });
+                WsWorkunits.WUQuery({ request: { Jobname: "*" + this.searchText + "*" } }).then(function (response) {
+                    context.loadWUQueryResponse("Job Name", response);
+                });
+                WsWorkunits.WUQuery({ request: { Owner: this.searchText } }).then(function (response) {
+                    context.loadWUQueryResponse("Owner", response);
+                });
+                WsWorkunits.WUQuery({ request: { ECL: this.searchText } }).then(function (response) {
+                    context.loadWUQueryResponse("ECL", response);
+                });
+                //  DFU WU  ---
+                FileSpray.GetDFUWorkunit({ request: { wuid: this.searchText }, suppressExceptionToaster: true }).then(function (response) {
+                    context.loadGetDFUWorkunitResponse("Wuid", response);
+                });
+                FileSpray.GetDFUWorkunits({ request: { Jobname: "*" + this.searchText + "*" } }).then(function (response) {
+                    context.loadGetDFUWorkunitsResponse("Job Name", response);
+                });
+                FileSpray.GetDFUWorkunits({ request: { Owner: this.searchText } }).then(function (response) {
+                    context.loadGetDFUWorkunitsResponse("Owner", response);
+                });
+                //  Logical Files  ---
+                WsDfu.DFUQuery({ request: { LogicalName: "*" + this.searchText + "*" } }).then(function (response) {
+                    context.loadDFUQueryResponse("Logical Name", response);
+                });
+                WsDfu.DFUQuery({ request: { Description: "*" + this.searchText + "*" } }).then(function (response) {
+                    context.loadDFUQueryResponse("Description", response);
+                });
+                WsDfu.DFUQuery({ request: { Owner: this.searchText } }).then(function (response) {
+                    context.loadDFUQueryResponse("Owner", response);
+                });
+            }
+        },
+
+        refreshActionState: function (selection) {
+            this.inherited(arguments);
+        }
+    });
+});

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

@@ -384,7 +384,7 @@ define([
                         }
                     },
                     Wuid: {
-                        label: "Wuid", width: 162,
+                        label: "Wuid", width: 180,
                         formatter: function (Wuid, idx) {
                             var wu = ESPWorkunit.Get(Wuid);
                             return "<img src='../files/" + wu.getStateImage() + "'>&nbsp<a href=# rowIndex=" + idx + " class='" + context.id + "WuidClick'>" + Wuid + "</a>";

+ 35 - 0
esp/files/scripts/WsAccount.js

@@ -0,0 +1,35 @@
+/*##############################################################################
+#    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([
+    "hpcc/ESPRequest"
+], function (
+    ESPRequest) {
+    return {
+        UpdateUser: function (params) {
+            return ESPRequest.send("ws_account", "UpdateUser", params);
+        },
+
+        UpdateUserInput: function (params) {
+            return ESPRequest.send("ws_account", "UpdateUserInput", params);
+        },
+
+        MyAccount: function (params) {
+            return ESPRequest.send("ws_account", "MyAccount", params);
+        },
+
+    };
+});
+

+ 68 - 0
esp/files/scripts/WsSMC.js

@@ -0,0 +1,68 @@
+/*##############################################################################
+#    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/Observable",
+
+    "hpcc/ESPRequest",
+    "hpcc/ESPWorkunit",
+    "hpcc/ESPDFUWorkunit"
+], function (declare, Observable,
+    ESPRequest, ESPWorkunit, ESPDFUWorkunit) {
+
+    var Store = declare([ESPRequest.Store], {
+        service: "WsSMC",
+        action: "Activity",
+        responseQualifier: "ActivityResponse.Running.ActiveWorkunit",
+        idProperty: "Wuid",
+
+        _watched: [],
+        create: function (id, item) {
+            if (item.Server === "DFUserver") {
+                return ESPDFUWorkunit.Get(id);
+            }
+            return ESPWorkunit.Get(id);
+        },
+        update: function (id, item) {
+            var storeItem = this.get(id);
+            storeItem.updateData(item);
+            if (!this._watched[id]) {
+                var context = this;
+                this._watched[id] = storeItem.watch("changedCount", function (name, oldValue, newValue) {
+                    if (context.notify && oldValue !== newValue) {
+                        context.notify(storeItem, id);
+                    }
+                });
+            }
+        },
+        postProcessResults: function (items) {
+            return items;
+        }
+    });
+
+    return {
+        CreateActivityStore: function (options) {
+            var store = new Store(options);
+            return store;//Observable(store);
+        },
+
+        Activity: function (params) {
+            return ESPRequest.send("WsSMC", "Activity", params);
+        },
+
+    };
+});
+

+ 1 - 1
esp/files/stub.htm

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

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

@@ -29,7 +29,7 @@
                                     <div id="${id}ClusterName"></div>
                                 </li>
                                 <li>
-                                    <label for="${id}JobName">Job name:</label>
+                                    <label for="${id}JobName">Job Name:</label>
                                     <input id="${id}JobName" data-dojo-props="trim:true" data-dojo-type="dijit.form.TextBox" />
                                 </li>
                                 <li>

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

@@ -0,0 +1,13 @@
+<div class="${baseClass}">
+    <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%; margin:0; padding:0" data-dojo-props="gutters:false, liveSplitters:false" data-dojo-type="dijit.layout.BorderContainer">
+        <div id="${id}TitlebarMini" class="miniTitlebar" data-dojo-props="region: 'top'" data-dojo-type="dijit.layout.ContentPane">
+            <div id="${id}StackController" style="width: 100%" data-dojo-props="containerId:'${id}TabContainer'" data-dojo-type="dijit.layout.StackController"></div>
+        </div>
+        <div id="${id}TabContainer" data-dojo-props="region: 'center', tabPosition: 'top'" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.StackContainer">
+            <div id="${id}_Workunits" title="Workunits" data-dojo-type="WUQueryWidget">
+            </div>
+            <div id="${id}_Resources" title="Playground" data-dojo-type="ECLPlaygroundWidget">
+            </div>
+        </div>
+    </div>
+</div>

+ 17 - 0
esp/files/templates/HPCCPlatformFilesWidget.html

@@ -0,0 +1,17 @@
+<div class="${baseClass}">
+    <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%; margin:0; padding:0" data-dojo-props="gutters:false, liveSplitters:false" data-dojo-type="dijit.layout.BorderContainer">
+        <div id="${id}TitlebarMini" class="miniTitlebar" data-dojo-props="region: 'top'" data-dojo-type="dijit.layout.ContentPane">
+            <div id="${id}StackController" style="width: 100%" data-dojo-props="containerId:'${id}TabContainer'" data-dojo-type="dijit.layout.StackController"></div>
+        </div>
+        <div id="${id}TabContainer" data-dojo-props="region: 'center', tabPosition: 'top'" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.StackContainer">
+            <div id="${id}_Workunits" title="Workunits" data-dojo-type="GetDFUWorkunitsWidget">
+            </div>
+            <div id="${id}_LogicalFiles" title="Logical Files" data-dojo-type="DFUQueryWidget">
+            </div>
+            <div id="${id}_LandingZones" title="Landing Zones" data-dojo-type="LZBrowseWidget">
+            </div>
+            <div id="${id}_XRef" title="XRef" data-dojo-type="dijit.layout.ContentPane">
+            </div>
+        </div>
+    </div>
+</div>

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

@@ -0,0 +1,13 @@
+<div class="${baseClass}">
+    <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%; margin:0; padding:0" data-dojo-props="gutters:false, liveSplitters:false" data-dojo-type="dijit.layout.BorderContainer">
+        <div id="${id}TitlebarMini" class="miniTitlebar" data-dojo-props="region: 'top'" data-dojo-type="dijit.layout.ContentPane">
+            <div id="${id}StackController" style="width: 100%" data-dojo-props="containerId:'${id}TabContainer'" data-dojo-type="dijit.layout.StackController"></div>
+        </div>
+        <div id="${id}TabContainer" data-dojo-props="region: 'center', tabPosition: 'top'" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.StackContainer">
+            <div id="${id}_Activity" title="Activity" data-dojo-type="ActivityWidget">
+            </div>
+            <div id="${id}_Search" title="Search Results" data-dojo-type="SearchResultsWidget">
+            </div>
+        </div>
+    </div>
+</div>

+ 23 - 0
esp/files/templates/HPCCPlatformOpsWidget.html

@@ -0,0 +1,23 @@
+<div class="${baseClass}">
+    <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%; margin:0; padding:0" data-dojo-props="gutters:false, liveSplitters:false" data-dojo-type="dijit.layout.BorderContainer">
+        <div id="${id}TitlebarMini" class="miniTitlebar" data-dojo-props="region: 'top'" data-dojo-type="dijit.layout.ContentPane">
+            <div id="${id}StackController" style="width: 100%" data-dojo-props="containerId:'${id}TabContainer'" data-dojo-type="dijit.layout.StackController"></div>
+        </div>
+        <div id="${id}TabContainer" data-dojo-props="region: 'center', tabPosition: 'top'" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.StackContainer">
+            <div id="${id}_Users" title="Users" data-dojo-type="dijit.layout.ContentPane">
+            </div>
+            <div id="${id}_Groups" title="Groups" data-dojo-type="dijit.layout.ContentPane">
+            </div>
+            <div id="${id}_Permissions" title="Permissions" data-dojo-type="dijit.layout.ContentPane">
+            </div>
+            <div id="${id}_TargetClusters" title="Target Clusters" data-dojo-type="dijit.layout.ContentPane">
+            </div>
+            <div id="${id}_ClusterProcesses" title="Cluster Processes" data-dojo-type="dijit.layout.ContentPane">
+            </div>
+            <div id="${id}_SystemServers" title="System Servers" data-dojo-type="dijit.layout.ContentPane">
+            </div>
+            <div id="${id}_Resources" title="Resources" data-dojo-type="dijit.layout.ContentPane">
+            </div>
+        </div>
+    </div>
+</div>

+ 11 - 0
esp/files/templates/HPCCPlatformRoxieWidget.html

@@ -0,0 +1,11 @@
+<div class="${baseClass}">
+    <div id="${id}BorderContainer" class="${baseClass}BorderContainer" style="width: 100%; height: 100%; margin:0; padding:0" data-dojo-props="gutters:false, liveSplitters:false" data-dojo-type="dijit.layout.BorderContainer">
+        <div id="${id}TitlebarMini" class="miniTitlebar" data-dojo-props="region: 'top'" data-dojo-type="dijit.layout.ContentPane">
+            <div id="${id}StackController" style="width: 100%" data-dojo-props="containerId:'${id}TabContainer'" data-dojo-type="dijit.layout.StackController"></div>
+        </div>
+        <div id="${id}TabContainer" data-dojo-props="region: 'center', tabPosition: 'top'" style="width: 100%; height: 100%" data-dojo-type="dijit.layout.StackContainer">
+            <div id="${id}_Queries" title="Queries" data-dojo-type="dijit.layout.ContentPane">
+            </div>
+        </div>
+    </div>
+</div>

+ 42 - 0
esp/files/templates/HPCCPlatformWidget.html

@@ -0,0 +1,42 @@
+<div class="${baseClass}">
+    <div id="${id}BorderContainer" class="hpccMainpage" data-dojo-props="gutters:false, liveSplitters:false" data-dojo-type="dijit.layout.BorderContainer">
+        <div id="${id}Titlebar" class="hpccTitlebar" data-dojo-props="region: 'top'" data-dojo-type="dijit.layout.ContentPane">
+            <div id="${id}StackController" class="left glow" data-dojo-props="containerId:'${id}TabContainer'" data-dojo-type="dijit.layout.StackController"></div>
+            <div class="right">
+                <div class="seperator grey"></div>
+                <div id="search-form">
+                    <input id="${id}FindText" class="roundForm" data-dojo-props="placeHolder: 'Wuid, User, More...'" data-dojo-type="dijit.form.TextBox" />
+                    <button id="${id}Find" data-dojo-props="iconClass:'iconFind', showLabel: false" data-dojo-attach-event="onClick:_onFind" data-dojo-type="dijit.form.Button">Find</button>
+                </div>
+                <div class="seperator grey"></div>
+                <div id="userAccount">
+                    <span class="navBarLoggedin">logged in as:  </span>
+                    <a id="${id}UserID" href="#"></a>
+                </div>
+                <div class="seperator grey"></div>
+                <div id="${id}More" class="left glow" data-dojo-type="dijit.form.DropDownButton">
+                    <span>
+                        <img src="img/Info.png" alt="User" />
+                    </span>
+                    <div data-dojo-type="dijit.DropDownMenu">
+                        <div id="${id}Legacy" data-dojo-attach-event="onClick:_onOpenLegacy" data-dojo-type="dijit.MenuItem">Open Legacy ECL Watch</div>
+                        <span data-dojo-type="dijit.MenuSeparator"></span>
+                        <div id="${id}About" data-dojo-attach-event="onClick:_onAbout" data-dojo-type="dijit.MenuItem">About</div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div id="${id}TabContainer" style="width: 100%; height: 100%" data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.StackContainer">
+            <div id="${id}_Main" data-dojo-props="iconClass: 'iconLogo'" data-dojo-type="HPCCPlatformMainWidget">
+            </div>
+            <div id="${id}_ECL" data-dojo-props="iconClass: 'iconWu', showLabel: false" data-dojo-type="HPCCPlatformECLWidget">
+            </div>
+            <div id="${id}_Files" data-dojo-props="iconClass: 'iconLandingZone'" data-dojo-type="HPCCPlatformFilesWidget">
+            </div>
+            <div id="${id}_Queries" data-dojo-props="iconClass: 'iconTargets'" data-dojo-type="HPCCPlatformRoxieWidget">
+            </div>
+            <div id="${id}_OPS" data-dojo-props="iconClass: 'iconOperations'" data-dojo-type="HPCCPlatformOpsWidget">
+            </div>
+        </div>
+    </div>
+</div>

+ 0 - 5
esp/services/ws_fs/ws_fsBinding.hpp

@@ -66,11 +66,6 @@ public:
         ensureNavLink(*folder, "Spray XML", "/FileSpray/SprayVariableInput?submethod=xml", "Spray an XML File", NULL, NULL, 10);
         ensureNavLink(*folder, "Remote Copy", "/FileSpray/CopyInput", "Copy a Logical File from one environment to another", NULL, NULL, 11);
         ensureNavLink(*folder, "XRef", "/WsDFUXRef/DFUXRefList", "View Xref result details or run the Xref utility", NULL, NULL, 12);
-
-        IPropertyTree *folderTP = CEspBinding::ensureNavFolder(data, "Tech Preview", "Technical Preview");
-        CEspBinding::ensureNavLink(*folderTP, "DFU Workunits", "/esp/files/stub.htm?Widget=GetDFUWorkunitsWidget", "DFU Workunits", NULL, NULL, 2);
-        CEspBinding::ensureNavLink(*folderTP, "Logical Files", "/esp/files/stub.htm?Widget=DFUQueryWidget", "Logical Files", NULL, NULL, 3);
-        CEspBinding::ensureNavLink(*folderTP, "Landing Zones", "/esp/files/stub.htm?Widget=LZBrowseWidget", "Landing Zone Files", NULL, NULL, 4);
     }
 
     int onGetInstantQuery(IEspContext &context, CHttpRequest* request, CHttpResponse* response, const char *service, const char *method);

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

@@ -144,7 +144,8 @@ public:
             ensureNavLink(*folderQueryset, "Browse", "/WsWorkunits/WUQuerySets", "Browse Published Queries");
 
             IPropertyTree *folderTP = CEspBinding::ensureNavFolder(data, "Tech Preview", "Technical Preview");
-            CEspBinding::ensureNavLink(*folderTP, "ECL Workunits", "/esp/files/stub.htm?Widget=WUQueryWidget", "ECL Workunits", NULL, NULL, 1);
+            IPropertyTree *eclWatchTP = CEspBinding::ensureNavLink(*folderTP, "ECL Watch", "/esp/files/stub.htm?Widget=HPCCPlatformWidget", "ECL Watch", NULL, NULL, 1);
+            eclWatchTP->setProp("@target", "_blank");
         }
     }
 

+ 8 - 1
esp/xslt/nav.xsl

@@ -140,7 +140,14 @@
                 <a class="espnavlink">
                     <xsl:if test="@path">
                         <xsl:attribute name="href"><xsl:value-of select="@path"/></xsl:attribute>
-                        <xsl:attribute name="onclick">return gomain('<xsl:value-of select="@path"/>')</xsl:attribute>
+                        <xsl:choose>
+                            <xsl:when test="@target">
+                                <xsl:attribute name="target"><xsl:value-of select="@target"/></xsl:attribute>
+                            </xsl:when>
+                            <xsl:otherwise>
+                                <xsl:attribute name="onclick">return gomain('<xsl:value-of select="@path"/>')</xsl:attribute>
+                            </xsl:otherwise>
+                        </xsl:choose>
                     </xsl:if>
                     <xsl:if test="@tooltip">
                         <xsl:attribute name="alt"><xsl:value-of select="@tooltip"/></xsl:attribute>