Browse Source

HPCC-8177 Enhance Queries/Browse function

This fix merges the old function of 'Search Roxie Queries' to Queries/
Browse menu. A user may see detailed information about a query using
a link on the Query Set page. The detailed information includes: who
published the query, who suspened the query, comment, files used, etc.
The details page also contains links to both ECL WU Details page and
Logical File Details page.

This fix also removes 'Search Roxie Queries' menu from 'Roxie Queries'
section.

Signed-off-by: Kevin Wang <kevin.wang@lexisnexis.com>
Kevin Wang 12 years ago
parent
commit
0b11e1bfcf

+ 1 - 0
esp/eclwatch/ws_XSLT/CMakeLists.txt

@@ -129,6 +129,7 @@ FOREACH ( iFILES
     ${CMAKE_CURRENT_SOURCE_DIR}/filerelationlist.xslt
     ${CMAKE_CURRENT_SOURCE_DIR}/WUQuerysets.xslt
     ${CMAKE_CURRENT_SOURCE_DIR}/WUQuerysetQueries.xslt
+    ${CMAKE_CURRENT_SOURCE_DIR}/WUQueryDetails.xslt
     ${CMAKE_CURRENT_SOURCE_DIR}/dropzonefile.xslt
     ${CMAKE_CURRENT_SOURCE_DIR}/hpccresourcelist.xslt
     ${CMAKE_CURRENT_SOURCE_DIR}/dropzonefilelist.xslt

+ 204 - 0
esp/eclwatch/ws_XSLT/WUQueryDetails.xslt

@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+    <xsl:output method="html"/>
+    <xsl:template match="/WUQueryDetailsResponse">
+        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+            <head>
+                <xsl:text disable-output-escaping="yes"><![CDATA[
+                <link rel="stylesheet" type="text/css" href="/esp/files/yui/build/fonts/fonts-min.css" />
+                <link rel="stylesheet" type="text/css" href="/esp/files/yui/build/menu/assets/skins/sam/menu.css" />
+                <link rel="stylesheet" type="text/css" href="/esp/files/yui/build/button/assets/skins/sam/button.css" />
+                <link rel="stylesheet" type="text/css" href="/esp/files/yui/build/tabview/assets/skins/sam/tabview.css" />
+                <link rel="stylesheet" type="text/css" href="/esp/files/yui/build/treeview/assets/skins/sam/treeview.css" />
+                <link rel="stylesheet" type="text/css" href="/esp/files/yui/build/paginator/assets/skins/sam/paginator.css" />
+                <link rel="stylesheet" type="text/css" href="/esp/files/yui/build/datatable/assets/skins/sam/datatable.css" />
+                <link rel="stylesheet" type="text/css" href="/esp/files/yui/build/container/assets/skins/sam/container.css" />
+                <link rel="stylesheet" type="text/css" href="/esp/files/yui/build/fonts/fonts-min.css" />
+                <link rel="stylesheet" type="text/css" href="/esp/files/css/espdefault.css" />
+                <link rel="stylesheet" type="text/css" href="/esp/files/css/eclwatch.css" />
+                <script type="text/javascript" src="/esp/files/yui/build/yahoo/yahoo-min.js"></script>
+                <script type="text/javascript" src="/esp/files/yui/build/event/event-min.js"></script>
+                <script type="text/javascript" src="/esp/files/yui/build/dom/dom-min.js"></script>
+                <script type="text/javascript" src="/esp/files/yui/build/yahoo-dom-event/yahoo-dom-event.js"></script>
+                <script type="text/javascript" src="/esp/files/yui/build/element/element-min.js"></script>
+                <script type="text/javascript" src="/esp/files/yui/build/connection/connection-min.js"></script>
+                <script type="text/javascript" src="/esp/files/yui/build/datasource/datasource-min.js"></script>
+                <script type="text/javascript" src="/esp/files/yui/build/datatable/datatable-min.js"></script>
+                <script type="text/javascript" src="/esp/files/yui/build/json/json-min.js"></script>
+                <script type="text/javascript" src="/esp/files/yui/build/tabview/tabview-min.js"></script>
+                <script type="text/javascript" src="/esp/files/yui/build/container/container_core-min.js"></script>
+                <script type="text/javascript" src="/esp/files/yui/build/menu/menu-min.js"></script>
+                <script type="text/javascript" src="/esp/files/yui/build/button/button-min.js"></script>
+                <script type="text/javascript" src="/esp/files/scripts/espdefault.js">&#160;</script>
+                ]]></xsl:text>
+                <script language="JavaScript1.2">
+                    var querySet = '<xsl:value-of select="QuerySet"/>';
+                    var queryId = '<xsl:value-of select="QueryId"/>';
+                    var suspended = '<xsl:value-of select="Suspended"/>';
+                    <xsl:text disable-output-escaping="yes"><![CDATA[
+                      function deleteQuery() {
+                        actionWorkunits('Delete');
+                      }
+
+                      function toggleQuery() {
+                        actionWorkunits('ToggleSuspend');
+                      }
+                      function activateQuery() {
+                        actionWorkunits('Activate');
+                      }
+
+                      function getQueryActions(Action) {
+                          var soapXML = '<WUQuerysetQueryAction><QuerySetName>' + querySet + '</QuerySetName><Action>' + Action + '</Action><Queries>';
+                          soapXML += '<QuerySetQueryActionItem><QueryId>' + queryId + '</QueryId><ClientState><Suspended>' + suspended + '</Suspended></ClientState></QuerySetQueryActionItem>';
+                          soapXML += '</Queries></WUQuerysetQueryAction>';
+                          return soapXML;
+                      }
+
+                      function actionWorkunits(Action) {
+                          var connectionCallback = {
+                              success: function(o) {
+                                  var xmlDoc = o.responseXML;
+                                  document.location.replace( document.location.href );
+
+                              },
+                              failure: function(o) {
+                                  alert('Failure:' + o.statusText);
+
+                              }
+                          };
+
+                          var postBody = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns="http://webservices.seisint.com/WsWorkunits"><soap:Body>' + getQueryActions(Action) + '</soap:Body></soap:Envelope>';
+
+                          YAHOO.util.Connect.initHeader("SOAPAction", "/WsWorkunits/WUQuerysetQueryAction?");
+                          YAHOO.util.Connect.initHeader("Content-Type", "text/xml");
+                          YAHOO.util.Connect._use_default_post_header = false;
+
+                          var getXML = YAHOO.util.Connect.asyncRequest("POST",
+                                  "/WsWorkunits/WUQuerysetQueryAction",
+                                  connectionCallback, postBody);
+                          return;
+                      }
+
+                      function DFUFileDetails(fileName) {
+                          document.location.href='/WsDfu/DFUInfo?Name='+escape(fileName);
+                      }
+                      function WUDetails(WUID) {
+                          document.location.href='/WsWorkunits/WUInfo?Wuid='+escape(WUID);
+                      }
+                    ]]></xsl:text>
+                </script>
+            </head>
+            <body class="yui-skin-sam">
+                <h3>Query Details for <xsl:value-of select="QueryId"/></h3>
+                <form>
+                    <table style="text-align:left;" cellspacing="10">
+                        <colgroup style="vertical-align:top;padding-right:10px;" span="2"/>
+                        <tr>
+                            <th>Name:</th>
+                            <td><xsl:value-of select="QueryName"/></td>
+                        </tr>
+                        <tr>
+                            <th>Query Set:</th>
+                            <td><xsl:value-of select="QuerySet"/></td>
+                        </tr>
+                        <tr>
+                            <th>WUID:</th>
+                            <td>
+                                <a href="javascript:void(0)" onclick="WUDetails('{Wuid}');">
+                                    <xsl:value-of select="Wuid"/>
+                                </a>
+                            </td>
+                        </tr>
+                        <tr>
+                            <th>Dll:</th>
+                            <td>
+                                <xsl:value-of select="Dll"/>
+                            </td>
+                        </tr>
+                        <xsl:if test="string-length(PublishedBy)">
+                            <tr>
+                                <th>Published By:</th>
+                                <td><xsl:value-of select="PublishedBy"/></td>
+                            </tr>
+                        </xsl:if>
+                        <tr>
+                            <th>Suspended:
+                        </th>
+                            <td>
+                                <input type="checkbox" onclick="toggleQuery();">
+                                    <xsl:if test="Suspended=1">
+                                        <xsl:attribute name="checked"/>
+                                    </xsl:if>
+                                </input>
+                            </td>
+                        </tr>
+                        <xsl:if test="string-length(SuspendedBy)">
+                            <tr>
+                                <th>Suspended By:</th>
+                                <td><xsl:value-of select="SuspendedBy"/></td>
+                            </tr>
+                        </xsl:if>
+                        <xsl:if test="string-length(Label)">
+                            <tr>
+                                <th>Label:</th>
+                                <td><xsl:value-of select="Label"/></td>
+                            </tr>
+                        </xsl:if>
+                        <xsl:if test="string-length(Error)">
+                            <tr>
+                                <th>Error:</th>
+                                <td><xsl:value-of select="Error"/></td>
+                            </tr>
+                        </xsl:if>
+                        <xsl:if test="string-length(Comment)">
+                            <tr>
+                                <th>Comment:</th>
+                                <td><xsl:value-of select="Comment"/></td>
+                            </tr>
+                        </xsl:if>
+                        <xsl:if test="count(LogicalFiles/*)">
+                            <tr>
+                                <th valign="top">Files Used:</th>
+                                <td>
+                                    <table id="FileTable">
+                                        <xsl:for-each select="LogicalFiles/Item">
+                                            <tr>
+                                                <td>
+                                                    <a href="javascript:void(0)" onclick="DFUFileDetails('{.}');">
+                                                        <xsl:value-of select="."/>
+                                                    </a>
+                                                </td>
+                                            </tr>
+                                        </xsl:for-each>
+                                    </table>
+                                </td>
+                            </tr>
+                        </xsl:if>
+                    </table>
+                </form>
+                <input id="deleteBtn" type="button" value="Delete" onclick="deleteQuery();"> </input>
+                <input id="activateBtn" type="button" value="Activate" onclick="activateQuery();"> </input>
+            </body>
+        </html>
+    </xsl:template>
+
+    <xsl:template match="*|@*|text()"/>
+
+</xsl:stylesheet>

+ 8 - 3
esp/eclwatch/ws_XSLT/WUQuerysetQueries.xslt

@@ -169,6 +169,12 @@
                   }
               };
 
