Browse Source

HPCC-9671 Add Published Query Pages

Created a ESPQuery Singleton

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

+ 7 - 0
esp/files/css/hpcc.css

@@ -758,6 +758,13 @@ margin-left:-20px;
     display: inline-block;
 }
 
+.iconCluster{
+    background-image: url("../img/server.png"); 
+    width: 16px;
+    height: 16px;
+    display: inline-block;
+}
+
 .ErrorCell{
     background: red;
     color: white;

BIN
esp/files/img/active.png


BIN
esp/files/img/error.png


BIN
esp/files/img/inactive.png


BIN
esp/files/img/suspended.png


BIN
esp/files/img/unsuspended.png


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

@@ -118,7 +118,7 @@ define([
                 this.clearInput();
                 this.wu = ESPDFUWorkunit.Get(params.Wuid);
                 var data = this.wu.getData();
-                for (key in data) {
+                for (var key in data) {
                     this.updateInput(key, null, data[key]);
                 }
                 var context = this;

+ 136 - 0
esp/files/scripts/ESPQuery.js

@@ -0,0 +1,136 @@
+/*##############################################################################
+#    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/array",
+    "dojo/_base/lang",
+    "dojo/_base/Deferred",
+    "dojo/data/ObjectStore",
+    "dojo/store/util/QueryResults",
+    "dojo/store/Observable",
+    "dojo/Stateful",
+
+    "hpcc/WsWorkunits",
+    "hpcc/ESPRequest",
+    "hpcc/ESPUtil",
+    "hpcc/ESPResult"
+], function (declare, arrayUtil, lang, Deferred, ObjectStore, QueryResults, Observable, Stateful,
+        WsWorkunits, ESPRequest, ESPUtil, ESPResult) {
+
+    var _logicalFiles = {};
+
+    var Store = declare([ESPRequest.Store], {
+        service: "WsWorkunits",
+        action: "WUListQueries",
+        responseQualifier: "WUListQueriesResponse.QuerysetQueries.QuerySetQuery",
+        idProperty: "Id",
+        startProperty: "PageStartFrom",
+        countProperty: "NumberOfQueries",
+
+        _watched: [],
+        create: function (id) {
+            return new Query({
+                Id: 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 (oldValue !== newValue) {
+                        context.notify(storeItem, id);
+                    }
+                });
+            }
+        },
+
+        preProcessRow: function (item, request, query, options) {
+            var ErrorCount = 0;
+            var Suspended = false;
+            if (lang.exists("Clusters", item)) {
+                arrayUtil.forEach(item.Clusters.ClusterQueryState, function(cqs, idx){
+                    if (lang.exists("Errors", cqs) && cqs.Errors != null && cqs.Errors != "" && cqs.State == "Suspended"){
+                        ErrorCount++
+                        Suspended = true;
+                    }
+                });
+            }
+            lang.mixin(item, {
+                ErrorCount:ErrorCount,
+                Suspended: Suspended
+            });
+        }
+    });
+
+    var Query = declare([ESPUtil.Singleton], {
+        constructor: function (args) {
+            this.inherited(arguments);
+            if (args) {
+                declare.safeMixin(this, args);
+            }
+        },
+        refresh: function (full) {
+            return this.getDetails();
+        },
+        getDetails: function (args) {
+            var context = this;
+            return WsWorkunits.WUQueryDetails({
+                request:{
+                    QueryId: this.Id,
+                    QuerySet: this.QuerySetId
+                }
+            }).then(function (response) {
+                if (lang.exists("WUQueryDetailsResponse", response)) {
+                    context.updateData(response.WUQueryDetailsResponse);
+                }
+            });
+        },
+
+        doAction: function (action) {
+            var context = this;
+            return WsWorkunits.WUQuerysetQueryAction([{
+                QuerySetId: this.QuerySetId,
+                Id: this.Id,
+                Name: this.Name
+            }], action).then(function (responses) {
+                context.refresh();
+            });
+        },
+        setSuspended: function (suspended) {
+            return this.doAction(suspended ? "Suspend" : "Unsuspend");
+        },
+        setActivated: function (activated) {
+            return this.doAction(activated ? "Activate" : "Deactivate");
+        },
+        doDelete: function () {
+            return this.doAction("Delete");
+        }
+    });
+
+    return {
+        Get: function (Id) {
+            var store = new Store();
+            return store.get(Id);
+        },
+
+        CreateQueryStore: function (options) {
+            var store = new Store(options);
+            return new Observable(store);
+        }
+    };
+});

+ 5 - 2
esp/files/scripts/ESPRequest.js

@@ -343,13 +343,16 @@ define([
                 Deferred.when(results, function (response) {
                     var items = [];
                     if (context._hasResponseContent(response)) {
+                        if (context.preProcessFullResponse) {
+                            context.preProcessFullResponse(response, request, query, options);
+                        }
                         if (context.preProcessResponse) {
                             var responseQualiferArray = context.responseQualifier.split(".");
-                            context.preProcessResponse(lang.getObject(responseQualiferArray[0], false, response), request);
+                            context.preProcessResponse(lang.getObject(responseQualiferArray[0], false, response), request, query, options);
                         }
                         arrayUtil.forEach(context._getResponseContent(response), function (item, index) {
                             if (context.preProcessRow) {
-                                context.preProcessRow(item);
+                                context.preProcessRow(item, request, query, options);
                             }
                             var storeItem = context.get(context.getIdentity(item), item);
                             context.update(context.getIdentity(item), item);

+ 33 - 3
esp/files/scripts/GraphPageWidget.js

@@ -46,6 +46,7 @@ define([
     "hpcc/ESPWorkunit",
     "hpcc/TimingGridWidget",
     "hpcc/TimingTreeMapWidget",
+    "hpcc/WsWorkunits",
 
     "dojo/text!../templates/GraphPageWidget.html",
 
@@ -62,7 +63,7 @@ define([
             BorderContainer, TabContainer, ContentPane, registry, Dialog,
             entities,
             OnDemandGrid, Keyboard, Selection, selector, ColumnResizer, DijitRegistry,
-            _Widget, GraphWidget, ESPUtil, ESPWorkunit, TimingGridWidget, TimingTreeMapWidget,
+            _Widget, GraphWidget, ESPUtil, ESPWorkunit, TimingGridWidget, TimingTreeMapWidget, WsWorkunits,
             template) {
     return declare("GraphPageWidget", [_Widget], {
         templateString: template,
@@ -418,7 +419,7 @@ define([
                         onGetGraphs: function (graphs) {
                             if (firstLoad == true) {
                                 firstLoad = false;
-                                context.loadGraph(context.wu, context.graphName).then(function (response) {
+                                context.loadGraphFromWu(context.wu, context.graphName).then(function (response) {
                                     context.refresh(params);
                                 });
                             } else {
@@ -427,6 +428,12 @@ define([
                         }
                     });
                 });
+            } else if (params.QueryId) {
+                this.targetQuery = params.Target;
+                this.queryId = params.QueryId;
+                this.graphName = params.GraphName;
+
+                this.loadGraphFromQuery(this.targetQuery, this.queryId, this.graphName);
             }
 
             this.timingGrid.init(lang.mixin({
@@ -465,7 +472,7 @@ define([
             this.loadEdges();
         },
 
-        loadGraph: function (wu, graphName) {
+        loadGraphFromWu: function (wu, graphName) {
             var deferred = new Deferred();
             this.overview.setMessage("Fetching Data...");
             this.main.setMessage("Fetching Data...");
@@ -481,6 +488,29 @@ define([
             return deferred.promise;
         },
 
+        loadGraphFromQuery: function (targetQuery, queryId, graphName) {
+            this.overview.setMessage("Fetching Data...");
+            this.main.setMessage("Fetching Data...");
+            this.local.setMessage("Fetching Data...");
+            var context = this;
+            WsWorkunits.WUQueryGetGraph({
+                request: {
+                    Target: targetQuery,
+                    QueryId: queryId,
+                    GraphName: graphName
+                }
+            }).then(function(response){
+                context.overview.setMessage("");
+                context.main.setMessage("");
+                context.local.setMessage("");
+                if(lang.exists("WUQueryGetGraphResponse.Graphs.ECLGraphEx", response)){
+                    if(response.WUQueryGetGraphResponse.Graphs.ECLGraphEx.length > 0){
+                        context.loadGraphFromXGMML(response.WUQueryGetGraphResponse.Graphs.ECLGraphEx[0].Graph, "");
+                    }
+                }
+            });
+        },
+
         refreshGraph: function (wu, graphName) {
             var context = this;
             wu.fetchGraphXgmmlByName(graphName, function (xgmml) {

+ 55 - 17
esp/files/scripts/GraphsWidget.js

@@ -15,6 +15,7 @@
 ############################################################################## */
 define([
     "dojo/_base/declare",
+    "dojo/_base/lang",
     "dojo/_base/array",
     "dojo/on",
 
@@ -33,7 +34,7 @@ define([
     "hpcc/TimingTreeMapWidget",
     "hpcc/ESPUtil"
 
-], function (declare, arrayUtil, on,
+], function (declare, lang, arrayUtil, on,
                 Button,
                 OnDemandGrid, Keyboard, Selection, selector, ColumnResizer, DijitRegistry,
                 GridDetailsWidget, ESPWorkunit, GraphPageWidget, TimingTreeMapWidget, ESPUtil) {
@@ -43,6 +44,7 @@ define([
         idProperty: "Name",
 
         wu: null,
+        query: null,
 
         postCreate: function (args) {
             this.inherited(arguments);
@@ -60,16 +62,21 @@ define([
             if (this.inherited(arguments))
                 return;
 
+            var context = this;
             if (params.Wuid) {
                 this.wu = ESPWorkunit.Get(params.Wuid);
                 var monitorCount = 4;
-                var context = this;
                 this.wu.monitor(function () {
                     if (context.wu.isComplete() || ++monitorCount % 5 == 0) {
                         context.refreshGrid();
                     }
                 });
             }
+            else if (params.Query){
+                this.query = params.Query;
+                this.refreshGrid();
+            }
+
             this.timingTreeMap.init(params);
             this.timingTreeMap.onClick = function (value) {
                 context.syncSelectionFrom(context.timingTreeMap);
@@ -130,33 +137,64 @@ define([
         },
 
         createDetail: function (id, row, params) {
+            var localParams = {}
+            if (this.wu) {
+                localParams = {
+                    Wuid: this.wu.Wuid,
+                    GraphName: row.Name,
+                    GraphName: row.Name,
+                    SubGraphId: (params && params.SubGraphId) ? params.SubGraphId : null,
+                    SafeMode: (params && params.safeMode) ? true : false
+                }
+            } else if (this.query) {
+                localParams = {
+                    Target: this.query.QuerySet,
+                    QueryId: this.query.QueryId,
+                    GraphName: row.Name,
+                    SubGraphId: (params && params.SubGraphId) ? params.SubGraphId : null,
+                    SafeMode: (params && params.safeMode) ? true : false
+                }
+            }
             return new GraphPageWidget({
                 id: id,
                 title: row.Name,
                 closable: true,
                 hpcc: {
                     type: "graph",
-                    params: {
-                        Wuid: this.wu.Wuid,
-                        GraphName: row.Name,
-                        SubGraphId: (params && params.SubGraphId) ? params.SubGraphId : null,
-                        SafeMode: (params && params.safeMode) ? true : false
-                    }
+                    params: localParams
                 }
             });
         },
 
         refreshGrid: function (args) {
-            var context = this;
-            this.wu.getInfo({
-                onGetTimers: function (timers) {
-                    //  Required to calculate Graphs Total Time  ---
-                },
-                onGetGraphs: function (graphs) {
-                    context.store.setData(graphs);
-                    context.grid.refresh();
+            if (this.wu) {
+                var context = this;
+                this.wu.getInfo({
+                    onGetTimers: function (timers) {
+                        //  Required to calculate Graphs Total Time  ---
+                    },
+                    onGetGraphs: function (graphs) {
+                        context.store.setData(graphs);
+                        context.grid.refresh();
+                    }
+                });
+            } else if (this.query) {
+                var graphs = [];
+                if (lang.exists("GraphIds.Item", this.query)) {
+                    arrayUtil.forEach(this.query.GraphIds.Item, function (item, idx) {
+                        var graph = {
+                            Name: item,
+                            Label: "",
+                            Completed: "",
+                            Time: 0,
+                            Type: ""
+                        };
+                        graphs.push(graph);
+                    });
                 }
-            });
+                this.store.setData(graphs);
+                this.grid.refresh();
+            }
         },
 
         refreshActionState: function (selection) {

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

@@ -52,8 +52,8 @@ define([
 
         //  Implementation  ---
         init: function (params) {
-                if (this.inherited(arguments))
-                    return;
+            if (this.inherited(arguments))
+                return;
             this.initTab();
         },
 

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

@@ -1,17 +1,17 @@
 /*##############################################################################
-#	HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
+#   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
+#   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
+#      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.
+#   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",
@@ -19,7 +19,8 @@ define([
     "dijit/registry",
 
     "hpcc/_TabContainerWidget",
-    "hpcc/ESPRequest",
+    "hpcc/QuerySetQueryWidget",
+    "hpcc/PackageMapQueryWidget",
 
     "dojo/text!../templates/HPCCPlatformRoxieWidget.html",
 
@@ -29,7 +30,7 @@ define([
 
 ], function (declare,
                 registry,
-                _TabContainerWidget, ESPRequest,
+                _TabContainerWidget, QuerySetQueryWidget, PackageMapQueryWidget,
                 template) {
     return declare("HPCCPlatformRoxieWidget", [_TabContainerWidget], {
         templateString: template,
@@ -53,20 +54,13 @@ define([
         init: function (params) {
             if (this.inherited(arguments))
                 return;
-
             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) {
+                if (currSel.init) {
                     currSel.init({});
                 }
             }

+ 234 - 0
esp/files/scripts/QuerySetDetailsWidget.js

@@ -0,0 +1,234 @@
+/*##############################################################################
+#   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-attr",
+    "dojo/dom-class",
+    "dojo/query",
+    "dojo/store/Memory",
+    "dojo/store/Observable",
+    "dojo/promise/all",
+
+    "dijit/registry",
+
+    "dgrid/OnDemandGrid",
+    "dgrid/Keyboard",
+    "dgrid/Selection",
+    "dgrid/selector",
+    "dgrid/extensions/ColumnResizer",
+    "dgrid/extensions/DijitRegistry",
+
+    "hpcc/ESPWorkunit",
+    "hpcc/ESPQuery",
+    "hpcc/WsWorkunits",
+    "hpcc/_TabContainerWidget",
+    "hpcc/QuerySetLogicalFilesWidget",
+    "hpcc/QuerySetErrorsWidget",
+
+    "dojo/text!../templates/QuerySetDetailsWidget.html",
+
+    "dijit/layout/BorderContainer",
+    "dijit/layout/TabContainer",
+    "dijit/layout/ContentPane",
+    "dijit/form/Textarea",
+    "dijit/form/Button",
+    "dijit/form/CheckBox",
+    "dijit/Toolbar",
+    "dijit/ToolbarSeparator",
+    "dijit/TooltipDialog",
+    "dijit/TitlePane",
+
+    "hpcc/WUDetailsWidget"
+
+], function (declare, lang, dom, domAttr, domClass, query, Memory, Observable, all,
+                registry,
+                OnDemandGrid, Keyboard, Selection, selector, ColumnResizer, DijitRegistry,
+                ESPWorkunit, ESPQuery, WsWorkunits, _TabContainerWidget, QuerySetLogicalFilesWidget, QuerySetErrorsWidget,
+                template) {
+    return declare("QuerySetDetailsWidget", [_TabContainerWidget], {
+        templateString: template,
+        baseClass: "QuerySetDetailsWidget",
+        
+        query: null,
+
+        initalized: false,
+        summaryTab: null,
+        summaryTabLoaded:false,
+        errorsTab: null,
+        errorsTabLoaded: false,
+        graphsTab: null,
+        graphsTabLoaded: false,
+        logicalFilesTab: null,
+        logicalFilesTabLoaded: false,
+        superFilesTab: false,
+        superFilesTabLoaded: null,
+        workunitsTab: null,
+        workunitsTabLoaded: false,
+        loaded:false,
+
+        postCreate: function (args) {
+            this.inherited(arguments);
+            this.summaryTab = registry.byId(this.id + "_Summary");
+            this.errorsTab = registry.byId(this.id + "_Errors");
+            this.graphsTab = registry.byId(this.id + "_Graphs");
+            this.logicalFilesTab = registry.byId(this.id + "_QuerySetLogicalFiles");
+            this.superFilesTab = registry.byId(this.id + "_QuerySetSuperFiles");
+            this.workunitsTab = registry.byId(this.id + "_Workunit");
+        },
+
+        //  Hitched actions  ---
+        _onSave: function (event) {
+            var suspended = registry.byId(this.id + "Suspended").get("value");
+            var activated = registry.byId(this.id + "Activated").get("value");
+            var context = this;
+            all({
+                suspend: this.query.setSuspended(suspended),
+                activate: this.query.setActivated(activated)
+            });
+        },
+        _onDelete: function (event) {
+            if (confirm('Delete selected workunits?')) {
+                this.query.doDelete();
+            }
+        },
+        _onRefresh: function () {
+            this.query.refresh();
+        },
+
+        //  Implementation  ---
+        init: function (params) {
+            if (this.inherited(arguments))
+                return;
+
+            this.query = ESPQuery.Get(params.Id);
+
+            var context = this;
+            var data = this.query.getData();
+            for (key in data) {
+                this.updateInput(key, null, data[key]);
+            }
+            this.query.watch(function (name, oldValue, newValue) {
+                context.updateInput(name, oldValue, newValue);
+            });
+            this.query.refresh();
+
+            this.selectChild(this.summaryWidget, true);
+        },
+
+        initTab: function () {
+            var currSel = this.getSelectedChild();
+            if (currSel.id == this.summaryTab.id && !this.summaryTabLoaded) {
+                this.summaryTabLoaded = true;
+            } else if (currSel.id == this.workunitsTab.id && !this.workunitsTabLoaded) {
+                this.workunitsTabLoaded = true;
+                this.workunitsTab.init({
+                    Wuid: this.query.Wuid
+                });
+            } else if (currSel.id == this.errorsTab.id && !this.errorsTabLoaded) {
+                this.errorsTabLoaded = true;
+                this.errorsTab.init({
+                    Query: this.query
+                });
+            } else if (currSel.id == this.graphsTab.id && !this.graphsTabLoaded) {
+                this.graphsTabLoaded = true;
+                this.graphsTab.init({
+                    Query: this.query
+                });
+            } else if (currSel.id == this.logicalFilesTab.id && !this.logicalFilesTabLoaded) {
+                this.logicalFilesTabLoaded = true;
+                this.logicalFilesTab.init({
+                    QueryId: this.query.Id,
+                    QuerySet: this.query.QuerySet,
+                    Query: this.query
+                });
+            }
+        },
+
+        updateInput: function (name, oldValue, newValue) {
+           var registryNode = registry.byId(this.id + name);
+            if (registryNode) {
+                registryNode.set("value", newValue);
+            } else {
+                var domElem = dom.byId(this.id + name);
+                if (domElem) {
+                    switch (domElem.tagName) {
+                        case "SPAN":
+                        case "DIV":
+                            domAttr.set(this.id + name, "innerHTML", newValue);
+                            break;
+                        case "INPUT":
+                        case "TEXTAREA":
+                            domAttr.set(this.id + name, "value", newValue);
+                            break;
+                        default:
+                            alert(domElem.tagName);
+                            break;
+                    }
+                }
+            }
+            if (name === "Wuid") {
+                this.workunitsTab.set("title", newValue);
+            }
+            if (name === "Suspended") {
+                dom.byId(this.id + "SuspendImg").src = newValue ? "img/suspended.png" : "img/unsuspended.png";
+            }
+            if (name === "Activated") {
+                dom.byId(this.id + "ActiveImg").src = newValue ? "img/active.png" : "img/inactive.png";
+            }
+
+            else if (name === "CountGraphs" && newValue) {
+                this.graphsTab.set("title", "Graphs " + "(" + newValue + ")");
+            } else if (name === "graphs") {
+                this.graphsTab.set("title", "Graphs " + "(" + newValue.length + ")");
+                var tooltip = "";
+                for (var i = 0; i < newValue.length; ++i) {
+                    if (tooltip != "")
+                        tooltip += "\n";
+                    tooltip += newValue[i].Name;
+                    if (newValue[i].Time)
+                        tooltip += " " + newValue[i].Time;
+                }
+                this.graphsTab.set("tooltip", tooltip);
+            }
+            else if (name === "LogicalFiles") {
+                if (lang.exists("Item.length", newValue)) {
+                    this.logicalFilesTab.set("title", "Logical Files " + "(" + newValue.Item.length + ")");
+                    var tooltip = "";
+                    for (var i = 0; i < newValue.Item.length; ++i) {
+                        if (tooltip != "")
+                            tooltip += "\n";
+                        tooltip += newValue.Item[i];
+                    }
+                    this.logicalFilesTab.set("tooltip", tooltip);
+                }
+            }
+            else if (name === "Clusters") {
+                if (lang.exists("ClusterQueryState.length", newValue)) {
+                    this.errorsTab.set("title", "Errors / Status " + "(" + newValue.ClusterQueryState.length + ")");
+                    var tooltip = "";
+                    for (var i = 0; i < newValue.ClusterQueryState.length; ++i) {
+                        if (tooltip != "")
+                            tooltip += "\n";
+                        tooltip += newValue.ClusterQueryState[i].Cluster + " (" + newValue.ClusterQueryState[i].State + ")";
+                    }
+                    this.errorsTab.set("tooltip", tooltip);
+                }
+            }
+        }
+    });
+});

+ 93 - 0
esp/files/scripts/QuerySetErrorsWidget.js

@@ -0,0 +1,93 @@
+/*##############################################################################
+#    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/array",
+    "dojo/_base/lang",
+    "dojo/on",
+
+    "dgrid/OnDemandGrid",
+    "dgrid/Keyboard",
+    "dgrid/Selection",
+    "dgrid/selector",
+    "dgrid/extensions/ColumnResizer",
+    "dgrid/extensions/DijitRegistry",
+
+    "hpcc/GridDetailsWidget",
+    "hpcc/WsWorkunits",
+    "hpcc/ESPUtil"
+], function (declare, arrayUtil, lang, on,
+                OnDemandGrid, Keyboard, Selection, selector, ColumnResizer, DijitRegistry,
+                GridDetailsWidget, WsWorkunits, ESPUtil) {
+    return declare("QuerySetErrorsWidget", [GridDetailsWidget], {
+
+        gridTitle: "Errors",
+        idProperty: "Name",
+
+        queryId: null,
+        querySet: null,
+
+        init: function (params) {
+            if (this.inherited(arguments))
+                return;
+        
+            this.refreshGrid();
+            //disabled buttons for now since we cannot open an error atm 
+            
+        },
+
+        createGrid: function (domID) {
+            var context = this;
+            var retVal = new declare([OnDemandGrid, Keyboard, Selection, ColumnResizer, DijitRegistry, ESPUtil.GridHelper])({
+                allowSelectAll: true,
+                deselectOnRefresh: false,
+                store: this.store,
+                columns: {
+                    col1: selector({ width: 27, selectorType: 'checkbox' }),
+                    Cluster: { label: "Cluster", width: 108, sortable: false },
+                    Errors: { label: "Error", width: 108, sortable: false },
+                    State: { label: "State", width: 108, sortable: false },
+
+                }
+            }, domID);
+
+            on(document, "." + this.id + "WuidClick:click", function (evt) {
+                if (context._onRowDblClick) {
+                    var row = retVal.row(evt).data;
+                    context._onRowDblClick(row);
+                }
+            });
+            return retVal;
+        },
+
+        refreshGrid: function (args) {
+            var errors = [];
+            if (lang.exists("params.Query.Clusters.ClusterQueryState", this)) {
+                var context = this;
+                arrayUtil.forEach(this.params.Query.Clusters.ClusterQueryState, function (item, idx) {
+                    var error = {
+                        Cluster: item.Cluster,
+                        Errors: item.Error,
+                        State: item.State
+                    }
+                    errors.push(error);
+                });
+            }
+            this.store.setData(errors);
+            this.grid.refresh();
+        }
+    });
+});

+ 92 - 0
esp/files/scripts/QuerySetLogicalFilesWidget.js

@@ -0,0 +1,92 @@
+/*##############################################################################
+#    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/array",
+    "dojo/_base/lang",
+    "dojo/on",
+
+    "dgrid/OnDemandGrid",
+    "dgrid/Keyboard",
+    "dgrid/Selection",
+    "dgrid/selector",
+    "dgrid/extensions/ColumnResizer",
+    "dgrid/extensions/DijitRegistry",
+
+    "hpcc/GridDetailsWidget",
+    "hpcc/WsWorkunits",
+    "hpcc/ESPUtil"
+], function (declare, arrayUtil, lang, on,
+                OnDemandGrid, Keyboard, Selection, selector, ColumnResizer, DijitRegistry,
+                GridDetailsWidget, WsWorkunits, ESPUtil) {
+    return declare("QuerySetLogicalFilesWidget", [GridDetailsWidget], {
+
+        gridTitle: "Logical Files",
+        idProperty: "Name",
+
+        queryId: null,
+        querySet: null,
+
+        init: function (params) {
+            if (this.inherited(arguments))
+                return;
+
+            if (params.Query) {
+                this.query = params.Query
+            }
+
+            this.refreshGrid();
+        },
+
+        createGrid: function (domID) {
+            var context = this;
+            var retVal = new declare([OnDemandGrid, Keyboard, Selection, ColumnResizer, DijitRegistry, ESPUtil.GridHelper])({
+                allowSelectAll: true,
+                deselectOnRefresh: false,
+                store: this.store,
+                columns: {
+                    col1: selector({ width: 27, selectorType: 'checkbox' }),
+                    Name: { label: "Logical Files", width: 108, sortable: false },
+                }
+            }, domID);
+
+            on(document, "." + this.id + "WuidClick:click", function (evt) {
+                if (context._onRowDblClick) {
+                    var row = retVal.row(evt).data;
+                    context._onRowDblClick(row);
+                }
+            });
+            return retVal;
+        },
+
+        refreshGrid: function (args) {
+            if (this.query) {
+                var logicalFiles = [];
+                if (lang.exists("Query.LogicalFiles.Item", this.query)) {
+                    var context = this;
+                    arrayUtil.forEach(this.query.LogicalFiles.Item, function (item, idx) {
+                        var file = {
+                            Name: item
+                        }
+                        logicalFiles.push(file);
+                    });
+                }
+                this.store.setData(logicalFiles);
+                this.grid.refresh();
+            }
+        }
+    });
+});

+ 498 - 0
esp/files/scripts/QuerySetQueryWidget.js

@@ -0,0 +1,498 @@
+/*##############################################################################
+#    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-form",
+    "dojo/request/iframe",
+    "dojo/_base/array",
+    "dojo/on",
+
+    "dijit/registry",
+    "dijit/Menu",
+    "dijit/MenuItem",
+    "dijit/MenuSeparator",
+    "dijit/PopupMenuItem",
+
+    "dgrid/OnDemandGrid",
+    "dgrid/Keyboard",
+    "dgrid/Selection",
+    "dgrid/selector",
+    "dgrid/extensions/ColumnResizer",
+    "dgrid/extensions/DijitRegistry",
+    "dgrid/extensions/Pagination",
+
+    "hpcc/_TabContainerWidget",
+    "hpcc/ESPBase",
+    "hpcc/ESPWorkunit",
+    "hpcc/ESPLogicalFile",
+    "hpcc/TargetSelectWidget",
+    "hpcc/QuerySetDetailsWidget",
+    "hpcc/WsWorkunits",
+    "hpcc/ESPQuery",
+    "hpcc/ESPUtil",
+
+    "dojo/text!../templates/QuerySetQueryWidget.html",
+
+    "dijit/layout/BorderContainer",
+    "dijit/layout/TabContainer",
+    "dijit/layout/ContentPane",
+    "dijit/Toolbar",
+    "dijit/form/Form",
+    "dijit/form/Button",
+    "dijit/form/CheckBox",
+    "dijit/ToolbarSeparator",
+    "dijit/form/TextBox",
+    "dijit/Dialog",
+    "dijit/form/DropDownButton",
+    "dijit/TooltipDialog",
+
+    "dojox/layout/TableContainer"
+], function (declare, lang, dom, domForm, iframe, arrayUtil, on,
+                registry, Menu, MenuItem, MenuSeparator, PopupMenuItem,
+                OnDemandGrid, Keyboard, Selection, selector, ColumnResizer, DijitRegistry, Pagination,
+                _TabContainerWidget, ESPBase, ESPWorkunit, ESPLogicalFile, TargetSelectWidget, QuerySetDetailsWidget, WsWorkunits, ESPQuery, ESPUtil,
+                template) {
+    return declare("QuerySetQueryWidget", [_TabContainerWidget], {
+        templateString: template,
+        baseClass: "QuerySetQueryWidget",
+
+        borderContainer: null,
+        queriesTab: null,
+        querySetGrid: null,
+        clusterTargetSelect: null,
+
+        initalized: false,
+        loaded: false,
+
+        buildRendering: function (args) {
+            this.inherited(arguments);
+        },
+
+        postCreate: function (args) {
+            this.inherited(arguments);
+            this.queriesTab = registry.byId(this.id + "_Queries");
+            this.clusterTargetSelect = registry.byId(this.id + "ClusterTargetSelect");
+            this.borderContainer = registry.byId(this.id + "BorderContainer");
+        },
+
+        startup: function (args) {
+            this.inherited(arguments);
+            this.initContextMenu();
+        },
+
+        resize: function (args) {
+            this.inherited(arguments);
+            this.borderContainer.resize();
+        },
+
+        layout: function (args) {
+            this.inherited(arguments);
+        },
+
+        destroy: function (args) {
+            this.inherited(arguments);
+        },
+
+        init: function (params) {
+            if (this.inherited(arguments))
+                return;
+
+            var context = this;
+            var firstCall = true;
+            this.clusterTargetSelect.init({
+                Targets: true,
+                includeBlank: true,
+                Target: params.Cluster,
+            });
+            this.initQuerySetGrid();
+            this.selectChild(this.queriesTab, true);
+        },
+
+        initTab: function () {
+            var currSel = this.getSelectedChild();
+            if (currSel && !currSel.initalized) {
+                if (currSel.id == this.queriesTab.id) {
+                } else {
+                    currSel.init(currSel.hpcc.params);
+                }
+            }
+        },
+
+         addMenuItem: function (menu, details) {
+            var menuItem = new MenuItem(details);
+            menu.addChild(menuItem);
+            return menuItem;
+        },
+
+        initContextMenu: function ( ) {
+            var context = this;
+            var pMenu = new Menu({
+                targetNodeIds: [this.id + "QuerySetGrid"]
+            });
+             this.menuOpen = this.addMenuItem(pMenu, {
+                label: "Open",
+                onClick: function () { context._onOpen(); }
+            });
+            this.menuDelete = this.addMenuItem(pMenu, {
+                label: "Delete",
+                onClick: function () { context._onDelete(); }
+            });
+             pMenu.addChild(new MenuSeparator());
+            this.menuUnsuspend = this.addMenuItem(pMenu, {
+                label: "Unsuspend",
+                onClick: function () { context._onUnsuspend(); }
+            });
+            this.menuSuspend= this.addMenuItem(pMenu, {
+                label: "Suspend",
+                onClick: function () { context._onSuspend(); }
+            });
+             pMenu.addChild(new MenuSeparator());
+            this.menuActivate = this.addMenuItem(pMenu, {
+                label: "Activate",
+                onClick: function () { context._onActivate(); }
+            });
+            this.menuDeactivate = this.addMenuItem(pMenu, {
+                label: "Deactivate",
+                onClick: function () { context._onDeactivate(); }
+            });
+            pMenu.addChild(new MenuSeparator());
+            {
+                var pSubMenu = new Menu();
+                /*
+                this.menuFilterCluster = this.addMenuItem(pSubMenu, {
+                    onClick: function (args) {
+                        context.clearFilter();
+                        registry.byId(context.id + "ClusterTargetSelect").set("value", context.menuFilterCluster.get("hpcc_value"));
+                        context._onFilterApply();
+                    }
+                });*/
+                this.menuFilterSuspend = this.addMenuItem(pSubMenu, {
+                    onClick: function (args) {
+                        context.clearFilter();
+                        registry.byId(context.id + "Suspended").set("value", context.menuFilterSuspend.get("hpcc_value"));
+                        context._onFilterApply();
+                    }
+                });
+                pSubMenu.addChild(new MenuSeparator());
+                this.menuFilterClearFilter = this.addMenuItem(pSubMenu, {
+                    label: "Clear",
+                    onClick: function () {
+                        context._onFilterClear();
+                    }
+                });
+                pMenu.addChild(new PopupMenuItem({
+                    label: "Filter",
+                    popup: pSubMenu
+                }));
+            }
+            pMenu.startup();
+        },
+
+        /*Not Applicable*/
+        _onRowContextMenu: function (item, colField, mystring) {
+            this.menuFilterSuspend.set("disabled", false);
+            //this.menuFilterCluster.set("disabled", false);
+            //this.menuFilterUnsuspend.set("disabled", false);
+            //this.menuFilterActive.set("disabled", false);
+            //this.menuFilterDeactive.set("disabled", false);
+
+            if (item) {
+                /*this.menuFilterCluster.set("label", "Cluster: " + item.QuerySetName);
+                this.menuFilterCluster.set("hpcc_value", item.QuerySetName);*/
+                this.menuFilterSuspend.set("label", "Suspend:  " + item.Suspended);
+                this.menuFilterSuspend.set("hpcc_value", item.Suspended);
+                /*
+                this.menuFilterUnsuspend.set("label", "Unsuspend:  " + item.Suspend);
+                this.menuFilterUnsuspend.set("hpcc_value", item.Suspend);
+                this.menuFilterActive.set("label", "Active:  " + item.Active);
+                this.menuFilterActive.set("hpcc_value", item.Active);
+                this.menuFilterDeactivate.set("label", "Deactivate:  " + item.Active);
+                this.menuFilterDeactivate.set("hpcc_value", item.Active);
+            }
+            if (item.Cluster == "") {
+                this.menuFilterCluster.set("disabled", true);
+                this.menuFilterCluster.set("label", "Cluster: " + "N/A");
+            }*/
+            
+            if (item.Suspend == "") {
+                this.menuFilterSuspend.set("disabled", true);
+                this.menuFilterSuspend.set("label", "Suspend: " + "N/A");
+            }
+            /*
+            if (item.Suspend == true) {
+                this.menuFilterUnsuspend.set("disabled", false);
+                this.menuFilterUnsuspend.set("label", "Unsuspend:  " + "N/A");
+            }
+            if (item.Active == false) {
+                this.menuFilterActive.set("disabled", true);
+                this.menuFilterActive.set("label", "Active:  " + "N/A");
+            }
+            if (item.Active == true) {
+                this.menuFilterState.set("disabled", false);
+                this.menuFilterState.set("label", "Deactivate:  " + "N/A");*/
+            }
+        },
+
+        initQuerySetGrid: function (params) {
+            var context = this;
+            var store = ESPQuery.CreateQueryStore();
+            this.querySetGrid = declare([OnDemandGrid, Keyboard, Selection, ColumnResizer, DijitRegistry, ESPUtil.GridHelper])({
+                allowSelectAll: true,
+                deselectOnRefresh: false,
+                store: store,
+                columns: {
+                    col1: selector({
+                        width: 27,
+                        selectorType: 'checkbox'
+                    }),
+                    Suspended: {
+                        renderHeaderCell: function (node) {
+                            node.innerHTML = "<img src='../files/img/suspended.png'>";
+                        },
+                        width: 18,
+                        sortable: false,
+                        formatter: function (suspended) {
+                            if (suspended == true) {
+                                return ("<img src='../files/img/suspended.png'>");
+                            }
+                            return "";
+                        }
+                    },
+                    Activated: {
+                        renderHeaderCell: function (node) {
+                            node.innerHTML = "<img src='../files/img/active.png'>";
+                        },
+                        width: 18,
+                        sortable: false,
+                        formatter: function (activated) {
+                            if (activated == true) {
+                                return ("<img src='../files/img/active.png'>");
+                            }
+                            return "";
+                        }
+                    },
+                    ErrorCount: {
+                        renderHeaderCell: function (node) {
+                            node.innerHTML = "<img src='../files/img/error.png'>";
+                        },
+                        width: 18,
+                        sortable: false,
+                        formatter: function (error) {
+                            if (error > 0) {
+                                return ("<img src='../files/img/error.png'>");
+                            }
+                            return "";
+                        }
+                    },
+                    Id: {
+                        width: 220,
+                        label: "Id",
+                        formatter: function (Id, idx) {
+                            return "<a href='#' rowIndex=" + idx + " class='" + context.id + "WuidClick'>" + Id + "</a>";
+                        }
+                    },
+                    Name: {
+                        width: 180,
+                        label: "Name"
+                    },
+                    QuerySetId:{
+                        width: 180,
+                        label: "Target"
+                    },
+                    Wuid: {
+                        width: 180,
+                        label: "Wuid"
+                    },
+                     Dll: {
+                        width: 180,
+                        label: "Dll"
+                    },
+                    Priority: {
+                        width: 100,
+                        label: "Priority"
+                    },
+                    IsLibrary: {
+                        width: 100,
+                        label: "Is Library"
+                    },
+                    PublishedBy: {
+                        width: 180,
+                        label: "Published By"
+                    },
+                },
+            },
+            this.id + "QuerySetGrid");
+            //this.querySetGrid.set("noDataMessage", "<span class='dojoxGridNoData'>Zero Workunits (check filter).</span>");
+            on(document, "." + context.id + "WuidClick:click", function (evt) {
+                if (context._onRowDblClick) {
+                    var item = context.querySetGrid.row(evt).data;
+                    context._onRowDblClick(item);
+                }
+            });
+             this.querySetGrid.on(".dgrid-row:dblclick", function (evt) {
+                if (context._onRowDblClick) {
+                    var item = context.querySetGrid.row(evt).data;
+                    context._onRowDblClick(item);
+                }
+            });
+             this.querySetGrid.on(".dgrid-row:contextmenu", function (evt) {
+                if (context._onRowContextMenu) {
+                    var item = context.querySetGrid.row(evt).data;
+                    var cell = context.querySetGrid.cell(evt);
+                    var colField = cell.column.field;
+                    var mystring = "item." + colField;
+                    context._onRowContextMenu(item, colField, mystring);
+                }
+            });
+            this.querySetGrid.onSelectionChanged(function (event) {
+                context.refreshActionState();
+            });
+            this.querySetGrid.onContentChanged(function (event) {
+                context.refreshActionState();
+            });
+            this.querySetGrid.startup();
+            this.refreshActionState();
+        },
+
+        refreshActionState: function () {
+            var selection = this.querySetGrid.getSelected();
+            var hasSelection = false;
+            var isSuspended = false;
+            var isNotSuspended = false;
+            for (var i = 0; i < selection.length; ++i) {
+                hasSelection = true;
+                if (selection[i].Suspended != true) {
+                    isSuspended = true;
+                } else {
+                    isNotSuspended = true;
+                }
+            }
+
+            registry.byId(this.id + "Delete").set("disabled", !hasSelection);
+            registry.byId(this.id + "unSuspend").set("disabled", !isNotSuspended);
+            registry.byId(this.id + "onSuspend").set("disabled", !isSuspended);
+            registry.byId(this.id + "Activate").set("disabled", !hasSelection);
+            registry.byId(this.id + "Deactivate").set("disabled", !hasSelection);
+            registry.byId(this.id + "Open").set("disabled", !hasSelection);
+        },
+
+        _onRefresh: function (params) {
+           this.refreshGrid();
+        },
+
+        _onFilterClear: function(event) {
+            this.clearFilter();
+            this.refreshGrid();
+        },
+
+        clearFilter: function () {
+            arrayUtil.forEach(registry.byId(this.id + "FilterForm").getDescendants(), function (item, idx) {
+                item.set('value', null);
+            });
+        },
+
+        _onFilterApply: function(){
+            this.querySetGrid.set("query", this.getFilter());
+        },
+
+        _onDelete:function(){
+            if (confirm('Delete Selected Queries?')) {
+                var context = this;
+                WsWorkunits.WUQuerysetQueryAction(this.querySetGrid.getSelected(), "Delete").then(function (response) {
+                    context.refreshGrid();
+                });
+            }
+        },
+        
+        refreshGrid: function (args) {
+            this.querySetGrid.set("query", this.getFilter());
+        },
+
+        _onSuspend: function(){
+           var context = this;
+           WsWorkunits.WUQuerysetQueryAction(this.querySetGrid.getSelected(), "Suspend").then(function (response) {
+               context.refreshGrid();
+           });
+        },
+
+        _onUnsuspend: function (){
+            var context = this;
+            WsWorkunits.WUQuerysetQueryAction(this.querySetGrid.getSelected(), "Unsuspend").then(function (response) {
+                context.refreshGrid();
+            });
+        },
+
+        _onActivate: function(){
+            var context = this;
+            WsWorkunits.WUQuerysetQueryAction(this.querySetGrid.getSelected(), "Activate").then(function (response) {
+                context.refreshGrid();
+            });
+        },
+
+         _onDeactivate: function(){
+            var context = this;
+            WsWorkunits.WUQuerysetQueryAction(this.querySetGrid.getSelected(), "Deactivate").then(function (response) {
+                context.refreshGrid();
+            });
+        },
+
+        _onOpen: function(){
+            var selections = this.querySetGrid.getSelected();
+            var firstTab = null;
+            for (var i = selections.length - 1; i >= 0; --i) {
+                var tab = this.ensurePane(this.id + "_" + selections[i].Id, selections[i]);
+                if (i == 0) {
+                    firstTab = tab;
+                }
+            }
+            if (firstTab) {
+                this.selectChild(firstTab);
+            }
+        },
+
+        _onRowDblClick: function (item) {
+            var wuTab = this.ensurePane(this.id + "_" + item.Id, item);
+            this.selectChild(wuTab);
+        },
+
+        getFilter: function(){
+            var context = this;
+            var retVal = domForm.toObject(this.id + "FilterForm");
+            return retVal;
+        },
+
+        ensurePane: function (id, params) {
+            id = id.split(".").join("x");
+            var retVal = registry.byId(id);
+            if (!retVal) {
+                var context = this;
+                retVal = new QuerySetDetailsWidget({
+                    id: id,
+                    title: params.Id,
+                    closable: true,
+                    hpcc: {
+                        type: "QuerySetDetailsWidget",
+                        params: params
+                    }
+                });
+                this.addChild(retVal, 1);
+            }
+            return retVal;
+        }
+    });
+});

+ 138 - 0
esp/files/scripts/QuerySetSuperFilesWidget.js

@@ -0,0 +1,138 @@
+/*##############################################################################
+#    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/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/ESPQuery",
+    "hpcc/ESPUtil"
+
+], function (declare, arrayUtil, on,
+                Button,
+                OnDemandGrid, Keyboard, Selection, selector, ColumnResizer, DijitRegistry,
+                GridDetailsWidget, ESPWorkunit, ESPQuery, ESPUtil) {
+    return declare("QuerySetSuperFilesWidget", [GridDetailsWidget], {
+
+        gridTitle: "Super Files",
+        idProperty: "Name",
+
+        wu: null,
+        query: null,
+
+
+        init: function (params) {
+           if (this.inherited(arguments))
+                return;
+
+            this._refreshActionState();
+        },
+
+         createGrid: function (domID) {
+            var context = this;
+            var retVal = new declare([OnDemandGrid, Keyboard, Selection, ColumnResizer, DijitRegistry, ESPUtil.GridHelper])({
+                allowSelectAll: true,
+                deselectOnRefresh: false,
+                store: ESPQuery.CreateQueryStore(),
+                columns: {
+                    col1: selector({ width: 27, selectorType: 'checkbox' }),
+                    /*Item: {
+                        label: "File", 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>";
+                        }
+
+                    },*/
+                    LogicalFiles: { label: "Logical Files", width: 108, sortable: false },
+                    /*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
+                    }
+                }
+            });
+        },
+
+        
+
+        refreshGrid: function (args) {
+            var context = this;
+            this.wu.getInfo({
+                onGetTimers: function (timers) {
+                    //  Required to calculate Graphs Total Time  ---
+                },
+                onGetGraphs: function (graphs) {
+                    context.store.setData(graphs);
+                    context.grid.refresh();
+                }
+            });
+        },
+
+        refreshActionState: function (selection) {
+            this.inherited(arguments);
+
+            this.openSafeMode.set("disabled", !selection.length);
+        }
+    });
+});

+ 56 - 6
esp/files/scripts/WsWorkunits.js

@@ -17,10 +17,13 @@ define([
     "dojo/_base/declare",
     "dojo/_base/lang",
     "dojo/_base/array",
+    "dojo/promise/all",
+    "dojo/store/Observable",
     
     "hpcc/ESPRequest"
-], function (declare, lang, arrayUtil,
+], function (declare, lang, arrayUtil, all, Observable,
     ESPRequest) {
+
     return {
         States: {
             0: "unknown",
@@ -58,6 +61,50 @@ define([
             return ESPRequest.send("WsWorkunits", "WUResubmit", params);
         },
 
+        WUQueryDetails: function (params) {
+            return ESPRequest.send("WsWorkunits", "WUQueryDetails", params);
+        },
+
+        WUQuerysetAliasAction: function (selection, action) {
+            var requests = [];
+            arrayUtil.forEach(selection, function (item, idx) {
+                var request = {
+                    QuerySetName: item.QuerySetId,
+                    Action: action,
+                    "Aliases.QuerySetAliasActionItem.0.Name": item.Name,
+                    "Aliases.QuerySetAliasActionItem.itemcount": 1
+                };
+                requests.push(ESPRequest.send("WsWorkunits", "WUQuerysetAliasAction", {
+                    request: request
+                }));
+            });
+            return all(requests);
+        },
+
+        WUQuerysetQueryAction: function (selection, action) {
+            if (action === "Deactivate") {
+                return this.WUQuerysetAliasAction(selection, action);
+            }
+            var requests = [];
+            arrayUtil.forEach(selection, function (item, idx) {
+                var request = {
+                    QuerySetName: item.QuerySetId,
+                    Action: action,
+                    "Queries.QuerySetQueryActionItem.0.QueryId": item.Id,
+                    "Queries.QuerySetQueryActionItem.itemcount": 1
+                };
+                requests.push(ESPRequest.send("WsWorkunits", "WUQuerysetQueryAction", {
+                    request: request
+                }));
+            });
+            return all(requests);
+        },
+
+        CreateQuerySetStore: function (options) {
+            var store = new QuerySetStore(options);
+            return Observable(store);
+        },
+
         WUPublishWorkunit: function (params) {
             return ESPRequest.send("WsWorkunits", "WUPublishWorkunit", params).then(function (response) {
                 if (lang.exists("WUPublishWorkunitResponse", response)) {
@@ -137,6 +184,10 @@ define([
             return ESPRequest.send("WsWorkunits", "WUResult", params);
         },
 
+        WUQueryGetGraph: function (params) {
+            return ESPRequest.send("WsWorkunits", "WUQueryGetGraph", params);
+        },
+
         WUFile: function (params) {
             lang.mixin(params, {
                 handleAs: "text"
@@ -191,10 +242,10 @@ define([
                         return true;
                     }
                     break;
-                case 3:	//WUStateCompleted:
-                case 4:	//WUStateFailed:
-                case 5:	//WUStateArchived:
-                case 7:	//WUStateAborted:
+                case 3: //WUStateCompleted:
+                case 4: //WUStateFailed:
+                case 5: //WUStateArchived:
+                case 7: //WUStateAborted:
                 case 999: //WUStateDeleted:
                     return true;
             }
@@ -202,4 +253,3 @@ define([
         }
     };
 });
-

+ 3 - 1
esp/files/templates/HPCCPlatformRoxieWidget.html

@@ -4,7 +4,9 @@
             <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 id="${id}_Queries" title="Queries" data-dojo-type="QuerySetQueryWidget">
+            </div>
+            <div id="${id}_PackageMaps" title="Package Maps" data-dojo-type="PackageMapQueryWidget">
             </div>
         </div>
     </div>

+ 87 - 0
esp/files/templates/QuerySetDetailsWidget.html

@@ -0,0 +1,87 @@
+<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}Refresh" data-dojo-attach-event="onClick:_onRefresh" data-dojo-props='iconClass:"iconRefresh"' data-dojo-type="dijit.form.Button">Refresh</div>
+                    <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}NewPage" class="right" data-dojo-attach-event="onClick:_onNewPage" data-dojo-props="iconClass:'iconNewPage', showLabel:false" data-dojo-type="dijit.form.Button">Open in New Page</div>
+                </div>
+                <div data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">
+                    <h2>
+                        <img id="${id}SuspendImg" src="img/unsuspended.png" alt="Unsuspended"/>&nbsp;<img id="${id}ActiveImg" src="img/inactive.png"/>&nbsp;<span id="${id}QueryId" class="bold">Query Details for</span>
+                    </h2>
+                    <form id="${id}SummaryForm">
+                        <ul>
+                            <li>
+                                <label class="Prompt" for="${id}QueryName">Name:</label>
+                                <div id="${id}QueryName"></div>
+                            </li>
+                            <li>
+                                <label class="Prompt" for="${id}QuerySet">Query Set:</label>
+                                <div id="${id}QuerySet"></div>
+                            </li>
+                            <li>
+                                <label class="Prompt" for="${id}Priority">Priority:</label>
+                                <div id="${id}Priority"></div>
+                            </li>
+                            <li> 
+                                <label class="Prompt" for="${id}PublishedBy">Published By:</label>
+                                <div id="${id}PublishedBy"></div>
+                            </li>
+                            <li>
+                                <label class="Prompt" for="${id}Suspended">Suspended:</label>
+                                <div><input id="${id}Suspended" data-dojo-type="dijit.form.CheckBox"/></div>
+                            </li>
+                            <li>
+                                <label class="Prompt" for="${id}SuspendedBy">Suspended By:</label>
+                                <div id="${id}SuspendedBy"></div>
+                            </li>
+                            <li>
+                                <label class="Prompt" for="${id}Activated">Activated:</label>
+                                <div><input id="${id}Activated" data-dojo-type="dijit.form.CheckBox"/></div>
+                            </li>
+                            <li>
+                                <label class="Prompt" for="${id}Comment">Comment:</label>
+                                <div id="${id}Comment"></div>
+                            </li>
+                            <hr class="dashedLine">
+                            <li>
+                                <label class="Prompt" for="${id}Wuid">WUID:</label>
+                                <div id="${id}Wuid"></div>
+                            </li>
+                            <li>
+                                <label class="Prompt" for="${id}Dll">Dll:</label>
+                                <div id="${id}Dll"></div>
+                            </li>
+                            <li>
+                                <label class="Prompt" for="${id}WUSnapShot">WU Snap Shot:</label>
+                                <div id="${id}WUSnapShot"></div>
+                            </li>
+                             <hr class="dashedLine">
+                            <li>
+                                <label class="Prompt" for="${id}IsLibrary">Is Library:</label>
+                                <div id="${id}IsLibrary"></div>
+                            </li>
+                            <li>
+                                <label class="Prompt" for="${id}LibrariesUsed">Libraries Used:</label>
+                                <div id="${id}LibrariesUsed"></div>
+                            </li>
+                        </ul>
+                    </form>
+                </div>
+            </div>
+            <div id="${id}_Errors" title="Errors" data-dojo-type="QuerySetErrorsWidget">
+            </div>
+            <div id="${id}_Graphs" title="Graphs" data-dojo-type="GraphsWidget">
+            </div>
+            <div id="${id}_QuerySetLogicalFiles" title="Logical Files" data-dojo-type="QuerySetLogicalFilesWidget">
+            </div>
+            <div id="${id}_Workunit" title="WUDetailsWidget" data-dojo-type="WUDetailsWidget">
+            </div>
+        </div>
+    </div>
+</div>

+ 9 - 0
esp/files/templates/QuerySetErrorsWidget.html

@@ -0,0 +1,9 @@
+<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}_QuerySetLogicalFiles" style="width: 100%; height: 100%" data-dojo-props='title:"My Account", iconClass:"iconLogicalFile"' data-dojo-type="dijit.layout.BorderContainer">
+                <div data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">
+            </div>
+        </div>
+    </div>
+</div>

+ 9 - 0
esp/files/templates/QuerySetLogicalFilesWidget.html

@@ -0,0 +1,9 @@
+<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}_QuerySetLogicalFiles" style="width: 100%; height: 100%" data-dojo-props='title:"My Account", iconClass:"iconLogicalFile"' data-dojo-type="dijit.layout.BorderContainer">
+                <div data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">
+            </div>
+        </div>
+    </div>
+</div>

+ 41 - 0
esp/files/templates/QuerySetQueryWidget.html

@@ -0,0 +1,41 @@
+<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}_Queries" style="width: 100%; height: 100%" data-dojo-props='title:"Queries", iconClass:"iconCluster"' data-dojo-type="dijit.layout.BorderContainer">
+				<div id="${id}QueryToolbar" class="topPanel" data-dojo-props="region: 'top'" data-dojo-type="dijit.Toolbar">
+					<div id="${id}Refresh" data-dojo-attach-event="onClick:_onRefresh" data-dojo-type="dijit.form.Button" data-dojo-props='iconClass:"iconRefresh"'>Refresh</div>
+					<span data-dojo-type="dijit.ToolbarSeparator"></span>
+					<div id="${id}Open" data-dojo-attach-event="onClick:_onOpen" data-dojo-type="dijit.form.Button">Open</div>
+					<div id="${id}Delete" data-dojo-attach-event="onClick:_onDelete" data-dojo-type="dijit.form.Button">Delete</div>
+					<span data-dojo-type="dijit.ToolbarSeparator"></span>
+					<div id="${id}unSuspend" data-dojo-attach-event="onClick:_onUnsuspend" data-dojo-type="dijit.form.Button">Unsuspend</div>
+					<div id="${id}onSuspend" data-dojo-attach-event="onClick:_onSuspend" data-dojo-type="dijit.form.Button">Suspend</div>
+					<span data-dojo-type="dijit.ToolbarSeparator"></span>
+					<div id="${id}Activate" data-dojo-attach-event="onClick:_onActivate" data-dojo-type="dijit.form.Button">Activate</div>
+					<div id="${id}Deactivate" data-dojo-attach-event="onClick:_onDeactivate" data-dojo-type="dijit.form.Button">Deactivate</div>
+					<span data-dojo-type="dijit.ToolbarSeparator"></span>
+					<img id="${id}IconFilter" src="img/noFilter.png" class="iconNoFilter"/>
+                    <div id="${id}FilterDropDown" data-dojo-type="dijit.form.DropDownButton">
+                        <span>Filter</span>
+                        <div data-dojo-type="dijit.TooltipDialog" class="toolTip">
+                        	<div id="${id}FilterForm" style="width:460px" data-dojo-type="dijit.form.Form">
+                                <div data-dojo-props="cols:2" data-dojo-type="dojox.layout.TableContainer">
+                        			<input id="${id}ClusterTargetSelect" title="Cluster:" name="QuerySetName" colspan="2" data-dojo-props="trim: true, placeHolder:'r?x*'" data-dojo-type="TargetSelectWidget" />
+                        			<input id="${id}Active" title="Active:" name="Active" colspan="2" data-dojo-props="trim: true, placeHolder:'jsmi*'" data-dojo-type="dijit.form.CheckBox" />
+                        			<input id="${id}Suspended" title="Suspended:" name="Suspended" colspan="2" data-dojo-props="trim: true, placeHolder:'jsmi*'" data-dojo-type="dijit.form.CheckBox" />
+                        		</div>
+	                    		<button id="${id}FilterApply" data-dojo-attach-event="onClick:_onFilterApply" data-dojo-type="dijit.form.Button">Apply</button>
+	                            <button id="${id}FilterClear" data-dojo-attach-event="onClick:_onFilterClear" data-dojo-type="dijit.form.Button">Clear</button>
+                        	</div>
+                   		</div>
+                    </div>
+                    <span data-dojo-type="dijit.ToolbarSeparator"></span>
+                    <div id="${id}NewPage" class="right" data-dojo-attach-event="onClick:_onNewPage" data-dojo-props="iconClass:'iconNewPage', showLabel:false" data-dojo-type="dijit.form.Button">Open in New Page</div>
+				</div>
+				<div id="${id}GridCP" style="padding: 0px; border:0px; border-color:none; overflow: hidden" data-dojo-props="region: 'center'" data-dojo-type="dijit.layout.ContentPane">
+					<div id="${id}QuerySetGrid"></div>
+				</div>
+			</div>
+		</div>
+	</div><!--end of border container-->
+</div>

+ 0 - 0
esp/files/templates/QuerySetSuperFilesWidget.html


+ 5 - 0
lib2/CMakeLists.txt

@@ -82,6 +82,11 @@ foreach(dylib ${DYLIBS})
             set(fixupCommand "${fixupCommand}\r\nexecute_process(COMMAND install_name_tool -change \"${dylib_110_path}\" \"@loader_path/../lib2/${dylib_name_ext}\" \${file})")
         endif ()
 
+        string(REPLACE ".51.2.dylib" ".51.dylib" dylib_51_path "${dylib_path}")
+        if (NOT "${dylib_51_path}" STREQUAL "${dylib_path}")
+            set(fixupCommand "${fixupCommand}\r\nexecute_process(COMMAND install_name_tool -change \"${dylib_51_path}\" \"@loader_path/../lib2/${dylib_name_ext}\" \${file})")
+        endif ()
+
         install(CODE "
             file(GLOB files \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${EXEC_DIR}/*\" \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${LIB_DIR}/*.dylib\" \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/plugins/*.dylib\" \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/lib2/*.dylib\")
             foreach(file \${files})