From 1097a9247ffe7717ced798c36dd7e6495ff9fddd Mon Sep 17 00:00:00 2001 From: Owen Leonard Date: Tue, 26 Apr 2022 11:29:13 +0000 Subject: [PATCH] Bug 30623: Copy permissions from one user to another This patch adds controls to the patron "Set permissions" page allowing the user to copy a set of permissions from one patron to another. The patch also makes a minor correction to global staff interface CSS to correct the appearance of non-primary split buttons. To test, apply the patch and rebuild the staff interface CSS. You may want to clear your browser cache. - Locate a patron in the staff client and choose More -> Set permissions. You might want to start with a staff patron who has multiple permissions enabled. - You should see two new buttons in the toolbar immediately above the list of permissions: "Copy settings," a split button with a secondary option to choose "Forget copied settings"; and "Paste settings" which should be disabled by default. - Clicking the "Copy settings" button should trigger the copy icon to cycle/fade from the copy icon to the check-mark icon and back to the copy icon. I thought this interaction needed some visual feedback since it doesn't otherwise trigger visible action. - Clicking the "Copy settings" button should also enable the "Paste settings" button. - Locate another patron, preferable one with permissions visibly different from your first choice. - On their "Set permissions" page, click the "Paste settings" button. The list of permissions should expand all settings and all the checkboxes should now match your original choice. - At this stage you could find another patron and paste the same permissions again. - Click "Copy settings -> Forget copied settings." The "Paste settings" button should become disabled. - Using the browser console to check the contents of Local Storage should confirm that the "copiedPermissions" entry has been removed. --- .../prog/en/modules/members/member-flags.tt | 62 ++++++++++++++++++- .../intranet-tmpl/prog/js/staff-global.js | 18 ++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/member-flags.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/member-flags.tt index e7deafe761..4d99a37b14 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/member-flags.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/member-flags.tt @@ -39,6 +39,7 @@ [% INCLUDE 'members-toolbar.inc' %] +
@@ -57,12 +58,22 @@ Clear all + +
+ + + +
+ + Paste settings
Filter:
-
+
[% FOREACH loo IN loop %] [% IF ( loo.expand ) %]
@@ -271,8 +282,57 @@ } } }); + + if( copied = getCopiedPermissions() ){ + $("#pastePermissions").removeClass("disabled"); + } + + /* write to the clipboard now */ + $("#copyPermissions").on("click", function(e){ + e.preventDefault(); + let flags = new Object(); + $("#flag_form input:checkbox").each(function(){ + flags[ $(this).attr('id') ] = $(this).prop("checked"); + }); + formText = JSON.stringify( flags ); + localStorage.setItem("copiedPermissions", formText ); + toggleBtnIcon( $(this), "fa-copy", "fa-check" ); + $("#pastePermissions").removeClass("disabled"); + }); + + $("#pastePermissions").on("click", function(e){ + e.preventDefault(); + $(".toggleall_on").click(); + let copiedPermissions = getCopiedPermissions(); + + let checkBox; + let checked; + for( const permission in copiedPermissions ){ + checkBox = `${permission}`; + checked = `${copiedPermissions[permission]}` == "true" ? true : false; + $("#" + checkBox).prop("checked", checked ); + } + }); + + $("#clearCopied").on("click", function(e){ + e.preventDefault(); + localStorage.removeItem("copiedPermissions"); + $("#pastePermissions").addClass("disabled"); + }); }); + function getCopiedPermissions(){ + const copied = localStorage.getItem("copiedPermissions"); + let copiedPermissions; + try { + copiedPermissions = JSON.parse( copied ); + return copiedPermissions; + } catch ( ex ){ + console.error("Bad parse: ", ex.message ); + return false; + } + } + function setLibrarian(){ $('input[name="flag"]').each(function() { if($(this).attr('id') != "flag-0" && !$(this).hasClass('superlib') ){ diff --git a/koha-tmpl/intranet-tmpl/prog/js/staff-global.js b/koha-tmpl/intranet-tmpl/prog/js/staff-global.js index f5dd4f9186..1e263fa364 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/staff-global.js +++ b/koha-tmpl/intranet-tmpl/prog/js/staff-global.js @@ -283,6 +283,7 @@ function logOut(){ localStorage.removeItem("bibs_selected"); localStorage.removeItem("patron_search_selections"); localStorage.removeItem("item_search_selections"); + localStorage.removeItem("copiedPermissions"); } function openHelp(){ @@ -676,3 +677,20 @@ function selectBsTabByHash( tabs_container_id ){ $('#' + tabs_container_id + ' a:first').tab('show'); } } + +/** + * Fades out a Font Awesome icon, fades in a replacement, and back + * @param {object} element - jQuery object representing the icon's container + * @param {string} start - The icon which will be temporarily replaced + * @param {string} replacement - The icon which will be the temporary replacement + */ +function toggleBtnIcon( element, start, replacement ){ + let icon = element.find( "." + start ); + icon.fadeOut( 1000, function(){ + $(this).removeClass( start ).addClass( replacement ).fadeIn( 1000, function(){ + $(this).fadeOut( 1000, function(){ + $(this).removeClass( replacement ).addClass( start ).fadeIn( 1000 ); + }); + }); + }); +} -- 2.30.2