Add favorited LTI tools to RCE toolbar

Takes external tools labeled as favorite and includes them in the toolbar.
Embeds the icon into an SVG to be used as the toolbar icon.
Only shows a max of 2 favorite tools.
Also moved the tools favorites to be next to the media upload icons,
as per Peyton's request.

Includes Selenium tests

Test plan:
Enable RCE Enhancements
Activate some apps (Wikipedia and Dropbox work well)
Use Ed's new work to favorite those two apps (or one of them - you do you)
Open an RCE page.
The icons should appear in the toolbar to the right.
Clicking the icon opens up the LTI tool modal properly.

flag = rce_enhancements

Closes LS-532

Change-Id: I96ace173793093f1fd2aa9dba546e7d4cd973c42
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/240530
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Ed Schiebel <eschiebel@instructure.com>
Product-Review: Peyton Craighill <pcraighill@instructure.com>
QA-Review: Robin Kuss <rkuss@instructure.com>
This commit is contained in:
Alex Anderson 2020-06-17 16:23:41 -06:00
parent f356c25e39
commit 8855def32f
7 changed files with 73 additions and 5 deletions

View File

@ -992,6 +992,7 @@ end
{
:name => tool.label_for(:editor_button, I18n.locale),
:id => tool.id,
:favorite => tool.is_rce_favorite,
:url => tool.editor_button(:url),
:icon_url => tool.editor_button(:icon_url),
:canvas_icon_class => tool.editor_button(:canvas_icon_class),

View File

@ -958,6 +958,13 @@ class RCEWrapper extends React.Component {
this._elementRef.removeEventListener('keyup', this.handleShortcutKeyShortcut, true)
}
// Get top 2 favorited LTI Tools
ltiToolFavorites =
window.INST?.editorButtons
.filter(e => e.favorite)
.map(e => `instructure_external_button_${e.id}`)
.slice(0, 2) || []
wrapOptions(options = {}) {
const setupCallback = options.setup
@ -1019,7 +1026,8 @@ class RCEWrapper extends React.Component {
'instructure_links',
'instructure_image',
'instructure_record',
'instructure_documents'
'instructure_documents',
...this.ltiToolFavorites
]
},
{
@ -1077,6 +1085,11 @@ class RCEWrapper extends React.Component {
this._elementRef.addEventListener('keyup', this.handleShortcutKeyShortcut, true)
// give the textarea its initial size
this.onResize(null, {deltaY: 0})
// Preload the LTI Tools modal
// This helps with loading the favorited external tools
if (this.ltiToolFavorites.length > 0) {
import('./plugins/instructure_external_tools/components/LtiToolsModal')
}
}
componentDidUpdate(_prevProps, prevState) {

View File

@ -57,6 +57,7 @@ export default {
config.id = button.id
config.onAction = () => editor.execCommand(`instructureExternalButton${button.id}`)
config.description = button.description
config.favorite = button.favorite
} else {
config.cmd = `instructureExternalButton${button.id}`
}

View File

@ -92,6 +92,28 @@ const ExternalToolsPlugin = {
icon: 'lti',
tooltip: 'Apps'
})
ltiButtons.forEach(button => {
if (!button.favorite) return
// Sanitize input against XSS
const svg = document.createElement('svg')
svg.setAttribute('viewBox', '0 0 16 16')
svg.setAttribute('version', '1.1')
svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg')
const image = document.createElement('image')
image.setAttribute('xlink:href', button.image)
svg.appendChild(image)
const div = document.createElement('div')
div.appendChild(svg)
ed.ui.registry.addIcon(`favorite_lti_tool_${button.id}`, div.innerHTML)
ed.ui.registry.addButton(`instructure_external_button_${button.id}`, {
onAction: () => button.onAction(),
tooltip: button.title,
icon: `favorite_lti_tool_${button.id}`,
title: button.title
})
})
}
if (clumpedButtons.length) {
const handleClick = function() {

View File

@ -562,7 +562,8 @@ describe ApplicationHelper do
:width=>800,
:height=>400,
:use_tray => false,
:description => "<p>the description.</p>\n"
:description => "<p>the description.</p>\n",
:favorite => false
}])
end
@ -583,7 +584,8 @@ describe ApplicationHelper do
:width=>800,
:height=>400,
:use_tray => false,
:description => ""
:description => "",
:favorite => false
}])
end

View File

@ -183,6 +183,14 @@ module RCENextPage
f('[role="dialog"][aria-label="Apps"]')
end
def lti_favorite_button
possibly_hidden_toolbar_button('button[aria-label="Commons Favorites"')
end
def lti_favorite_modal
f('[role="dialog"][aria-label="Embed content from External Tool"]')
end
def course_images
f('[role="menuitem"][title="Course Images"]')
end

View File

@ -747,7 +747,8 @@ describe "RCE next tests" do
:name => "Commons",
:domain => "canvaslms.com",
:consumer_key => '12345',
:shared_secret => 'secret'
:shared_secret => 'secret',
:is_rce_favorite => "true"
})
@tool.set_extension_setting(:editor_button, {
:message_type => "ContentItemSelectionRequest",
@ -755,7 +756,8 @@ describe "RCE next tests" do
:icon_url => "https://lor.instructure.com/img/icon_commons.png",
:text => "Commons Favorites",
:enabled => "true",
:use_tray => "true"
:use_tray => "true",
:favorite => "true"
})
@tool.save!
end
@ -778,6 +780,25 @@ describe "RCE next tests" do
expect(lti_tools_modal).to be_displayed
end
it "should show favorited LTI tool icon when a tool is favorited", ignore_js_errors: true do
page_title = "Page1"
create_wiki_page_with_embedded_image(page_title)
visit_existing_wiki_edit(@course, page_title)
expect(lti_favorite_button).to be_displayed
end
it "should display the favorited lti tool modal", ignore_js_errors: true do
page_title = "Page1"
create_wiki_page_with_embedded_image(page_title)
visit_existing_wiki_edit(@course, page_title)
lti_favorite_button.click
expect(lti_favorite_modal).to be_displayed
end
end
end
end