From 3a1db3cc47f4e109361091c481946dd0f554dc38 Mon Sep 17 00:00:00 2001 From: Jake Dallimore Date: Mon, 7 Aug 2023 17:17:27 +0800 Subject: [PATCH] MDL-78576 mod_lti: improve course tool deletion with contextual messages Present different deletion messages depending on whether the tool has usages or not. --- mod/lti/amd/build/course_tools_list.min.js | 2 +- .../amd/build/course_tools_list.min.js.map | 2 +- mod/lti/amd/src/course_tools_list.js | 38 +++++++++---------- .../course_external_tools_list.php | 5 ++- mod/lti/lang/en/lti.php | 7 ++-- mod/lti/tests/behat/managecoursetools.feature | 10 ++--- 6 files changed, 33 insertions(+), 31 deletions(-) diff --git a/mod/lti/amd/build/course_tools_list.min.js b/mod/lti/amd/build/course_tools_list.min.js index 991eba8c9d2..097ff13542f 100644 --- a/mod/lti/amd/build/course_tools_list.min.js +++ b/mod/lti/amd/build/course_tools_list.min.js @@ -1,3 +1,3 @@ -define("mod_lti/course_tools_list",["exports","core/notification","core/pending","core/ajax","core/toast","core/prefetch","core/str","core_table/dynamic","core_table/local/dynamic/selectors"],(function(_exports,_notification,_pending,_ajax,_toast,_prefetch,_str,_dynamic,Selectors){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_notification=_interopRequireDefault(_notification),_pending=_interopRequireDefault(_pending),_ajax=_interopRequireDefault(_ajax),Selectors=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Selectors);_exports.init=()=>{(0,_prefetch.prefetchStrings)("mod_lti",["deletecoursetool","deletecoursetoolconfirm","coursetooldeleted"]),(0,_prefetch.prefetchStrings)("core",["delete"]),document.addEventListener("click",(event=>{const courseToolDelete=event.target.closest('[data-action="course-tool-delete"]');if(courseToolDelete){event.preventDefault();const triggerElement=courseToolDelete.closest(".dropdown").querySelector(".dropdown-toggle");_notification.default.saveCancelPromise((0,_str.get_string)("deletecoursetool","mod_lti"),(0,_str.get_string)("deletecoursetoolconfirm","mod_lti",courseToolDelete.dataset.courseToolName),(0,_str.get_string)("delete","core"),{triggerElement:triggerElement}).then((()=>{const pendingPromise=new _pending.default("mod_lti/course_tools:delete"),request={methodname:"mod_lti_delete_course_tool_type",args:{tooltypeid:courseToolDelete.dataset.courseToolId}};return _ajax.default.call([request])[0].then((0,_toast.add)((0,_str.get_string)("coursetooldeleted","mod_lti"))).then((()=>{const tableRoot=triggerElement.closest(Selectors.main.region);return(0,_dynamic.refreshTableContent)(tableRoot)})).then(pendingPromise.resolve).catch(_notification.default.exception)})).catch((()=>{}))}}))}})); +define("mod_lti/course_tools_list",["exports","core/notification","core/pending","core/ajax","core/toast","core/str","core_table/dynamic","core_table/local/dynamic/selectors"],(function(_exports,_notification,_pending,_ajax,_toast,_str,_dynamic,Selectors){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_notification=_interopRequireDefault(_notification),_pending=_interopRequireDefault(_pending),_ajax=_interopRequireDefault(_ajax),Selectors=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Selectors);_exports.init=()=>{document.addEventListener("click",(event=>{const courseToolDelete=event.target.closest('[data-action="course-tool-delete"]');if(courseToolDelete){event.preventDefault();const deleteBodyStringId=courseToolDelete.dataset.courseToolUsage>0?"deletecoursetoolwithusageconfirm":"deletecoursetoolconfirm",requiredStrings=[{key:"deletecoursetool",component:"mod_lti",param:courseToolDelete.dataset.courseToolName},{key:deleteBodyStringId,component:"mod_lti",param:courseToolDelete.dataset.courseToolName},{key:"delete",component:"core",param:courseToolDelete.dataset.courseToolName},{key:"coursetooldeleted",component:"mod_lti",param:courseToolDelete.dataset.courseToolName}],triggerElement=courseToolDelete.closest(".dropdown").querySelector(".dropdown-toggle");(0,_str.get_strings)(requiredStrings).then((_ref=>{let[modalTitle,modalBody,deleteLabel]=_ref;return _notification.default.deleteCancelPromise(modalTitle,modalBody,deleteLabel,{triggerElement:triggerElement})})).then((()=>{const pendingPromise=new _pending.default("mod_lti/course_tools:delete"),request={methodname:"mod_lti_delete_course_tool_type",args:{tooltypeid:courseToolDelete.dataset.courseToolId}};return _ajax.default.call([request])[0].then((0,_toast.add)((0,_str.get_string)("coursetooldeleted","mod_lti",courseToolDelete.dataset.courseToolName))).then((()=>{const tableRoot=triggerElement.closest(Selectors.main.region);return(0,_dynamic.refreshTableContent)(tableRoot)})).then(pendingPromise.resolve).catch(_notification.default.exception)})).catch((()=>{}))}}))}})); //# sourceMappingURL=course_tools_list.min.js.map \ No newline at end of file diff --git a/mod/lti/amd/build/course_tools_list.min.js.map b/mod/lti/amd/build/course_tools_list.min.js.map index 13e18320ae4..9a7005049b9 100644 --- a/mod/lti/amd/build/course_tools_list.min.js.map +++ b/mod/lti/amd/build/course_tools_list.min.js.map @@ -1 +1 @@ -{"version":3,"file":"course_tools_list.min.js","sources":["../src/course_tools_list.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Course LTI External tools list management.\n *\n * @module mod_lti/course_tools_list\n * @copyright 2023 Jake Dallimore \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n\"use strict\";\n\nimport Notification from 'core/notification';\nimport Pending from 'core/pending';\nimport Ajax from 'core/ajax';\nimport {add as addToast} from 'core/toast';\nimport {prefetchStrings} from 'core/prefetch';\nimport {get_string as getString} from 'core/str';\nimport {refreshTableContent} from 'core_table/dynamic';\nimport * as Selectors from 'core_table/local/dynamic/selectors';\n\n/**\n * Initialise module.\n */\nexport const init = () => {\n prefetchStrings('mod_lti', [\n 'deletecoursetool',\n 'deletecoursetoolconfirm',\n 'coursetooldeleted'\n ]);\n\n prefetchStrings('core', [\n 'delete',\n ]);\n\n document.addEventListener('click', event => {\n\n const courseToolDelete = event.target.closest('[data-action=\"course-tool-delete\"]');\n if (courseToolDelete) {\n event.preventDefault();\n\n // Use triggerElement to return focus to the action menu toggle.\n const triggerElement = courseToolDelete.closest('.dropdown').querySelector('.dropdown-toggle');\n Notification.saveCancelPromise(\n getString('deletecoursetool', 'mod_lti'),\n getString('deletecoursetoolconfirm', 'mod_lti', courseToolDelete.dataset.courseToolName),\n getString('delete', 'core'),\n {triggerElement}\n ).then(() => {\n const pendingPromise = new Pending('mod_lti/course_tools:delete');\n\n const request = {\n methodname: 'mod_lti_delete_course_tool_type',\n args: {tooltypeid: courseToolDelete.dataset.courseToolId}\n };\n return Ajax.call([request])[0]\n .then(addToast(getString('coursetooldeleted', 'mod_lti')))\n .then(() => {\n const tableRoot = triggerElement.closest(Selectors.main.region);\n return refreshTableContent(tableRoot);\n })\n .then(pendingPromise.resolve)\n .catch(Notification.exception);\n }).catch(() => {\n return;\n });\n }\n });\n};\n"],"names":["document","addEventListener","event","courseToolDelete","target","closest","preventDefault","triggerElement","querySelector","saveCancelPromise","dataset","courseToolName","then","pendingPromise","Pending","request","methodname","args","tooltypeid","courseToolId","Ajax","call","tableRoot","Selectors","main","region","resolve","catch","Notification","exception"],"mappings":"8/CAqCoB,mCACA,UAAW,CACvB,mBACA,0BACA,oDAGY,OAAQ,CACpB,WAGJA,SAASC,iBAAiB,SAASC,cAEzBC,iBAAmBD,MAAME,OAAOC,QAAQ,yCAC1CF,iBAAkB,CAClBD,MAAMI,uBAGAC,eAAiBJ,iBAAiBE,QAAQ,aAAaG,cAAc,0CAC9DC,mBACT,mBAAU,mBAAoB,YAC9B,mBAAU,0BAA2B,UAAWN,iBAAiBO,QAAQC,iBACzE,mBAAU,SAAU,QACpB,CAACJ,eAAAA,iBACHK,MAAK,WACGC,eAAiB,IAAIC,iBAAQ,+BAE7BC,QAAU,CACZC,WAAY,kCACZC,KAAM,CAACC,WAAYf,iBAAiBO,QAAQS,sBAEzCC,cAAKC,KAAK,CAACN,UAAU,GACvBH,MAAK,eAAS,mBAAU,oBAAqB,aAC7CA,MAAK,WACIU,UAAYf,eAAeF,QAAQkB,UAAUC,KAAKC,eACjD,gCAAoBH,cAE9BV,KAAKC,eAAea,SACpBC,MAAMC,sBAAaC,cACzBF,OAAM"} \ No newline at end of file +{"version":3,"file":"course_tools_list.min.js","sources":["../src/course_tools_list.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Course LTI External tools list management.\n *\n * @module mod_lti/course_tools_list\n * @copyright 2023 Jake Dallimore \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n\"use strict\";\n\nimport Notification from 'core/notification';\nimport Pending from 'core/pending';\nimport Ajax from 'core/ajax';\nimport {add as addToast} from 'core/toast';\nimport {get_string as getString, get_strings as getStrings} from 'core/str';\nimport {refreshTableContent} from 'core_table/dynamic';\nimport * as Selectors from 'core_table/local/dynamic/selectors';\n\n/**\n * Initialise module.\n */\nexport const init = () => {\n document.addEventListener('click', event => {\n\n const courseToolDelete = event.target.closest('[data-action=\"course-tool-delete\"]');\n if (courseToolDelete) {\n event.preventDefault();\n\n // A different message is used in the modal if the tool has usages within the course.\n const usage = courseToolDelete.dataset.courseToolUsage;\n const deleteBodyStringId = usage > 0 ? 'deletecoursetoolwithusageconfirm' : 'deletecoursetoolconfirm';\n const requiredStrings = [\n {key: 'deletecoursetool', component: 'mod_lti', param: courseToolDelete.dataset.courseToolName},\n {key: deleteBodyStringId, component: 'mod_lti', param: courseToolDelete.dataset.courseToolName},\n {key: 'delete', component: 'core', param: courseToolDelete.dataset.courseToolName},\n {key: 'coursetooldeleted', component: 'mod_lti', param: courseToolDelete.dataset.courseToolName}\n ];\n // Use triggerElement to return focus to the action menu toggle.\n const triggerElement = courseToolDelete.closest('.dropdown').querySelector('.dropdown-toggle');\n\n getStrings(requiredStrings).then(([modalTitle, modalBody, deleteLabel]) => {\n return Notification.deleteCancelPromise(\n modalTitle,\n modalBody,\n deleteLabel,\n {triggerElement});\n }).then(() => {\n const pendingPromise = new Pending('mod_lti/course_tools:delete');\n\n const request = {\n methodname: 'mod_lti_delete_course_tool_type',\n args: {tooltypeid: courseToolDelete.dataset.courseToolId}\n };\n return Ajax.call([request])[0]\n .then(addToast(getString('coursetooldeleted', 'mod_lti', courseToolDelete.dataset.courseToolName)))\n .then(() => {\n const tableRoot = triggerElement.closest(Selectors.main.region);\n return refreshTableContent(tableRoot);\n })\n .then(pendingPromise.resolve)\n .catch(Notification.exception);\n }).catch(() => {\n return;\n });\n }\n });\n};\n"],"names":["document","addEventListener","event","courseToolDelete","target","closest","preventDefault","deleteBodyStringId","dataset","courseToolUsage","requiredStrings","key","component","param","courseToolName","triggerElement","querySelector","then","_ref","modalTitle","modalBody","deleteLabel","Notification","deleteCancelPromise","pendingPromise","Pending","request","methodname","args","tooltypeid","courseToolId","Ajax","call","tableRoot","Selectors","main","region","resolve","catch","exception"],"mappings":"o+CAoCoB,KAChBA,SAASC,iBAAiB,SAASC,cAEzBC,iBAAmBD,MAAME,OAAOC,QAAQ,yCAC1CF,iBAAkB,CAClBD,MAAMI,uBAIAC,mBADQJ,iBAAiBK,QAAQC,gBACJ,EAAI,mCAAqC,0BACtEC,gBAAkB,CACpB,CAACC,IAAK,mBAAoBC,UAAW,UAAWC,MAAOV,iBAAiBK,QAAQM,gBAChF,CAACH,IAAKJ,mBAAoBK,UAAW,UAAWC,MAAOV,iBAAiBK,QAAQM,gBAChF,CAACH,IAAK,SAAUC,UAAW,OAAQC,MAAOV,iBAAiBK,QAAQM,gBACnE,CAACH,IAAK,oBAAqBC,UAAW,UAAWC,MAAOV,iBAAiBK,QAAQM,iBAG/EC,eAAiBZ,iBAAiBE,QAAQ,aAAaW,cAAc,yCAEhEN,iBAAiBO,MAAKC,WAAEC,WAAYC,UAAWC,yBAC/CC,sBAAaC,oBAChBJ,WACAC,UACAC,YACA,CAACN,eAAAA,oBACNE,MAAK,WACEO,eAAiB,IAAIC,iBAAQ,+BAE7BC,QAAU,CACZC,WAAY,kCACZC,KAAM,CAACC,WAAY1B,iBAAiBK,QAAQsB,sBAEzCC,cAAKC,KAAK,CAACN,UAAU,GACvBT,MAAK,eAAS,mBAAU,oBAAqB,UAAWd,iBAAiBK,QAAQM,kBACjFG,MAAK,WACIgB,UAAYlB,eAAeV,QAAQ6B,UAAUC,KAAKC,eACjD,gCAAoBH,cAE9BhB,KAAKO,eAAea,SACpBC,MAAMhB,sBAAaiB,cACzBD,OAAM"} \ No newline at end of file diff --git a/mod/lti/amd/src/course_tools_list.js b/mod/lti/amd/src/course_tools_list.js index ca234c11436..9c16e2a2ef3 100644 --- a/mod/lti/amd/src/course_tools_list.js +++ b/mod/lti/amd/src/course_tools_list.js @@ -27,8 +27,7 @@ import Notification from 'core/notification'; import Pending from 'core/pending'; import Ajax from 'core/ajax'; import {add as addToast} from 'core/toast'; -import {prefetchStrings} from 'core/prefetch'; -import {get_string as getString} from 'core/str'; +import {get_string as getString, get_strings as getStrings} from 'core/str'; import {refreshTableContent} from 'core_table/dynamic'; import * as Selectors from 'core_table/local/dynamic/selectors'; @@ -36,30 +35,31 @@ import * as Selectors from 'core_table/local/dynamic/selectors'; * Initialise module. */ export const init = () => { - prefetchStrings('mod_lti', [ - 'deletecoursetool', - 'deletecoursetoolconfirm', - 'coursetooldeleted' - ]); - - prefetchStrings('core', [ - 'delete', - ]); - document.addEventListener('click', event => { const courseToolDelete = event.target.closest('[data-action="course-tool-delete"]'); if (courseToolDelete) { event.preventDefault(); + // A different message is used in the modal if the tool has usages within the course. + const usage = courseToolDelete.dataset.courseToolUsage; + const deleteBodyStringId = usage > 0 ? 'deletecoursetoolwithusageconfirm' : 'deletecoursetoolconfirm'; + const requiredStrings = [ + {key: 'deletecoursetool', component: 'mod_lti', param: courseToolDelete.dataset.courseToolName}, + {key: deleteBodyStringId, component: 'mod_lti', param: courseToolDelete.dataset.courseToolName}, + {key: 'delete', component: 'core', param: courseToolDelete.dataset.courseToolName}, + {key: 'coursetooldeleted', component: 'mod_lti', param: courseToolDelete.dataset.courseToolName} + ]; // Use triggerElement to return focus to the action menu toggle. const triggerElement = courseToolDelete.closest('.dropdown').querySelector('.dropdown-toggle'); - Notification.saveCancelPromise( - getString('deletecoursetool', 'mod_lti'), - getString('deletecoursetoolconfirm', 'mod_lti', courseToolDelete.dataset.courseToolName), - getString('delete', 'core'), - {triggerElement} - ).then(() => { + + getStrings(requiredStrings).then(([modalTitle, modalBody, deleteLabel]) => { + return Notification.deleteCancelPromise( + modalTitle, + modalBody, + deleteLabel, + {triggerElement}); + }).then(() => { const pendingPromise = new Pending('mod_lti/course_tools:delete'); const request = { @@ -67,7 +67,7 @@ export const init = () => { args: {tooltypeid: courseToolDelete.dataset.courseToolId} }; return Ajax.call([request])[0] - .then(addToast(getString('coursetooldeleted', 'mod_lti'))) + .then(addToast(getString('coursetooldeleted', 'mod_lti', courseToolDelete.dataset.courseToolName))) .then(() => { const tableRoot = triggerElement.closest(Selectors.main.region); return refreshTableContent(tableRoot); diff --git a/mod/lti/classes/reportbuilder/local/systemreports/course_external_tools_list.php b/mod/lti/classes/reportbuilder/local/systemreports/course_external_tools_list.php index 8a4a239dfcb..ad74128a94f 100644 --- a/mod/lti/classes/reportbuilder/local/systemreports/course_external_tools_list.php +++ b/mod/lti/classes/reportbuilder/local/systemreports/course_external_tools_list.php @@ -128,7 +128,7 @@ class course_external_tools_list extends system_report { ->set_type(column::TYPE_TEXT) ->set_is_sortable(false) ->add_fields("{$entitymainalias}.id, {$entitymainalias}.course, {$entitymainalias}.name") - ->add_callback(static function($field, $row) { + ->add_callback(function($field, $row) { global $OUTPUT; // Lock actions for site-level preconfigured tools. @@ -169,7 +169,8 @@ class course_external_tools_list extends system_report { [ 'data-action' => 'course-tool-delete', 'data-course-tool-id' => $row->id, - 'data-course-tool-name' => $row->name + 'data-course-tool-name' => $row->name, + 'data-course-tool-usage' => $this->perrowtoolusage ], )); diff --git a/mod/lti/lang/en/lti.php b/mod/lti/lang/en/lti.php index 7278d957821..804d76c70bc 100644 --- a/mod/lti/lang/en/lti.php +++ b/mod/lti/lang/en/lti.php @@ -130,7 +130,7 @@ $string['courseid'] = 'Course ID number'; $string['courseinformation'] = 'Course information'; $string['courselink'] = 'Go to course'; $string['coursemisconf'] = 'Course is misconfigured'; -$string['coursetooldeleted'] = 'Course tool deleted'; +$string['coursetooldeleted'] = '{$a} removed'; $string['createdon'] = 'Created on'; $string['curllibrarymissing'] = 'PHP cURL extension required for the External tool.'; $string['custom'] = 'Custom parameters'; @@ -159,8 +159,9 @@ $string['delegate'] = 'Delegate to teacher'; $string['delegate_tool'] = 'As specified in Deep Linking definition or Delegate to teacher'; $string['delete'] = 'Delete'; $string['delete_confirmation'] = 'Are you sure you want to delete this preconfigured tool?'; -$string['deletecoursetool'] = 'Delete a course tool'; -$string['deletecoursetoolconfirm'] = 'Are you sure you want to delete this course tool?'; +$string['deletecoursetool'] = 'Delete {$a}'; +$string['deletecoursetoolconfirm'] = 'This will delete {$a} from the available LTI tools in your course.'; +$string['deletecoursetoolwithusageconfirm'] = '{$a} is currently being used in at least one activity in your course. If you delete this tool, the activities that use it will no longer work.

