LP#1694577 Reports template searching and paging
authorBill Erickson <berickxx@gmail.com>
Sat, 12 Aug 2017 15:12:17 +0000 (11:12 -0400)
committerJason Etheridge <jason@EquinoxInitiative.org>
Wed, 23 Aug 2017 16:04:59 +0000 (12:04 -0400)
Adds a new template search from along the top of the reports interface.
Templates may be searched name and/or description.

Adds paging support to the template, reports, and output interfaces.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>
Signed-off-by: Jason Etheridge <jason@EquinoxInitiative.org>
Open-ILS/web/opac/locale/en-US/reports.dtd
Open-ILS/web/reports/oils_rpt.css
Open-ILS/web/reports/oils_rpt.js
Open-ILS/web/reports/oils_rpt.xhtml
Open-ILS/web/reports/oils_rpt_folder_window.js
Open-ILS/web/reports/oils_rpt_folder_window.xhtml
Open-ILS/web/reports/oils_rpt_folders.js
Open-ILS/web/reports/oils_rpt_vars.js

index 85fc17d..4654292 100644 (file)
 <!ENTITY reports.oils_rpt_param_editor.months "Months(s)">
 <!ENTITY reports.oils_rpt_param_editor.ago " ago">
 
+<!ENTITY reports.oils_rpt_template_search_results "Template Search Results">
+<!ENTITY reports.oils_rpt_template_search_query "Template query...">
+<!ENTITY reports.oils_rpt_template_search_label "Search Templates">
+<!ENTITY reports.oils_rpt_template_search_all_fields "All Fields">
+<!ENTITY reports.oils_rpt_template_search_name "Name">
+<!ENTITY reports.oils_rpt_template_search_desc "Description">
+<!ENTITY reports.oils_rpt_template_search_all_folders "All Folders">
+<!ENTITY reports.oils_rpt_paging_start "Start">
+<!ENTITY reports.oils_rpt_paging_prev "Prev">
+<!ENTITY reports.oils_rpt_paging_next "Next">
 
 <!ENTITY reports.xul.template_builder.db_source_browser.label "Database Source Browser">
 <!ENTITY reports.xul.template_builder.sources_menulist.label "Sources">
