Bugzilla – Attachment 182343 Details for
Bug 33430
Use REST API for suggestions tables
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 33430: Enable datatables for suggestion tabs
Bug-33430-Enable-datatables-for-suggestion-tabs.patch (text/plain), 34.47 KB, created by
Philip Orr
on 2025-05-13 09:40:17 UTC
(
hide
)
Description:
Bug 33430: Enable datatables for suggestion tabs
Filename:
MIME Type:
Creator:
Philip Orr
Created:
2025-05-13 09:40:17 UTC
Size:
34.47 KB
patch
obsolete
>From cb1ba5020f597b57c5f2629a2775297f2960b04b Mon Sep 17 00:00:00 2001 >From: Matt Blenkinsop <matt.blenkinsop@openfifth.co.uk> >Date: Thu, 8 May 2025 17:10:14 +0100 >Subject: [PATCH] Bug 33430: Enable datatables for suggestion tabs > >Test plan: >1) Either add loads of suggestions to your KTD or use the script in the data script patch uploaded to the bug >2) Navigate to Acquisitions > Suggestions >3) Depending on how many suggestions you have loaded (the script does 2000), the page will load very slowly >4) Apply patches >5) yarn build && restart_all >6) Hard refresh the page, the page should load much faster and the first tab should load a paginated datatable >7) Click into another tab, the tab should also load a paginated datatable >8) Click back into the first tab, the original table should persist and should not reload >9) Use the edit tools at the bottom of the page, they should work as expected >10) Click on the links in various table cells, they should redirect as expected >11) Use the actions buttons in the far right column, then should work as expected > >Signed-off-by: Emily Lamancusa <emily.lamancusa@montgomerycountymd.gov> >Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com> > >Sponsored by: Montgomery County Public Libraries > >Signed-off-by: krimsonkharne <philip.orr@posteo.de> >--- > .../prog/en/modules/suggestion/suggestion.tt | 375 +++++++++++------- > 1 file changed, 223 insertions(+), 152 deletions(-) > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/suggestion/suggestion.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/suggestion/suggestion.tt >index 3484852206..7d96a366d1 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/suggestion/suggestion.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/suggestion/suggestion.tt >@@ -3,6 +3,7 @@ > [% USE Branches %] > [% USE AuthorisedValues %] > [% USE KohaDates %] >+[% USE To %] > [% USE Price %] > [% USE TablesSettings %] > [% PROCESS 'i18n.inc' %] >@@ -759,7 +760,7 @@ > <span>No name</span> > [% END %] > [% END %] >- ([% suggestion.suggestions.size| html %]) >+ ([% suggestion.tab_count | html %]) > [% END %] > [% END # /FOREACH suggestion %] > [% END # /WRAPPER tabs_nav %] >@@ -776,7 +777,7 @@ > [% INCLUDE 'csrf-token.inc' %] > <input type="hidden" name="op" value="cud-" />[%# filled by submit %] > >- [% IF suggestion.suggestions.size %] >+ [% IF suggestion.tab_count %] > <p> <a class="checkall" href="#">Check all</a> | <a class="uncheckall" href="#">Uncheck all</a> </p> > > <table id="table_[% suggestion.suggestiontype | html %]" class="sorted" data-tab-name="[% suggestion.suggestiontype | html %]"> >@@ -800,132 +801,6 @@ > <th class="no-sort no-export"> </th> > </tr> > </thead> >- <tbody> >- [% FOREACH s IN suggestion.suggestions %] >- <tr> >- <td> >- <input type="checkbox" name="suggestionid" value="[% s.suggestionid | html %]" /> >- </td> >- <td> >- <a href="suggestion.pl?suggestionid=[% s.suggestionid | uri %]&op=show" title="suggestion"> >- [% s.title | html %][% IF ( s.author ) %], by [% s.author | html %][% END %] >- </a> >- <br /> >- [% IF ( s.copyrightdate ) %] >- © <span class="suggestion_copyrightdate">[% s.copyrightdate | html %]</span> >- [% END %] >- [% IF ( s.volumedesc ) %] >- ; <span class="suggestion_volume">Volume:<em>[% s.volumedesc | html %]</em></span> >- [% END %] >- [% IF ( s.isbn ) %] >- ; <span class="suggestion_isbn">ISBN: <em>[% s.isbn | html %]</em></span> >- [% END %] >- [% IF ( s.publishercode ) %] >- ; <span class="suggestion_publishercode">Published by [% s.publishercode | html %]</span> >- [% END %] >- [% IF ( s.publicationyear ) %] >- in <span class="suggestion_publicationyear"><em>[% s.publicationyear | html %]</em></span> >- [% END %] >- [% IF ( s.place ) %] >- in <span class="suggestion_place"><em>[% s.place | html %]</em></span> >- [% END %] >- [% IF ( s.collectiontitle ) %] >- ; <span class="suggestion_collectiontitle">[% s.collectiontitle | html %]</span> >- [% END %] >- [% IF ( s.itemtype ) %] >- ; <span class="suggestion_itype">[% AuthorisedValues.GetByCode( 'SUGGEST_FORMAT', s.itemtype, 0 ) | html %]</span> >- [% END %] >- <br /> >- [% IF ( s.note ) %] >- <div class="suggestion_note">[% s.note | html %]</div> >- [% END %] >- [% IF s.archived %] >- <br /><i class="fa fa-archive"></i> Archived >- [% END %] >- </td> >- <td> >- [% SET suggester = s.suggester %] >- <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% suggester.borrowernumber | uri %]" >- >[% suggester.surname | html %][% IF suggester.firstname %], [% suggester.firstname | html %][% END %] >- [% IF suggester.cardnumber %]([% suggester.cardnumber | html %])[% END %]</a >- > >- </td> >- <td> [% suggester.category.description | html %] </td> >- <td data-order="[% s.suggesteddate | html %]"> [% IF ( s.suggesteddate ) %][% s.suggesteddate | $KohaDates %][% END %] </td> >- <td>[% AuthorisedValues.GetByCode( 'OPAC_SUG', s.patronreason ) | html %]</td> >- <td> >- [% SET manager = s.manager %] >- <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% manager.borrowernumber | uri %]" >- >[% manager.surname | html %][% IF manager.firstname %], [% manager.firstname | html %][% END %]</a >- > >- </td> >- <td data-order="[% s.manageddate | html %]"> [% IF ( s.manageddate ) %][% s.manageddate | $KohaDates %][% END %] </td> >- <td> >- [% SET last_modifier = s.last_modifier %] >- <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% last_modifier.borrowernumber | uri %]" >- >[% last_modifier.surname | html %][% IF last_modifier.firstname %], [% last_modifier.firstname | html %][% END %]</a >- > >- </td> >- <td data-order="[% s.lastmodificationdate | html %]"> [% IF ( s.lastmodificationdate ) %][% s.lastmodificationdate | $KohaDates %][% END %] </td> >- <td> [% s.lastmodificationdate | $KohaDates %] </td> >- <td> [% Branches.GetName( s.branchcode ) | html %] </td> >- <td> [% s.fund.budget_name | html %] </td> >- <td> [% s.staff_note | html %] </td> >- <td> >- [% IF s.STATUS == 'ASKED' %] >- <span>Pending</span> >- [% ELSIF s.STATUS == 'ACCEPTED' %] >- <span>Accepted</span> >- [% ELSIF s.STATUS == 'ORDERED' %] >- <span>Ordered</span> >- [% ELSIF s.STATUS == 'REJECTED' %] >- <span>Rejected</span> >- [% ELSIF s.STATUS == 'CHECKED' %] >- <span>Checked</span> >- [% ELSIF s.STATUS == 'AVAILABLE' %] >- <span>Available</span> >- [% ELSIF AuthorisedValues.GetByCode( 'SUGGEST_STATUS', s.STATUS ) %] >- [% AuthorisedValues.GetByCode( 'SUGGEST_STATUS', s.STATUS ) | html %] >- [% ELSE %] >- <span>Status unknown</span> >- [% END %] >- >- [% IF ( s.reason ) %] >- <br />([% s.reason | html %]) >- [% END %] >- </td> >- <td class="actions"> >- [% IF CAN_user_suggestions_suggestions_manage %] >- <div class="btn-group dropup"> >- <a class="btn btn-default btn-xs" role="button" href="suggestion.pl?suggestionid=[% s.suggestionid | html %]&op=edit_form" >- ><i class="fa-solid fa-pencil" aria-hidden="true"></i> Edit</a >- ><a class="btn btn-default btn-xs dropdown-toggle" id="more_actions_[% s.suggestionid | html %]" role="button" data-bs-toggle="dropdown" href="#" >- ><b class="caret"></b >- ></a> >- <ul class="dropdown-menu" role="menu" aria-labelledby="more_actions_[% s.suggestionid | html %]"> >- [% IF CAN_user_suggestions_suggestions_delete %] >- <li> >- <a href="#" data-op="cud-delete" data-suggestionid="[% s.suggestionid | html %]" class="dropdown-item trigger_action">Delete</a> >- </li> >- [% END %] >- [% UNLESS s.archived %] >- <li> >- <a href="#" class="dropdown-item trigger_action" data-op="cud-archive" data-suggestionid="[% s.suggestionid | html %]">Archive</a> >- </li> >- [% ELSE %] >- <li> >- <a href="#" class="dropdown-item trigger_action" data-op="cud-unarchive" data-suggestionid="[% s.suggestionid | html %]">Unarchive</a> >- </li> >- [% END %] >- </ul> >- </div> >- [% ELSIF CAN_user_suggestions_suggestions_delete %] >- <button data-op="cud-delete" data-suggestionid="[% s.suggestionid | html %]" class="btn btn-xs btn-default trigger_action"><i class="fa fa-trash-can"></i> Delete</button> >- [% END %] >- </td> >- </tr> >- [% END # /FOREACH s %] >- </tbody> > </table> > <!-- /#table_[% suggestion.suggestiontype | html %] --> > >@@ -1447,22 +1322,231 @@ > [% INCLUDE 'datatables.inc' %] > <script> > $(document).ready(function() { >+ let suggestionData = [% To.json(suggestions) | $raw %]; >+ var table_settings = [% TablesSettings.GetTableSettings( 'acqui', 'suggestions', 'suggestions', 'json' ) | $raw %] >+ function loadDatatable(tabName) { >+ let tabSuggestionData = suggestionData.find(s => s.suggestiontype === tabName) >+ $("#table_" + tabName).kohaTable( >+ { >+ sorting: [[4, "asc"]], >+ autoWidth: false, >+ ajax: { >+ url: "/api/v1/suggestions?q=" + JSON.stringify(tabSuggestionData.search_params), >+ delay: 300, // wait 300 milliseconds before triggering the request >+ cache: true, >+ dataType: "json", >+ }, >+ serverSide: true, >+ embed: ["suggester", "suggester.category", "manager", "last_modifier", "library", "fund", "+strings"], >+ columns: [ >+ { >+ data: "me.suggestion_id", >+ searchable: false, >+ orderable: false, >+ render: function (data, type, row, meta) { >+ return '<input type="checkbox" value="%s" name="suggestionid" />'.format(row.suggestion_id); >+ } >+ }, >+ { >+ data: "me.title", >+ searchable: true, >+ orderable: false, >+ render: function (data, type, row, meta) { >+ let node = '<a href="suggestion.pl?suggestionid=%s&op=show" title="%s">%s'.format(row.suggestion_id, _("suggestion"), row.title); >+ if(row.author) node += ', by %s'.format(row.author); >+ node += '</a><br />'; >+ if(row.copyright_date) node += ' © <span class="suggestion_copyrightdate">%s</span>'.format(row.copyright_date); >+ if(row.volume_desc) node += '; <span class="suggestion_volume">%s:<em>%s</em></span>'.format(_("Volume"), row.volume_desc); >+ if(row.isbn) node += '; <span class="suggestion_isbn">%s:<em>%s</em></span>'.format(_("ISBN"), row.isbn); >+ if(row.publisher_code) node += '; <span class="suggestion_publishercode">%s %s</span>'.format(_("Published by"), row.publisher_code); >+ if(row.publication_year && row.publication_year != 0) node += '; <span class="suggestion_publicationyear"><em>%s</em></span>'.format(row.publication_year); >+ if(row.publication_place) node += '; <span class="suggestion_place"><em>%s</em></span>'.format(row.publication_place); >+ if(row.collection_title) node += '; <span class="suggestion_collectiontitle"><em>%s</em></span>'.format(row.collection_title); >+ if(row.item_type && row._strings.item_type.str) node += '; <span class="suggestion_itype"><em>%s</em></span>'.format(row._strings.item_type.str); >+ if(row.note) node += '<div class="suggestion_note">%s</div>'.format(row.note); >+ if(row.archived) node += '<br /><i class="fa fa-archive"></i> %s'.format(_("Archived")); >+ return node; >+ } >+ }, >+ { >+ data: "suggester.surname:suggester.firstname:suggester.cardnumber", >+ searchable: true, >+ orderable: false, >+ render: function (data, type, row, meta) { >+ let suggester = row.suggester; >+ let node = '<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=%s">%s'.format(suggester.patron_id, suggester.surname); >+ if(suggester.firstname) node += ', %s'.format(suggester.firstname); >+ if(suggester.cardnumber) node += ' (%s)'.format(suggester.cardnumber); >+ node += '</a>'; >+ return node; >+ } >+ }, >+ { >+ data: "suggester.category.name", >+ searchable: false, >+ orderable: false, >+ render: function (data, type, row, meta) { >+ return escape_str(row.suggester.category.name); >+ }, >+ }, >+ { >+ data: "suggestion_date", >+ searchable: false, >+ orderable: true, >+ render: function (data, type, row, meta) { >+ return escape_str(row.suggestion_date ? $date(row.suggestion_date) : ''); >+ }, >+ }, >+ { >+ data: "", >+ searchable: false, >+ orderable: false, >+ render: function (data, type, row, meta) { >+ return escape_str(row._strings.patron_reason.str ? row._strings.patron_reason.str : ''); >+ }, >+ }, >+ { >+ data: "manager.surname:manager.firstname", >+ searchable: true, >+ orderable: false, >+ render: function (data, type, row, meta) { >+ let node = '<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=%s">%s'.format(row.manager.patron_id, row.manager.surname); >+ if(row.manager.firstname) node += ', %s'.format(row.manager.firstname); >+ node += '</a>'; >+ return node; >+ }, >+ }, >+ { >+ data: "managed_date", >+ searchable: false, >+ orderable: true, >+ render: function (data, type, row, meta) { >+ return escape_str(row.managed_date ? $date(row.managed_date) : ''); >+ }, >+ }, >+ { >+ data: "last_modifier.surname:last_modifier.firstname", >+ searchable: true, >+ orderable: false, >+ render: function (data, type, row, meta) { >+ let node = '<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=%s">%s'.format(row.last_modifier.patron_id, row.last_modifier.surname); >+ if(row.last_modifier.firstname) node += ', %s'.format(row.last_modifier.firstname); >+ node += '</a>'; >+ return node; >+ }, >+ }, >+ { >+ data: "last_status_change_date", >+ searchable: false, >+ orderable: true, >+ render: function (data, type, row, meta) { >+ return escape_str(row.last_status_change_date ? $date(row.last_status_change_date) : ''); >+ }, >+ }, >+ { >+ data: "last_status_change_date", >+ searchable: false, >+ orderable: true, >+ render: function (data, type, row, meta) { >+ return escape_str(row.last_status_change_date ? $date(row.last_status_change_date) : ''); >+ }, >+ }, >+ { >+ data: "library.name", >+ searchable: false, >+ orderable: false, >+ render: function (data, type, row, meta) { >+ return escape_str(row.library.name ? row.library.name : ''); >+ }, >+ }, >+ { >+ data: "fund.name", >+ searchable: false, >+ orderable: false, >+ render: function (data, type, row, meta) { >+ return escape_str(row.fund ? row.fund.name : ''); >+ }, >+ }, >+ { >+ data: "staff_note", >+ searchable: false, >+ orderable: false, >+ render: function (data, type, row, meta) { >+ return escape_str(row.staff_note ? row.staff_note : ''); >+ }, >+ }, >+ { >+ data: "status", >+ searchable: false, >+ orderable: false, >+ render: function (data, type, row, meta) { >+ if(row.status === 'ASKED') return '<span>%s</span>'.format(_("Pending")); >+ if(row.status === 'ACCEPTED') return '<span>%s</span>'.format(_("Accepted")); >+ if(row.status === 'ORDERED') return '<span>%s</span>'.format(_("Ordered")); >+ if(row.status === 'REJECTED') return '<span>%s</span>'.format(_("Rejected")); >+ if(row.status === 'CHECKED') return '<span>%s</span>'.format(_("Checked")); >+ if(row.status === 'AVAILABLE') return '<span>%s</span>'.format(_("Available")); >+ if(row._strings.status.str) return '<span>%s</span>'.format(row._strings.status.str); >+ return '<span>%s</span>'.format(_("Status unknown")); >+ }, >+ }, >+ { >+ data: "suggestion_id", >+ searchable: false, >+ orderable: false, >+ render: function (data, type, row, meta) { >+ [% IF CAN_user_suggestions_suggestions_manage %] >+ let node = '<div class="btn-group dropup">' >+ node += '<a class="btn btn-default btn-xs" role="button" href="suggestion.pl?suggestionid=%s&op=edit_form"><i class="fa-solid fa-pencil" aria-hidden="true"></i> %s</a>'.format(row.suggestion_id, _("Edit")) >+ node += '<a class="btn btn-default btn-xs dropdown-toggle" id="more_actions_%s" role="button" data-bs-toggle="dropdown" href="#"><b class="caret"></b></a>'.format(row.suggestion_id) >+ node += '<ul class="dropdown-menu" role="menu" aria-labelledby="more_actions_%s">'.format(row.suggestion_id) >+ [% IF CAN_user_suggestions_suggestions_delete %] >+ node += '<li><a href="#" data-op="cud-delete" data-suggestionid="%s" class="dropdown-item trigger_action">%s</a></li>'.format(row.suggestion_id, _("Delete")) >+ [% END %] >+ [% UNLESS s.archived %] >+ node += '<li><a href="#" class="dropdown-item trigger_action" data-op="cud-archive" data-suggestionid="%s">%s</a></li>'.format(row.suggestion_id, _("Archive")) >+ [% ELSE %] >+ node += '<li><a href="#" class="dropdown-item trigger_action" data-op="cud-unarchive" data-suggestionid="%s">%s</a></li>'.format(row.suggestion_id, _("Unarchive")) >+ [% END %] >+ node += '</ul></div>' >+ return node >+ [% ELSIF CAN_user_suggestions_suggestions_delete %] >+ return '<button data-op="cud-delete" data-suggestionid="%s" class="btn btn-xs btn-default trigger_action"><i class="fa fa-trash-can"></i> %s</button>'.format(row.suggestion_id, _("Delete")) >+ [% END %] >+ }, >+ createdCell: function (cell, cellData, rowData, rowIndex, colIndex) { >+ $(cell).find(".trigger_action").on("click", function(e) { >+ var id = $(this).data('suggestionid'); >+ var op = $(this).data('op'); >+ if ( op == 'cud-delete' && !confirm(_("Are you sure you want to delete this suggestion?")) ) { >+ e.preventDefault(); >+ return false; >+ } >+ $('#action_form input[name="op"]').val(op); >+ $('#action_form input[name="suggestionid"]').val(id); >+ $('#action_form').submit(); >+ return false; >+ }) >+ } >+ }, >+ ] >+ }, >+ table_settings >+ ); >+ } > if( $("#suggestiontabs .tab-pane.active").length < 1 ){ > $("#suggestiontabs a:first").tab("show"); >+ loadDatatable($("#suggestiontabs a:first").data("tabname")) >+ $("#suggestiontabs a:first").attr("data-table_loaded", 'true') > } > >- var table_settings = [% TablesSettings.GetTableSettings( 'acqui', 'suggestions', 'suggestions', 'json' ) | $raw %] >- > [% FOREACH suggestion IN suggestions %] >- [% IF suggestion.suggestions.size %] >- $("#table_[% suggestion.suggestiontype | html %]").kohaTable( >- { >- sorting: [[4, "asc"]], >- autoWidth: false, >- }, >- table_settings >- ); >- [% END %] >+ $("#suggestiontabs #[% suggestion.suggestiontype | html %]-tab").on("click", function() { >+ if(!$(this).data("table_loaded")) { >+ loadDatatable("[% suggestion.suggestiontype | html%]") >+ $(this).attr("data-table_loaded", "true") >+ } >+ }); > [% END %] > > $("#branchcode").on('change',function(){ >@@ -1505,19 +1589,6 @@ > $("." + target).toggle(); > }); > >- $(".trigger_action").on("click", function(e) { >- var id = $(this).data('suggestionid'); >- var op = $(this).data('op'); >- if ( op == 'cud-delete' && !confirm(_("Are you sure you want to delete this suggestion?")) ) { >- e.preventDefault(); >- return false; >- } >- $('#action_form input[name="op"]').val(op); >- $('#action_form input[name="suggestionid"]').val(id); >- $('#action_form').submit(); >- return false; >- }); >- > $("form.update_suggestions button[type='submit']").on("click", function(e) { > var submit_button = this; > var op = $(submit_button).data('op'); >-- >2.39.5
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 33430
:
182146
|
182147
|
182148
|
182149
|
182150
|
182161
|
182196
|
182197
|
182198
|
182199
|
182200
|
182202
|
182203
|
182204
|
182205
|
182206
|
182207
|
182208
|
182209
|
182210
|
182211
|
182339
|
182340
|
182341
|
182342
|
182343
|
182428
|
182429
|
182430
|
182431
|
182432
|
182433
|
182434
|
182478
|
182480
|
182481
|
182482
|
182483
|
182484
|
182485
|
182486
|
182487
|
182493
|
182494
|
182495
|
182496
|
182497
|
182498
|
182499
|
182500
|
182577
|
182578