Are you sure you want to delete {$a}?'; $string['deletetype'] = 'Delete preconfigured tool'; $string['display_description'] = 'Display activity description when launched'; $string['display_description_help'] = 'If selected, the activity description (specified above) will display above the tool provider\'s content. diff --git a/mod/lti/tests/behat/managecoursetools.feature b/mod/lti/tests/behat/managecoursetools.feature index fd7791ae51d..df40abf4076 100644 --- a/mod/lti/tests/behat/managecoursetools.feature +++ b/mod/lti/tests/behat/managecoursetools.feature @@ -107,12 +107,12 @@ Feature: Manage course tools And I navigate to "LTI External tools" in current page administration When I open the action menu in "Test tool" "table_row" And I choose "Delete" in the open action menu - Then I should see "Are you sure you want to delete this course tool?" - And I click on "Cancel" "button" in the "Delete a course tool" "dialogue" + Then I should see "This will delete Test tool from the available LTI tools in your course." + And I click on "Cancel" "button" in the "Delete Test tool" "dialogue" And I should see "Test tool" in the "reportbuilder-table" "table" And I open the action menu in "Test tool" "table_row" And I choose "Delete" in the open action menu - And I should see "Are you sure you want to delete this course tool?" - And I click on "Delete" "button" in the "Delete a course tool" "dialogue" - And I should see "Course tool deleted" + And I should see "This will delete Test tool from the available LTI tools in your course." + And I click on "Delete" "button" in the "Delete Test tool" "dialogue" + And I should see "Test tool removed" And I should not see "Test tool" in the "reportbuilder-table" "table"