index 17a71ed..da744b2 100644 (file)
@@ -303,6 +303,10 @@ button:disabled {
 .oils_rpt_generic_table { width: 100%; }
 .oils_rpt_generic_table td { border: 1px solid #808080; padding: 5px; }
 
+#oils_rpt_content_count_row a {
+    padding-left: 5px;
+}
+
 #oils_rpt_content_count_row_2 {
        border-top: 2px solid #808080;
        border-bottom: 1px solid #808080;
@@ -334,3 +338,11 @@ button:disabled {
 #oils_rpt_editor_sched_confirm:first-child {
     font-size: 110%;
 }
+
+#template_search_form_wrapper label {
+    font-weight: bold;
+}
+
+#template_search_form_wrapper span {
+    padding-right: 10px;
+}
index 3d212de..3a75552 100644 (file)
@@ -28,12 +28,21 @@ function oilsInitReports() {
        dojo.cookie(COOKIE_SES, SESSION, { 'path' : '/', 'secure' : true});
        dojo.cookie('ws_ou', USER.ws_ou(), { 'path' : '/', 'secure' : true});
 
+    // set the search form to submit-on-enter
+    DOM.template_search_query.onkeyup = function(evt) {
+        if (evt.keyCode == 13 && 
+            DOM.template_search_query.value) {
+            DOM.template_search_submit_button.onclick();
+        }
+    }
+
        oilsRptFetchOrgTree(
                function() {
                        oilsLoadRptTree(
                                function() {
                                        hideMe(DOM.oils_rpt_tree_loading); 
                                        unHideMe(DOM.oils_rpt_folder_table);
+                                       unHideMe(DOM.template_search_form_wrapper);
                                }
                        )
                }
index f3ceac5..c5bcd28 100644 (file)
                        &reports.common.loading;
                </div>
 
+        <div id='template_search_form_wrapper' class='hide_me'>
+            <span><label>&reports.oils_rpt_template_search_label;</label></span>
+            <span><input type='text' id='template_search_query' 
+                placeholder="&reports.oils_rpt_template_search_query;"/></span>
+            <span>
+                <select id='template_search_fields_selector'>
+                    <option value='' selected='selected'>&reports.oils_rpt_template_search_all_fields;</option>
+                    <option value='name'>&reports.oils_rpt_template_search_name;</option>
+                    <option value='description'>&reports.oils_rpt_template_search_desc;</option>
+                </select>
+            </span>
+            <span>
+                <select id='template_search_folder_selector'>
+                    <option value=''>&reports.oils_rpt_template_search_all_folders;</option>
+                </select>
+            </span>
+            <span>
+                <button id='template_search_submit_button'>
+                    &reports.oils_rpt_folder_manager.fldr_mngr_actions_submit;
+                </button>
+            </span>
+        </div>
+
                <table id='oils_rpt_folder_table' class='hide_me'>
                        <tbody>
                                <tr>
@@ -66,7 +89,8 @@
                                        <td id='oils_rpt_folder_table_right_td' class='hide_me'>
                                                <div class='oils_rpt_folder_window'>
 
-                                                       <table class='oils_rpt_tab_table' id='oils_rpt_folder_manager_tab_table'><tbody>
+                                                       <table class='oils_rpt_tab_table hidden-for-search-results' 
+                                    id='oils_rpt_folder_manager_tab_table'><tbody>
                                                                <tr>
                                                                        <td width='50%'>
                                                                                <a id='oils_rpt_folder_window_manage_tab' href='javascript:void(0);'>&reports.oils_rpt.manage_folder_contents;</a></td>
                                                        </tbody></table>
 
                                                        <table id='oils_rpt_folder_details_table'>
-                                                               <tbody>
-                                                                       <tr>
-                                                                               <td>
-                                                                                       <span><b id='oils_rpt_folder_name_label'/>: 
-                                                                                       &reports.oils_rpt.created_by;</span> <b id='oils_rpt_folder_creator_label'/>
-                                                                               </td>
-                                                                       </tr>
-                                                               </tbody>
+                                                               <tbody><tr><td>
+                                    <div id='real_folder_name'>
+                                                                       <span><b id='oils_rpt_folder_name_label'/>: 
+                                                                               &reports.oils_rpt.created_by;</span> <b id='oils_rpt_folder_creator_label'/>
+                                    </div>
+                                    <div id='search_results_folder_name'>
+                                        <b>&reports.oils_rpt_template_search_results;</b>
+                                    </div>
+                                                       </td></tr></tbody>
                                                        </table>
 
                                                        <div>
index f5e0cf8..d1ba641 100644 (file)
@@ -23,24 +23,57 @@ function oilsRptFolderWindow(type, folderId) {
 // maps folder IDs to their containing oilsRptFolderWindow objects
 oilsRptFolderWindow.folderIdMap = {};
 
-oilsRptFolderWindow.prototype.draw = function() {
+// Here lie the contents of a specific folder
+oilsRptFolderWindow.prototype.draw = function(viaPaging) {
 
        _debug('drawing folder window for ' + this.folderNode.folder.name() );
 
+    // always start a new folder at the first page of results
+    if (!viaPaging) oilsRptOutputOffset = 0;
+
+    console.log('drawing folder ' + this.folderNode.folder.name() + 
+        ' ; offset=' + oilsRptOutputOffset + ' ; limit=' + oilsRptOutputLimit);
+
        var obj = this;
        setSelector(DOM.oils_rpt_output_limit_selector, oilsRptOutputLimit);
        setSelector(DOM.oils_rpt_output_limit_selector_2, oilsRptOutputLimit2);
 
        DOM.oils_rpt_output_limit_selector.onchange = function() {
                oilsRptOutputLimit = getSelectorVal(DOM.oils_rpt_output_limit_selector);
-               obj.draw();
+               obj.draw(); // resets offset
        }
 
        DOM.oils_rpt_output_limit_selector_2.onchange = function() {
                oilsRptOutputLimit2 = getSelectorVal(DOM.oils_rpt_output_limit_selector_2);
-               obj.draw();
+               obj.draw(); // resets offset
        }
 
+    DOM.oils_rpt_output_next_selector.onclick = function() {
+        oilsRptOutputOffset += Number(oilsRptOutputLimit);
+        obj.draw(true);
+    }
+
+    // Enable / disable the Previous and Start links depending on
+    // current page.
+    if (oilsRptOutputOffset <= 0) {
+        DOM.oils_rpt_output_prev_selector.onclick = function(){};
+        DOM.oils_rpt_output_first_selector.onclick = function(){};
+        DOM.oils_rpt_output_prev_selector.removeAttribute('href');
+        DOM.oils_rpt_output_first_selector.removeAttribute('href');
+    } else {
+        DOM.oils_rpt_output_prev_selector.setAttribute('href', 'javascript:');
+        DOM.oils_rpt_output_first_selector.setAttribute('href', 'javascript:');
+
+        DOM.oils_rpt_output_prev_selector.onclick = function() {
+            oilsRptOutputOffset -= Number(oilsRptOutputLimit);
+            obj.draw(true);
+        }
+
+        DOM.oils_rpt_output_first_selector.onclick = function() {
+            obj.draw(); // resets offset
+        }
+    }
+
        var mine = ( this.folderNode.folder.owner().id() == USER.id() );
 
        _debug('drawing folder window with type '+this.type);
@@ -486,6 +519,22 @@ oilsRptFolderWindow.prototype.drawFolderDetails = function() {
 }
 
 
+oilsRptFolderWindow.prototype.createSearchRequest = function() {
+    var field = getSelectorVal(DOM.template_search_fields_selector);
+    var fields = field ? [field] : ['name', 'description'];
+
+    return new Request(
+        'open-ils.reporter:open-ils.reporter.search.templates.atomic', 
+        SESSION, {
+            limit  : oilsRptOutputLimit,
+            offset : oilsRptOutputOffset,
+            query  : DOM.template_search_query.value,
+            folder : getSelectorVal(DOM.template_search_folder_selector),
+            fields : fields,
+        }
+    );
+}
+
 oilsRptFolderWindow.prototype.fetchFolderData = function(callback) {
 
        hideMe(DOM.oils_rpt_content_count_row_2);
@@ -493,7 +542,8 @@ oilsRptFolderWindow.prototype.fetchFolderData = function(callback) {
 
        removeChildren(this.selector);
        var req = new Request(OILS_RPT_FETCH_FOLDER_DATA, 
-               SESSION, this.type, this.folderNode.folder.id(), oilsRptOutputLimit);
+               SESSION, this.type, this.folderNode.folder.id(), 
+        oilsRptOutputLimit, oilsRptOutputOffset);
 
        hideMe(DOM.oils_rpt_pending_output);
 
@@ -504,6 +554,26 @@ oilsRptFolderWindow.prototype.fetchFolderData = function(callback) {
                        SESSION, this.folderNode.folder.id(), oilsRptOutputLimit, 0);
        }
 
+    // Displaying the special template "Search Results" folder means 
+    // starting a new search.
+    var hidableNodes = document.getElementsByClassName('hidden-for-search-results');
+    var showableNodes = document.getElementsByClassName('show-for-search-results');
+    if (this.type == 'template' && 
+        this.folderNode.folder.id() == oilsRptSearchResultFolderId) {
+        req = this.createSearchRequest();
+
+        // when displaying search results, hide anything that should be hidden
+        dojo.forEach(hidableNodes, function(n) { n.style.visibility = 'hidden' });
+        dojo.forEach(showableNodes, function(n) { n.style.visibility = 'visible' });
+        hideMe(DOM.real_folder_name);
+        unHideMe(DOM.search_results_folder_name);
+    } else {
+        dojo.forEach(hidableNodes, function(n) { n.style.visibility = 'visible' });
+        dojo.forEach(showableNodes, function(n) { n.style.visibility = 'hidden' });
+        unHideMe(DOM.real_folder_name);
+        hideMe(DOM.search_results_folder_name);
+    }
+
        var obj = this;
        removeChildren(obj.selector);
        req.callback(
index 34090bc..1003cc3 100644 (file)
@@ -9,7 +9,7 @@
        <table id='oils_rpt_folder_window_contents_table'>
                <tbody>
                        <tr>
-                               <td colspan='2'> 
+                               <td colspan='2' _class='hidden-for-search-results'
                                        <span>
                                                <select id='oils_rpt_folder_contents_action_selector' style='width: auto;'>
                                                        <option type='template' value='create_report'>&reports.oils_rpt_folder_window.new_report_from_template;</option>
                                                        <option value='50'>50</option>
                                                        <option value=''>&reports.oils_rpt_folder_window.all;</option>
                                                </select>
+                        <a id='oils_rpt_output_first_selector' href='javascript:void(0);'>&reports.oils_rpt_paging_start;</a>
+                        <a id='oils_rpt_output_prev_selector' href='javascript:void(0);'>&reports.oils_rpt_paging_prev;</a>
+                        <a id='oils_rpt_output_next_selector' href='javascript:void(0);'>&reports.oils_rpt_paging_next;</a>
                                                <span><b id='oils_rpt_pending_output' class='hide_me'>&reports.oils_rpt_folder_window.pending_items;</b></span>
                                        </div>
                                </td>
-                               <td style='text-align:right;'>
+                               <td style='text-align:right;' class='hidden-for-search-results'>
                                        <a id='oils_rpt_folder_window_contents_new_template' 
                                                href='javascript:void(0);'><b>&reports.oils_rpt_folder_window.new_template;</b></a>
                                </td>
index 2c2b3ff..71c656d 100644 (file)
@@ -6,6 +6,9 @@ var oilsRptFolderNodeCache = {};
 oilsRptFolderNodeCache.template = {};
 oilsRptFolderNodeCache.report  = {};
 oilsRptFolderNodeCache.output  = {};
+// ephemeral template search results folder needs an ID.
+var oilsRptSearchResultFolderId = -1000; 
+var oilsRptSearchResultFolderWindowId = null;
 
 oilsRptSetSubClass('oilsRptFolderManager','oilsRptObject');
 
@@ -130,6 +133,10 @@ oilsRptFolderManager.prototype.draw = function(auth) {
 
        oilsRptSharedOutputFolderTree.addNode(this.soId, -1, rpt_strings.FOLDERS_OUTPUT)
 
+    DOM.template_search_submit_button.onclick = function() {
+        oilsRptObject.find(oilsRptSearchResultFolderWindowId).draw();
+    }
+
        this.fetchFolders(auth);
 }
 
@@ -190,6 +197,15 @@ oilsRptFolderManager.prototype.drawFolders = function(type, folders) {
        var tree;
        var owners = {};
 
+    // Special search results folders ; not added to folder tree.
+    if (type == 'template') {
+        var resFolder = new rtf();
+        resFolder.id(oilsRptSearchResultFolderId);
+        resFolder.name(''); // not shown
+        resFolder.owner(USER);
+        folders.unshift(resFolder);
+    }
+
        for( var i = 0; i < folders.length; i++ ) {
 
                var folder = folders[i];
@@ -199,6 +215,9 @@ oilsRptFolderManager.prototype.drawFolders = function(type, folders) {
                oilsRptFolderNodeCache[type][folder.id()] = node;
                node.folderWindow = new oilsRptFolderWindow(type, folder.id())
 
+        if (folder.id() == oilsRptSearchResultFolderId) 
+            oilsRptSearchResultFolderWindowId = node.folderWindow.id;
+
                /*
                _debug("creating folder node for "+folder.name()+" : id = "+
                        folder.id()+' treeId = '+id + ' window id = ' + node.folderWindow.id);
@@ -238,9 +257,9 @@ oilsRptFolderManager.prototype.drawFolders = function(type, folders) {
                }
        }
 
+    var search_folders = [];
        for( var i = 0; i < folders.length; i++ ) {
 
-
                var folder = folders[i];
                var mine = (folder.owner().id() == USER.id());
                var pid;
@@ -283,8 +302,13 @@ oilsRptFolderManager.prototype.drawFolders = function(type, folders) {
 
                node = this.findNode(type, folder.id());
                id = node.treeId;
-               if( folder.parent() ) 
-                       pid = this.findNode(type, folder.parent()).treeId;
+               if( folder.parent() ) {
+            var pnode = this.findNode(type, folder.parent());
+                       pid = pnode.treeId;
+            node.depth = pnode.depth + 1;
+        } else {
+            node.depth = 0;
+        }
 
                var fname = folder.name();
 
@@ -304,9 +328,38 @@ oilsRptFolderManager.prototype.drawFolders = function(type, folders) {
                        +pid + ' parent = ' + folder.parent() + ' folder-window = ' + node.folderWindow.id );
                        */
 
-               tree.addNode(id, pid, fname, action);
-               tree.close(pid);
+        if (folder.id() != oilsRptSearchResultFolderId) {
+            search_folders.push({id : folder.id(), pid: folder.parent(), fname : fname, depth : node.depth});
+                   tree.addNode(id, pid, fname, action);
+                   tree.close(pid);
+        }
        }
+
+    // search only applies to templates
+    if (type != 'template') return;
+
+    // Sort the list of search folders from top to bottom of the folder tree.
+    var depth_cache = {};
+    function add_folder(node) {
+        if (!node) return;
+
+        var label = node.fname;
+        // Left-pad the selector options by depth with U+2003 'EM SPACE'
+        // characters so the browser won't collapse the space.
+        for (var i = 0; i < node.depth; i++) label = ' ' + label;
+
+        insertSelectorVal(
+            DOM.template_search_folder_selector, -1, label, node.id);
+
+        var children = search_folders.filter(
+            function(f) { return (f.pid == node.id) });
+        dojo.forEach(children, add_folder);
+    }
+
+    // start with the parent-less folders
+    dojo.forEach(
+        search_folders.filter(
+            function(f) {return f.pid == null}), add_folder);
 }
 
 
index bf3594e..bd9a5e5 100644 (file)
@@ -24,6 +24,7 @@ var oilsRptSharedOutputFolderTree;
 
 var oilsRptOutputLimit = 10;
 var oilsRptOutputLimit2 = 10;
+var oilsRptOutputOffset = 0;
 
 var OILS_RPT_INVALID_DATA = 'oils_rpt_invalid_input';