+              var formatLinkDetails = function(elCell, oRecord, oColumn, sData) {
+                  if (sData != "") {
+                      elCell.innerHTML = "<a href=\"/WsWorkunits/WUQueryDetails?QueryId=" + sData + "&QuerySet=" + querySet + "\">" + sData + "</a>";
+                  }
+              };
+
               function reloadPage()
               {
                   var clusterSelect = document.getElementById('Clusters');
@@ -190,7 +196,7 @@
               YAHOO.util.Event.addListener(window, "load", function() {
                 LoadQueries = function() {
                   var queryColumnDefs = [
-                    {key:"Id", sortable:true, resizeable:true},
+                    {key:"Id", sortable:true, resizeable:true, formatter: formatLinkDetails},
                     {key:"Name", sortable:true, resizeable:true},
                     {key:"Wuid", sortable:true, resizeable:true},
                     {key:"Dll", sortable:true, resizeable:true},
@@ -198,7 +204,7 @@
                   ];
                   if (clusterName != '')
                     queryColumnDefs = [
-                        {key:"Id", sortable:true, resizeable:true},
+                        {key:"Id", sortable:true, resizeable:true, formatter: formatLinkDetails},
                         {key:"Name", sortable:true, resizeable:true},
                         {key:"Wuid", sortable:true, resizeable:true},
                         {key:"Dll", sortable:true, resizeable:true},
@@ -222,7 +228,6 @@
 
                   queryDataTable.subscribe("rowMouseoverEvent", queryDataTable.onEventHighlightRow);   
                   queryDataTable.subscribe("rowMouseoutEvent", queryDataTable.onEventUnhighlightRow);   
-                  queryDataTable.subscribe("rowClickEvent", queryDataTable.onEventSelectRow);   
 
                   return {
                     oqDS: queryDataSource,

+ 22 - 0
esp/scm/ws_workunits.ecm

@@ -1184,6 +1184,27 @@ ESPresponse [exceptions_inline] WUQuerySetDetailsResponse
     [min_ver("1.37")] ESParray<string> ClusterNames;
 };
 
+ESPrequest WUQueryDetailsRequest
+{
+    string QueryId;
+    string QuerySet;
+};
+
+ESPresponse [exceptions_inline] WUQueryDetailsResponse
+{
+    string QueryId;
+    string QuerySet;
+    string QueryName;
+    string Wuid;
+    string Dll;
+    bool Suspended;
+    string SuspendedBy;
+    string PublishedBy;
+    string Comment;
+
+    ESParray<string> LogicalFiles;
+};
+
 ESPrequest WUMultiQuerySetDetailsRequest
 {
     string  ClusterName;
@@ -1367,6 +1388,7 @@ ESPservice [
     ESPmethod [resp_xsl_default("/esp/xslt/WUPublishWorkunit.xslt")] WUPublishWorkunit(WUPublishWorkunitRequest, WUPublishWorkunitResponse);
     ESPmethod [resp_xsl_default("/esp/xslt/WUQuerysets.xslt")] WUQuerysets(WUQuerysetsRequest, WUQuerysetsResponse);
     ESPmethod [resp_xsl_default("/esp/xslt/WUQuerysetQueries.xslt")] WUQuerysetDetails(WUQuerySetDetailsRequest, WUQuerySetDetailsResponse);
+    ESPmethod [resp_xsl_default("/esp/xslt/WUQueryDetails.xslt")] WUQueryDetails(WUQueryDetailsRequest, WUQueryDetailsResponse);
     ESPmethod WUMultiQuerysetDetails(WUMultiQuerySetDetailsRequest, WUMultiQuerySetDetailsResponse);
     ESPmethod WUQuerysetQueryAction(WUQuerySetQueryActionRequest, WUQuerySetQueryActionResponse);
     ESPmethod WUQuerysetAliasAction(WUQuerySetAliasActionRequest, WUQuerySetAliasActionResponse);

+ 0 - 2
esp/services/ws_roxiequery/ws_roxiequeryservice.hpp

@@ -51,8 +51,6 @@ public:
     virtual void getNavigationData(IEspContext &context, IPropertyTree & data)
     {
         IPropertyTree *folder = ensureNavFolder(data, "Roxie Queries", NULL, NULL, false, 7);
-        ensureNavLink(*folder, "Search Roxie Queries", "/WsRoxieQuery/RoxieQuerySearch", "Search Roxie Queries", NULL, NULL, 1);
-
         StringBuffer path = "/WsSMC/NotInCommunityEdition?form_";
         if (m_portalURL.length() > 0)
             path.appendf("&EEPortal=%s", m_portalURL.str());

+ 84 - 0
esp/services/ws_workunits/ws_workunitsQuerySets.cpp

@@ -863,6 +863,90 @@ bool CWsWorkunitsEx::onWUMultiQuerysetDetails(IEspContext &context, IEspWUMultiQ
     return true;
 }
 
+bool CWsWorkunitsEx::onWUQueryDetails(IEspContext &context, IEspWUQueryDetailsRequest & req, IEspWUQueryDetailsResponse & resp)
+{
+    const char* querySet = req.getQuerySet();
+    const char* queryId = req.getQueryId();
+    if (!querySet || !*querySet)
+        throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "QuerySet not specified");
+    if (!queryId || !*queryId)
+        throw MakeStringException(ECLWATCH_QUERYID_NOT_FOUND, "QueryId not specified");
+    resp.setQueryId(queryId);
+    resp.setQuerySet(querySet);
+
+    Owned<IPropertyTree> queryRegistry = getQueryRegistry(querySet, false);
+
+    StringBuffer xpath;
+    xpath.clear().append("Query[@id='").append(queryId).append("']");
+    IPropertyTree *query = queryRegistry->queryPropTree(xpath);
+    if (!query)
+    {
+        DBGLOG("No matching Query");
+        return false;
+    }
+
+    resp.setQueryName(query->queryProp("@name"));
+    resp.setWuid(query->queryProp("@wuid"));
+    resp.setDll(query->queryProp("@dll"));
+    resp.setPublishedBy(query->queryProp("@publishedBy"));
+    resp.setSuspended(query->getPropBool("@suspended", false));
+    resp.setSuspendedBy(query->queryProp("@suspendedBy"));
+    resp.setComment(query->queryProp("@comment"));
+
+    StringArray logicalFiles;
+    getQueryFiles(queryId, querySet, logicalFiles);
+    if (logicalFiles.length())
+        resp.setLogicalFiles(logicalFiles);
+
+    return true;
+}
+
+bool CWsWorkunitsEx::getQueryFiles(const char* query, const char* target, StringArray& logicalFiles)
+{
+    try
+    {
+        Owned<IConstWUClusterInfo> info = getTargetClusterInfo(target);
+        if (!info || (info->getPlatform()!=RoxieCluster))
+            return false;
+
+        const SocketEndpointArray &eps = info->getRoxieServers();
+        if (eps.empty())
+            return false;
+
+        StringBuffer control;
+        control.appendf("<control:getQueryXrefInfo full='1'><Query id='%s'/></control:getQueryXrefInfo>",  query);
+        Owned<ISocket> sock = ISocket::connect_timeout(eps.item(0), 5);
+        Owned<IPropertyTree> result = sendRoxieControlQuery(sock, control.str(), 5);
+        if (!result)
+            return false;
+
+        Owned<IPropertyTreeIterator> files = result->getElements("Endpoint/Queries/Query/File");
+        ForEach (*files)
+        {
+            IPropertyTree &file = files->query();
+            const char* fileName = file.queryProp("@name");
+            if (fileName && *fileName)
+                logicalFiles.append(fileName);
+        }
+
+        return true;
+    }
+    catch(IMultiException *me)
+    {
+        StringBuffer err;
+        DBGLOG("ERROR control:getQueryXrefInfo roxie query info %s", me->errorMessage(err.append(me->errorCode()).append(' ')).str());
+        me->Release();
+        return false;
+    }
+    catch(IException *e)
+    {
+        StringBuffer err;
+        DBGLOG("ERROR control:getQueryXrefInfo roxie query info %s", e->errorMessage(err.append(e->errorCode()).append(' ')).str());
+        e->Release();
+        return false;
+    }
+}
+
 inline void verifyQueryActionAllowsWild(bool &allowWildChecked, CQuerySetQueryActionTypes action)
 {
     if (allowWildChecked)

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

@@ -41,6 +41,7 @@ public:
     void deploySharedObject(IEspContext &context, IEspWUDeployWorkunitRequest & req, IEspWUDeployWorkunitResponse & resp, const char *dir, const char *xml=NULL);
     void deploySharedObject(IEspContext &context, StringBuffer &wuid, const char *filename, const char *cluster, const char *name, const MemoryBuffer &obj, const char *dir, const char *xml=NULL);
     void checkAndTrimWorkunit(const char* methodName, StringBuffer& input);
+    bool getQueryFiles(const char* query, const char* target, StringArray& logicalFiles);
 
     bool onWUQuery(IEspContext &context, IEspWUQueryRequest &req, IEspWUQueryResponse &resp);
     bool onWUPublishWorkunit(IEspContext &context, IEspWUPublishWorkunitRequest & req, IEspWUPublishWorkunitResponse & resp);
@@ -52,6 +53,7 @@ public:
     bool onWUQueryConfig(IEspContext &context, IEspWUQueryConfigRequest &req, IEspWUQueryConfigResponse &resp);
     bool onWUQuerysetCopyQuery(IEspContext &context, IEspWUQuerySetCopyQueryRequest &req, IEspWUQuerySetCopyQueryResponse &resp);
     bool onWUCopyLogicalFiles(IEspContext &context, IEspWUCopyLogicalFilesRequest &req, IEspWUCopyLogicalFilesResponse &resp);
+    bool onWUQueryDetails(IEspContext &context, IEspWUQueryDetailsRequest & req, IEspWUQueryDetailsResponse & resp);
 
     bool onWUInfo(IEspContext &context, IEspWUInfoRequest &req, IEspWUInfoResponse &resp);
     bool onWUInfoDetails(IEspContext &context, IEspWUInfoRequest &req, IEspWUInfoResponse &resp);