From 23f150917665a232dbc180a376be2d977de1317b Mon Sep 17 00:00:00 2001 From: guerler Date: Mon, 18 Apr 2022 17:33:47 -0400 Subject: [PATCH] Use popper.js instead of bootstrap tours --- client/gulpfile.js | 1 - client/package.json | 2 +- client/src/bundleEntries.js | 2 +- client/src/components/Tour/Tour.vue | 103 +++++++ client/src/components/Tour/TourStep.vue | 75 ++++++ client/src/components/Tour/runTour.js | 104 +++++++ client/src/entry/analysis/AnalysisRouter.js | 9 +- client/src/mvc/tours.js | 255 ------------------ client/src/onload/globalInits/index.js | 2 - client/src/onload/globalInits/initTours.js | 7 - client/src/onload/index.js | 1 - client/src/style/scss/tour.scss | 85 +++++- client/tests/qunit/test-app.js | 1 - client/yarn.lock | 23 +- config/plugins/tours/core.galaxy_ui.yaml | 45 +--- config/plugins/tours/core.history.yaml | 19 +- config/plugins/tours/core.scratchbook.yaml | 12 +- .../webhooks/demo/tour_generator/__init__.py | 50 +--- .../webhooks/demo/tour_generator/script.js | 2 +- .../demo/tour_generator/tour_generator.js | 3 +- lib/galaxy/selenium/navigation.yml | 12 +- 21 files changed, 400 insertions(+), 413 deletions(-) create mode 100644 client/src/components/Tour/Tour.vue create mode 100644 client/src/components/Tour/TourStep.vue create mode 100644 client/src/components/Tour/runTour.js delete mode 100644 client/src/mvc/tours.js delete mode 100644 client/src/onload/globalInits/initTours.js diff --git a/client/gulpfile.js b/client/gulpfile.js index 0d188490c0b..cbe2cccd675 100644 --- a/client/gulpfile.js +++ b/client/gulpfile.js @@ -40,7 +40,6 @@ const PATHS = { // automatically. Eventually, this dictionary and staging step will // not be necessary. backbone: ["backbone.js", "backbone.js"], - "@galaxyproject/bootstrap-tour": ["build/js/bootstrap-tour.js", "bootstrap-tour.js"], jquery: ["dist/jquery.js", "jquery/jquery.js"], "jquery-migrate": ["dist/jquery-migrate.js", "jquery/jquery.migrate.js"], "jquery-mousewheel": ["jquery.mousewheel.js", "jquery/jquery.mousewheel.js"], diff --git a/client/package.json b/client/package.json index c282f509608..ce1d7cc531f 100644 --- a/client/package.json +++ b/client/package.json @@ -20,10 +20,10 @@ "@fortawesome/free-regular-svg-icons": "^5.15.4", "@fortawesome/free-solid-svg-icons": "^5.15.4", "@fortawesome/vue-fontawesome": "^2.0.6", - "@galaxyproject/bootstrap-tour": "0.12.2", "@handsontable/vue": "^2.0.0-beta1", "@hirez_io/observer-spy": "^2.1.2", "@johmun/vue-tags-input": "^2.1.0", + "@popperjs/core": "^2.11.5", "@sentry/browser": "^6.17.4", "assert": "^2.0.0", "axios": "^0.25.0", diff --git a/client/src/bundleEntries.js b/client/src/bundleEntries.js index 9780e2d917f..22cec84111c 100644 --- a/client/src/bundleEntries.js +++ b/client/src/bundleEntries.js @@ -31,7 +31,7 @@ export { default as LegacyGridView } from "legacy/grid/grid-view"; export { create_chart, create_histogram } from "reports/run_stats"; export { default as ToolshedGroups } from "toolshed/toolshed.groups"; export { openGlobalUploadModal } from "components/Upload"; - +export { runTour } from "components/Tour/runTour"; export { Toast } from "ui/toast"; // TODO: remove when external consumers are updated/gone (IES right now) export function trackster(options) { diff --git a/client/src/components/Tour/Tour.vue b/client/src/components/Tour/Tour.vue new file mode 100644 index 00000000000..a522d2322a1 --- /dev/null +++ b/client/src/components/Tour/Tour.vue @@ -0,0 +1,103 @@ + + + diff --git a/client/src/components/Tour/TourStep.vue b/client/src/components/Tour/TourStep.vue new file mode 100644 index 00000000000..61ca11d502b --- /dev/null +++ b/client/src/components/Tour/TourStep.vue @@ -0,0 +1,75 @@ + + + diff --git a/client/src/components/Tour/runTour.js b/client/src/components/Tour/runTour.js new file mode 100644 index 00000000000..7b09e71cbe5 --- /dev/null +++ b/client/src/components/Tour/runTour.js @@ -0,0 +1,104 @@ +import axios from "axios"; +import { getAppRoot } from "onload"; +import { mountVueComponent } from "utils/mountVueComponent"; +import Tour from "./Tour"; + +// delays and maximum number of attempts to wait for element +const attempts = 100; +const delay = 200; + +// return tour data +async function getTourData(tourId) { + const url = `${getAppRoot()}api/tours/${tourId}`; + const { data } = await axios.get(url); + return data; +} + +// returns the selected element +function getElement(selector) { + return document.querySelector(selector); +} + +// wait for element +function waitForElement(selector, resolve, reject, tries) { + const el = getElement(selector); + if (el) { + resolve(); + } else if (tries > 0) { + setTimeout(() => { + waitForElement(selector, resolve, reject, tries - 1); + }, delay); + } else { + console.error("Tours - Element not found.", selector); + reject(); + } +} + +// performs a click event on the selected element +function doClick(targets) { + if (targets) { + targets.forEach((selector) => { + const el = getElement(selector); + if (el) { + el.click(); + } else { + console.error("Tours - Click target not found.", selector); + } + }); + } +} + +// insert text into the selected element +function doInsert(selector, value) { + if (value !== null) { + const el = getElement(selector); + if (el) { + el.value = value; + const event = new Event("input"); + el.dispatchEvent(event); + } else { + console.error("Tours - Insert target not found.", selector); + } + } +} + +// mount tours to body +function mountTour(props) { + const container = document.createElement("div"); + const body = document.querySelector("body"); + body.append(container); + const mountFn = mountVueComponent(Tour); + return mountFn(props, container); +} + +// executes tour +export async function runTour(tourId, tourData = null) { + if (!tourData) { + tourData = await getTourData(tourId); + } + const steps = []; + Object.values(tourData.steps).forEach((step) => { + steps.push({ + target: step.element, + title: step.title, + content: step.content, + onBefore: () => { + return new Promise((resolve, reject) => { + if (step.element) { + // wait for element before continuing tour + waitForElement(step.element, resolve, reject, attempts); + } else { + resolve(); + } + }).then(() => { + doClick(step.preclick); + doInsert(step.element, step.textinsert); + }); + }, + onNext: () => { + doClick(step.postclick); + }, + }); + }); + return mountTour({ steps }); +} diff --git a/client/src/entry/analysis/AnalysisRouter.js b/client/src/entry/analysis/AnalysisRouter.js index d7405318d44..62f47c2add3 100644 --- a/client/src/entry/analysis/AnalysisRouter.js +++ b/client/src/entry/analysis/AnalysisRouter.js @@ -22,7 +22,7 @@ import UserPreferences from "components/User/UserPreferences"; import DatasetList from "components/Dataset/DatasetList"; import { getUserPreferencesModel } from "components/User/UserPreferencesModel"; import CustomBuilds from "components/User/CustomBuilds"; -import Tours from "mvc/tours"; +import { runTour } from "components/Tour/runTour"; import GridView from "mvc/grid/grid-view"; import GridShared from "mvc/grid/grid-shared"; import JobDetails from "components/JobInformation/JobDetails"; @@ -142,10 +142,9 @@ export const getAnalysisRouter = (Galaxy) => { }, show_tours: function (tour_id) { + this.home(); if (tour_id) { - Tours.giveTourById(tour_id); - } else { - this.page.display(new Tours.ToursView()); + runTour(tour_id); } }, @@ -429,7 +428,7 @@ export const getAnalysisRouter = (Galaxy) => { }, /** */ - home: function (params) { + home: function (params = {}) { // TODO: to router, remove Globals // load a tool by id (tool_id) or rerun a previous tool execution (job_id) if (params.tool_id || params.job_id) { diff --git a/client/src/mvc/tours.js b/client/src/mvc/tours.js deleted file mode 100644 index 185faf144ed..00000000000 --- a/client/src/mvc/tours.js +++ /dev/null @@ -1,255 +0,0 @@ -/** - * This is the primary galaxy tours definition, currently only used for - * rendering a tour menu. - */ -import _l from "utils/localization"; -// The following must remain staged out of libs and not sourced from -// node_modules, until TDTs are bundled. -import _ from "underscore"; -import $ from "jquery"; -import Backbone from "backbone"; -import { getAppRoot } from "onload/loadConfig"; -import "@galaxyproject/bootstrap-tour"; - -// bootstrap-tour configures a window.Tour object; keep a local ref. -const Tour = window.Tour; - -// For buttons to show, we need to add them to bootstrap/popper's sanitizing filters. -$.fn.tooltip.Constructor.Default.whiteList.button = ["data-role"]; - -var gxy_root = getAppRoot(); - -const TOURPAGE_TEMPLATE = ` -

Galaxy Tours

-

This page presents a list of interactive tours available on this Galaxy server. - Select any tour to get started (and remember, you can click 'End Tour' at any time).

- -
-
- <% _.each(tourtagorder, function(tag) { %> - - <% }); %> -
-
- -
-
-

Tours

-
    - <% _.each(tours, function(tour) { %> -
  • - > - <%- tour.attributes.name || tour.id %> - - - <%- tour.attributes.description || "No description given." %> - <% _.each(tour.attributes.tags, function(tag) { %> - - <%- tag.charAt(0).toUpperCase() + tag.slice(1) %> - - <% }); %> -
  • - <% }); %> -
-
-
`; - -var tour_opts = { - storage: window.sessionStorage, - onEnd: function () { - window.sessionStorage.removeItem("activeGalaxyTour"); - }, - delay: 150, // Attempts to make it look natural - orphan: true, -}; - -var hooked_tour_from_data = (data) => { - _.each(data.steps, (step) => { - if (step.preclick) { - step.onShow = () => { - _.each(step.preclick, (preclick) => { - // TODO: click delay between clicks - $(preclick).click(); - }); - }; - } - if (step.postclick) { - step.onHide = () => { - _.each(step.postclick, (postclick) => { - // TODO: click delay between clicks - $(postclick).click(); - }); - }; - } - if (step.textinsert) { - // Have to manually trigger a change here, for some - // elements which have additional logic, like the - // upload input box - step.onShown = () => { - $(step.element).val(step.textinsert).trigger("change"); - }; - } - if (step.path) { - // Galaxy does *not* support automagic path navigation right now in - // Tours -- too many ways to get your client 'stuck' in automatic - // navigation loops. We can probably re-enable this as our client - // routing matures. - console.warn( - "This Galaxy Tour is attempting to use path navigation. This is known to be unstable and can possibly get the Galaxy client 'stuck' in a tour, and at this time is not allowed." - ); - delete step.path; - } - }); - return data; -}; - -var TourItem = Backbone.Model.extend({ - urlRoot: `${gxy_root}api/tours`, -}); - -var Tours = Backbone.Collection.extend({ - url: `${gxy_root}api/tours`, - model: TourItem, -}); - -export var ToursView = Backbone.View.extend({ - title: _l("Tours"), - initialize: function () { - var self = this; - this.setElement("
"); - this.model = new Tours(); - this.model.fetch({ - success: function () { - self.render(); - }, - error: function () { - // Do something. - console.error("Failed to fetch tours."); - }, - }); - }, - - render: function () { - var tpl = _.template(TOURPAGE_TEMPLATE); - - var tourtags = {}; - _.each(this.model.models, (tour) => { - tour.attributes.tags_lc = []; - if (tour.attributes.tags === null) { - if (tourtags.Untagged === undefined) { - tourtags.Untagged = { name: "Untagged", tours: [] }; - } - tourtags.Untagged.tours.push(tour); - } else { - _.each(tour.attributes.tags, (otag) => { - var tag = otag.charAt(0).toUpperCase() + otag.slice(1); - if (tourtags[tag] === undefined) { - tourtags[tag] = { name: tag, tours: [] }; - } - tour.attributes.tags_lc.push(otag.toLowerCase()); - tourtags[tag].tours.push(tour); - }); - } - }); - //var tourtagorder = Object.keys(tourtags).sort(); - var tourtagorder = []; - Object.keys(tourtags).forEach(function (tag, index) { - tourtagorder.push({ name: tag, key: tag.toLowerCase() }); - }); - - this.$el - .html( - tpl({ - tours: this.model.models, - tourtags: tourtags, - tourtagorder: tourtagorder, - }) - ) - .on("click", ".tourItem", function (e) { - e.preventDefault(); - giveTourById($(this).data("tour.id")); - }) - .on("click", ".tag-selector-button", (e) => { - var elem = $(e.target); - var active_tags = []; - - // Switch classes for the buttons - elem.toggleClass("btn-primary"); - elem.toggleClass("btn-secondary"); - - // Get all non-disabled tags - $(`.tag-selector-button.btn-primary`).each(function () { - active_tags.push($(this).attr("tag-selector-button")); - }); - - // Loop over all list items, subsequently determine these are - // only the tours (tags should be unique). Then use the non-disabled tags to - // determien whether or not to display this specific tour. - $(`li.list-group-item`).each(function () { - if ($(this).attr("tags")) { - var tour_tags = []; - var tour_tags_html = $(this).attr("tags"); - - tour_tags = tour_tags_html.split(","); - var fil_tour_tags = tour_tags.filter(function (tag) { - return active_tags.indexOf(tag.toLowerCase()) > -1; - }); - - $(this).css("display", fil_tour_tags.length > 0 ? "block" : "none"); - } - }); - }); - }, -}); - -export function giveTourWithData(data) { - const hookedTourData = hooked_tour_from_data(data); - window.sessionStorage.setItem("activeGalaxyTour", JSON.stringify(data)); - // Store tour steps in sessionStorage to easily persist w/o hackery. - const tour = new Tour(_.extend({ steps: hookedTourData.steps }, tour_opts)); - // Always clean restart, since this is a new, explicit execution. - tour.init(); - tour.goTo(0); - tour.restart(); - return tour; -} - -export function giveTourById(tour_id) { - var url = `${gxy_root}api/tours/${tour_id}`; - $.getJSON(url, (data) => { - giveTourWithData(data); - }); -} - -export function activeGalaxyTourRunner() { - var et = JSON.parse(window.sessionStorage.getItem("activeGalaxyTour")); - if (et) { - et = hooked_tour_from_data(et); - if (et && et.steps) { - if (window && window.self === window.top) { - // Only kick off a new tour if this is the toplevel window (non-iframe). This - // functionality actually *could* be useful, but we'd need to handle it better and - // come up with some design guidelines for tours jumping between windows. - // Disabling for now. - var tour = new Tour( - _.extend( - { - steps: et.steps, - }, - tour_opts - ) - ); - tour.init(); - tour.restart(); - } - } - } -} - -export default { - ToursView: ToursView, - giveTourWithData: giveTourWithData, - giveTourById: giveTourById, - activeGalaxyTourRunner: activeGalaxyTourRunner, -}; diff --git a/client/src/onload/globalInits/index.js b/client/src/onload/globalInits/index.js index d68c49c594b..3503323e307 100644 --- a/client/src/onload/globalInits/index.js +++ b/client/src/onload/globalInits/index.js @@ -18,7 +18,6 @@ import { init_refresh_on_change } from "./init_refresh_on_change"; import { onloadWebhooks } from "./onloadWebhooks"; import { replace_big_select_inputs } from "./replace_big_select_inputs"; import { make_popup_menus } from "ui/popupmenu"; -import { initTours } from "./initTours"; import { initModals } from "./initModals"; export function globalInits() { @@ -32,7 +31,6 @@ export function globalInits() { init_refresh_on_change, () => replace_big_select_inputs(20, 1500), make_popup_menus, - initTours, onloadWebhooks ); } diff --git a/client/src/onload/globalInits/initTours.js b/client/src/onload/globalInits/initTours.js deleted file mode 100644 index 28e407ddec5..00000000000 --- a/client/src/onload/globalInits/initTours.js +++ /dev/null @@ -1,7 +0,0 @@ -import Tours from "mvc/tours"; - -export function initTours(Galaxy) { - console.log("initTours"); - Tours.activeGalaxyTourRunner(); - Galaxy.giveTourWithData = Tours.giveTourWithData; -} diff --git a/client/src/onload/index.js b/client/src/onload/index.js index a5644ce41af..bd637657363 100644 --- a/client/src/onload/index.js +++ b/client/src/onload/index.js @@ -1,7 +1,6 @@ // Bootstrap overwrites .tooltip() method, load it after jquery-ui // (which is loaded everywhere via libs/jquery.custom.js) import "bootstrap"; -import "@galaxyproject/bootstrap-tour"; // Galaxy core styles import "scss/base.scss"; diff --git a/client/src/style/scss/tour.scss b/client/src/style/scss/tour.scss index 9fdbcee7959..13aec37193f 100644 --- a/client/src/style/scss/tour.scss +++ b/client/src/style/scss/tour.scss @@ -1,4 +1,83 @@ -.tour-tour > .popover-title { - background-color: $brand-dark; - color: $white; +.tour-element { + background: $white; + border-radius: $border-radius-base; + box-shadow: 0 $border-radius-base $border-radius-extralarge $brand-dark; + max-width: 400px; + outline: none; + width: 100%; + z-index: 9999; + &-sticky { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + .tour-header { + @extend .p-1; + border-top-left-radius: $border-radius-base; + border-top-right-radius: $border-radius-base; + background: $brand-info; + .tour-title { + @extend .h5; + @extend .m-0; + @extend .p-1; + color: $white; + } + } + .tour-content { + @extend .p-2; + border-radius: $border-radius-base; + color: $text-color; + } + .tour-buttons { + @extend .float-right; + @extend .p-2; + .tour-button { + @extend .ml-1; + @extend .btn; + @extend .btn-sm; + @extend .btn-info; + } + } +} + +.tour-element, +.tour-element *, +.tour-element :after, +.tour-element :before { + box-sizing: border-box; +} + +.tour-arrow, +.tour-arrow:before { + height: 16px; + width: 16px; + position: absolute; + z-index: -1; +} + +.tour-arrow:before { + background: $white; + content: ""; + transform: rotate(45deg); +} + +.tour-element[data-popper-placement^="top"] > .tour-arrow { + bottom: -8px; +} + +.tour-element[data-popper-placement^="bottom"] > .tour-arrow { + top: -8px; +} + +.tour-element[data-popper-placement^="left"] > .tour-arrow { + right: -8px; +} + +.tour-element[data-popper-placement^="right"] > .tour-arrow { + left: -8px; +} + +.tour-element.tour-has-title[data-popper-placement^="bottom"] > .tour-arrow:before { + background-color: $brand-info; } diff --git a/client/tests/qunit/test-app.js b/client/tests/qunit/test-app.js index d8c5619cf68..bf7ebe36332 100644 --- a/client/tests/qunit/test-app.js +++ b/client/tests/qunit/test-app.js @@ -3,7 +3,6 @@ // jQuery.fn.tooltip lives on one of these 2 libs import "bootstrap"; -import "@galaxyproject/bootstrap-tour"; import sinon from "sinon"; import Backbone from "backbone"; diff --git a/client/yarn.lock b/client/yarn.lock index d85a2b8de1c..ac21fbd3870 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -1167,15 +1167,6 @@ resolved "https://registry.yarnpkg.com/@fortawesome/vue-fontawesome/-/vue-fontawesome-2.0.6.tgz#87e691ed87f28f4667238573a29743f543a087f6" integrity sha512-V3vT3flY15AKbUS31aZOP12awQI3aAzkr2B1KnqcHLmwrmy51DW3pwyBczKdypV8QxBZ8U68Hl2XxK2nudTxpg== -"@galaxyproject/bootstrap-tour@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@galaxyproject/bootstrap-tour/-/bootstrap-tour-0.12.2.tgz#9277e2dd976b8c778927c70d8180bb7a7090f009" - integrity sha512-iGmRhRhoq5vuhgVNig5/Hiu+86emgBDMtB12vo0ApAh9K+1lSnb8NLvfxDOOD7XlO9n4UMFJ5xnjSzeKCnOhqQ== - dependencies: - bootstrap ">=4.0.0-beta" - jquery "^3.0.0" - popper.js "^1.12.3" - "@handsontable/vue@^2.0.0-beta1": version "2.0.0" resolved "https://registry.yarnpkg.com/@handsontable/vue/-/vue-2.0.0.tgz#28ae7d247a89738088abc32584562925dde18db0" @@ -1440,6 +1431,11 @@ consola "^2.15.0" node-fetch "^2.6.1" +"@popperjs/core@^2.11.5": + version "2.11.5" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64" + integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw== + "@sentry/browser@^6.17.4": version "6.17.4" resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.17.4.tgz#c2711a12e89dab4abecd9a04716c07c86712fa5a" @@ -2664,11 +2660,6 @@ bootstrap@4.6, "bootstrap@>=4.5.3 <5.0.0": resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.6.1.tgz#bc25380c2c14192374e8dec07cf01b2742d222a2" integrity sha512-0dj+VgI9Ecom+rvvpNZ4MUZJz8dcX7WCX+eTID9+/8HgOkv3dsRzi8BGeZJCQU6flWQVYxwTQnEZFrmJSEO7og== -bootstrap@>=4.0.0-beta: - version "5.1.3" - resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.1.3.tgz#ba081b0c130f810fa70900acbc1c6d3c28fa8f34" - integrity sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q== - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -6159,7 +6150,7 @@ jquery@2: resolved "https://registry.yarnpkg.com/jquery/-/jquery-2.2.4.tgz#2c89d6889b5eac522a7eea32c14521559c6cbf02" integrity sha1-LInWiJterFIqfuoywUUhVZxsvwI= -jquery@>=1.12.0, "jquery@>=1.8.0 <4.0.0", jquery@^3.0.0: +jquery@>=1.12.0, "jquery@>=1.8.0 <4.0.0": version "3.6.0" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470" integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw== @@ -7496,7 +7487,7 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -popper.js@^1.12.3, popper.js@^1.16.1: +popper.js@^1.16.1: version "1.16.1" resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== diff --git a/config/plugins/tours/core.galaxy_ui.yaml b/config/plugins/tours/core.galaxy_ui.yaml index 7c6ae938ca1..39e3a26fe6e 100644 --- a/config/plugins/tours/core.galaxy_ui.yaml +++ b/config/plugins/tours/core.galaxy_ui.yaml @@ -11,8 +11,7 @@ steps: # If you don't specify any title, a default title is used, defined above. - title: "Welcome to Galaxy" # 'content' is the actual text that is shown to the user - content: "This short tour will guide you through Galaxy's user interface.
- You can navigate with your arrow keys and leave the tour at any time point with 'Escape' or the 'End tour' button." + content: "This short tour will guide you through Galaxy's user interface. You can leave the tour at any time by pressing escape." # backdrop is just one of many properties you can attach to one step-container, # a full reference can be found at http://bootstraptour.com/api/ backdrop: true @@ -21,10 +20,7 @@ steps: # In this case we want to highlight the Upload button with the `.upload-button` selector - title: "Upload your data" element: ".upload-button" - intro: "Galaxy supports many ways to get in your data.
- Use this button to upload your data." - # position of the text box relative to the selected element - position: "right" + intro: "Galaxy supports many ways to get in your data. Use this button to upload your data." # You can trigger click() events on arbitrary elements before (preclick) or after (postclick) the element is shown postclick: - ".upload-button" @@ -32,19 +28,16 @@ steps: - title: "Upload your data" element: "#btn-local" intro: "You can upload data from your computer." - position: "top" postclick: - "#btn-new" - title: "Upload your data" element: "#btn-new" intro: "Copy and paste data directly into Galaxy or include URLs that lead to your data" - position: "top" - title: "Insert URLs" - element: ".upload-text-content:first" + element: ".upload-text-content" intro: "URLs separated by a line break are automatically downloaded by Galaxy." - position: "top" textinsert: | https://raw.githubusercontent.com/bgruening/galaxytools/adf077b912ddebd97b07b947b855cdd2862ed8ef/tools/augustus/test-data/human_augustus.fa https://raw.githubusercontent.com/bgruening/galaxytools/adf077b912ddebd97b07b947b855cdd2862ed8ef/tools/sailfish/test-data/reads_2.fastq @@ -53,61 +46,51 @@ steps: - title: "Start the upload" element: "#btn-start" intro: "Upload the data into your Galaxy history." - position: "top" postclick: - "#btn-start" - title: "Close upload/download manager" element: "#btn-close" intro: "Close the upload manager with this button or with a click outside of the manager window." - position: "top" postclick: - "#btn-close" - title: "Tools" element: "#left" intro: "This is your ToolBox. All tools available in your Galaxy instance you can find here." - position: "right" - title: "Tool categories" element: '.toolSectionTitle' intro: "Tools are grouped into categories to make them easier to find." - position: "right" - title: "Tool search bar" element: '.search-query' intro: "You can search for tools by keywords." - position: "right" textinsert: 'filter' - title: "Select a tool" element: 'a[href$="tool_runner?tool_id=Filter1"]' intro: "Select and load a tool for your analysis by clicking the underlined link." - position: "right" postclick: - 'a[href$="tool_runner?tool_id=Filter1"]' - title: "Filter Tool" element: '.center-panel' intro: "Your tool is loaded into the main Galaxy page and ready for use." - position: "right" - title: "Tool parameters" element: '.center-panel .portlet-content' intro: "Here you can choose your tool parameters. Select your input dataset from your history and specify parameters for your analysis." - position: "right" - title: "Tool help" element: 'div.form-help' intro: "Every Galaxy tool has a help section with detailed information about the tool and its parameters. Have a look and study your tool in depth by reading it." - position: "top" - title: "Run your tool" element: '#execute' intro: "Click on 'Execute' to run your tool and send it to the compute cluster. Don't be afraid to test different settings in parallel. Galaxy can handle multiple runs of the same tool." - position: "right" postclick: - '#execute' @@ -116,88 +99,72 @@ steps: intro: "This is your Galaxy history! All analysis steps with results of the tools and their parameters will be recorded here and can be redone at any time.
A running tool is shown in yellow and if your calculation is done, it turns green. If your dataset is grey this means you are queued and need to wait until your tool can be started. If your dataset turns into red, an error has occurred. Please report the bug to the Galaxy team with the bug report button." - position: "left" - title: "View dataset" element: "#current-history-panel div.content-item button[title='Display']" intro: "View your dataset by clicking the eye button." - position: "left" - title: "Rename dataset" element: "#current-history-panel div.content-item button[title='Edit attributes']" intro: "Rename your dataset by clicking the pencil button." - position: "left" - title: "Dataset information" element: "div.content-item .content-title" intro: "This is your dataset. You can get more informations and options like different visualizations by clicking on it." - position: "left" postclick: - "div.content-item .content-title" - + - title: "Remove dataset" element: "#current-history-panel div.content-item button[title='Delete']" intro: "Delete your dataset by clicking the trash-button." - position: "left" - title: "Dataset information" element: "#current-history-panel div.content-item button[title='Dataset Details']" intro: "Clicking on your dataset provides you with more information regarding your dataset (e.g. filetype or size)." - position: "left" preclick: - "#current-history-panel div.content-item button[title='Dataset Details']" - title: "Re-run tool" element: "#current-history-panel div.content-item button[title='Run Job Again']" intro: "By clicking the reload button, you can re-run your tool again (e.g. with different parameters or on another dataset)." - position: "left" - title: "Panel collapse" element: "#left > div.unified-panel-footer > div.panel-collapse.left" intro: "To extend the view for your main Galaxy page in the middle, you can collapse the tool panel on the left hand side. Clicking the panel arrow on the right hand side, collapses the history." - position: "top" postclick: - "#left > div.unified-panel-footer > div.panel-collapse.left" - title: 'Top panel' element: "#masthead" intro: "The top panel will give you access to a lot of useful things." - position: "bottom" - title: 'Analyze data' element: "#analysis" - intro: "This is the current view. Start your analysis from here." - position: "bottom" + intro: "This is the current view. Start your Analysis from here." - title: 'Workflow' element: "#workflow" intro: "Create, manage, import, export and share your Workflows." - position: "bottom" - title: 'Shared data' element: "#shared" intro: "Get access to all Workflows, Histories, Pages, Visualizations and your Data Library that are shared with you." - position: "bottom" - title: 'Visualization' element: "#visualization" - intro: "Do you want to start to visualize your data in Trackster? Start here!
Galaxy offers a lot more visualizations!" - position: "bottom" + intro: "Galaxy offers a lot of visualizations to review your data!" - title: 'Help' element: "#help" intro: "Here you get more help from the Galaxy Community with Videos, a QA board and more tours." - position: "bottom" - title: 'User Preferences' element: "#user" intro: "Login and start your analysis!" - position: "bottom" - title: 'Scratchbook' element: "#enable-scratchbook" intro: "Scratchbook offers you multiple visualizations next to each other. Have a look at our Scratchbook tour to learn more about it." - position: "bottom" - title: "Enjoy Galaxy" intro: "Thanks for taking this tour! Happy research with Galaxy!" diff --git a/config/plugins/tours/core.history.yaml b/config/plugins/tours/core.history.yaml index ef69119b37e..af939f5714b 100644 --- a/config/plugins/tours/core.history.yaml +++ b/config/plugins/tours/core.history.yaml @@ -13,26 +13,22 @@ steps: intro: | At first we upload some data into your Galaxy history.
Use this button to upload your data. - position: "right" postclick: - ".upload-button" - title: "Upload your data" element: "#btn-local" intro: "You can upload data from your computer." - position: "top" postclick: - "#btn-new" - title: "Upload your data" element: "#btn-new" intro: "Copy and paste data directly into Galaxy or include URLs that lead to your data." - position: "top" - title: "Insert URLs" element: ".upload-text-content" intro: "URLs separated by a line break are automatically downloaded by Galaxy." - position: "bottom" textinsert: | https://raw.githubusercontent.com/galaxyproject/galaxy/dev/test-data/1.fasta https://raw.githubusercontent.com/bgruening/galaxytools/adf077b912ddebd97b07b947b855cdd2862ed8ef/tools/statistics/test-data/anderson.tabular @@ -40,7 +36,6 @@ steps: - title: "Start the upload" element: "#btn-start" intro: "Upload the data into your Galaxy History." - position: "top" postclick: - "#btn-start" - "#btn-close" @@ -48,50 +43,42 @@ steps: - title: "History" element: "#right" intro: "This is your history! All analysis steps will be recorded and can be redone at any time." - position: "left" - title: "Dataset information" element: "div.content-item .content-title" intro: "This is one of your uploaded datasets. You can get more informations and options like different visualizations by clicking on it." - position: "left" postclick: - "div.content-item .content-title" - title: "Metadata" element: "#current-history-panel div.content-item span.datatype" intro: "Galaxy has assigned a datatype to your dataset during upload, which you can see here." - position: "left" - element: "#current-history-panel div.content-item button[title='Download']" title: "Download your dataset" intro: "You can download every dataset by using the floppy disc symbol." - position: "left" - element: "#current-history-panel div.content-item button[title='Dataset Details']" title: "Even more information" intro: "Get an overview of all metadata associated with your dataset by using the Information symbol." - position: "left" preclick: - "#current-history-panel div.content-item button[title='Dataset Details']" - element: "#current-history-panel div.content-item button[title='Display']" title: "Inspect your data" intro: "The eye symbol can be used to look at your data." - position: "left" preclick: - "#current-history-panel div.content-item button[title='Display']" - element: "#current-history-panel div.content-item button[title='Edit attributes']" title: "Edit metadata" intro: "With the pencil button you can edit metadata attributes of your dataset, like the associated filetype or the dataset name." - position: "left" preclick: - "#current-history-panel div.content-item button[title='Edit attributes']" - element: "#current-history-panel div.content-item button[title='Delete']" title: "Remove datasets" intro: "You can remove a dataset from the history with the cross symbol." - position: "left" postclick: - "#current-history-panel div.content-item button[title='Delete']" @@ -99,27 +86,23 @@ steps: title: "Filter your datasets" intro: "By default your history will hide all deleted datasets from you. You can visualize them by filtering." textinsert: "deleted=true" - position: "bottom" - element: "#current-history-panel div.content-item button[title='Undelete']" title: "Undeleting a dataset" intro: | Galaxy datasets are only marked as deleted and can be recovered by clicking this link. Please note that datasets marked as deleted can be purged by your administrator at any time. - position: "bottom" postclick: - "#current-history-panel div.content-item button[title='Undelete']" - element: "#current-history-panel [data-description='filter text input']" title: "Search your History" intro: "You can filter your history by typing your search term in here. Galaxy supports more advanced filters that can be seen here." - position: "left" - textinsert: "WWFSMD" + textinsert: "" - element: "#current-history-panel [title='Show history options']" title: "History Options" intro: "In the History menu you will find a lot more useful History options." - position: "left" postclick: - "#current-history-panel [title='Show history options']" diff --git a/config/plugins/tours/core.scratchbook.yaml b/config/plugins/tours/core.scratchbook.yaml index a2acd33c1c0..31e35319713 100644 --- a/config/plugins/tours/core.scratchbook.yaml +++ b/config/plugins/tours/core.scratchbook.yaml @@ -11,19 +11,16 @@ steps: - element: "#tool-panel-upload-button" intro: "Before using the Scratchbook, we will upload some tabular data." - position: "right" postclick: - "#tool-panel-upload-button" - element: "#btn-new" intro: "We will be using the paste feature to create a new dataset." - position: "top" postclick: - "#btn-new" - element: ".upload-text-content" intro: "...and paste content into the text area field." - position: "top" textinsert: | 1 0.039 0.000 2 0.455 0.000 @@ -36,47 +33,40 @@ steps: - element: ".upload-settings" intro: "Now, we may further configure the upload content." - position: "right" postclick: - ".upload-settings" - element: ".upload-space_to_tab" intro: "...by specifying that all spaces in our table should be converted into tabs." - position: "left" postclick: - ".upload-space_to_tab" + - ".popover-close" - element: "#btn-start" intro: "Upload the data into your Galaxy history." - position: "top" postclick: - "#btn-start" - element: "#btn-close" intro: "Hit the close button to close the upload dialog." - position: "top" postclick: - "#btn-close" - element: "#enable-scratchbook > .nav-link" intro: "Clicking this button will enable Galaxy's Scratchbook mode." - position: "right" postclick: - "#enable-scratchbook > .nav-link" - element: "#right" intro: "This is your history. It contains all datasets you are currently working with including our uploaded table." - position: "left" - element: "#current-history-panel div.content-item button[title='Display']" intro: "Clicking the eye-icon usually displays a dataset in the center panel." - position: "left" postclick: - "#current-history-panel div.content-item button[title='Display']" - element: "#frame-0" intro: "However while in Scratchbook mode, the dataset will be shown as resizable window." - position: "right" - title: "Done." intro: "You have created a Scratchbook view. Click on the background and select more datasets." diff --git a/config/plugins/webhooks/demo/tour_generator/__init__.py b/config/plugins/webhooks/demo/tour_generator/__init__.py index 098d2cb52f3..16219c91b40 100644 --- a/config/plugins/webhooks/demo/tour_generator/__init__.py +++ b/config/plugins/webhooks/demo/tour_generator/__init__.py @@ -12,13 +12,11 @@ class TourGenerator: def __init__(self, trans, tool_id, tool_version): self._trans = trans self._tool = self._trans.app.toolbox.get_tool(tool_id, tool_version) - self._use_datasets = True self._data_inputs = {} self._tour = {} self._hids = {} self._errors = [] - self._upload_test_data() self._generate_tour() @@ -29,26 +27,21 @@ class TourGenerator: """ if not self._tool.tests: raise ValueError("Tests are not defined.") - self._test = self._tool.tests[0] - # All inputs with the type 'data' self._data_inputs = {x.name: x for x in self._tool.input_params if x.type == "data"} - # Datasets from the section test_datasets = { input_name: self._test.inputs[input_name][0] for input_name in self._data_inputs.keys() if input_name in self._test.inputs.keys() } - # Conditional datasets for name in self._test.inputs.keys(): if "|" in name: input_name = name.split("|")[1] if input_name in self._data_inputs.keys(): test_datasets.update({input_name: self._test.inputs[name][0]}) - if not test_datasets.keys(): not_supported_input_types = [ k for k, v in self._tool.inputs.items() if v.type == "repeat" or v.type == "data_collection" @@ -60,7 +53,6 @@ class TourGenerator: # so we can generate a tour without them self._use_datasets = False return - # Upload all test datasets for input_name, input in self._data_inputs.items(): if input_name in test_datasets.keys(): @@ -68,10 +60,8 @@ class TourGenerator: input_path = self._tool.test_data_path(filename) if not input_path: raise ValueError('Test dataset "%s" doesn\'t exist.' % input_name) - upload_tool = self._trans.app.toolbox.get_tool("upload1") filename = os.path.basename(input_path) - with open(input_path, "rb") as f: content = f.read() headers = { @@ -79,11 +69,9 @@ class TourGenerator: "files_0|file_data", filename ), } - input_file = cgi_FieldStorage(headers=headers) input_file.file = input_file.make_file() input_file.file.write(content) - inputs = { "dbkey": "?", # is it always a question mark? "file_type": input.extensions[0], @@ -92,11 +80,9 @@ class TourGenerator: "files_0|to_posix_lines": "Yes", "files_0|file_data": input_file, } - params = Params(inputs, sanitize=False) incoming = params.__dict__ output = upload_tool.handle_input(self._trans, incoming, history=None) - job_errors = output.get("job_errors", []) if job_errors: # self._errors.extend(job_errors) @@ -108,7 +94,6 @@ class TourGenerator: """Generate a tour.""" tour_name = self._tool.name + " Tour" test_inputs = self._test.inputs.keys() - steps = [ { "title": tour_name, @@ -116,36 +101,34 @@ class TourGenerator: "orphan": True, } ] - for name, input in self._tool.inputs.items(): cond_case_steps = [] - if input.type == "repeat": continue - - step = {"title": input.label, "element": "[tour_id=%s]" % name, "placement": "right", "content": ""} - + step = { + "title": input.label, + "element": "[id='form-element-%s']" % name, + "placement": "right", + "content": "", + } if input.type == "text": if name in test_inputs: param = self._test.inputs[name] step["content"] = "Enter value(s): %s" % param else: step["content"] = "Enter a value" - elif input.type == "integer" or input.type == "float": if name in test_inputs: num_param = self._test.inputs[name][0] step["content"] = "Enter number: %s" % num_param else: step["content"] = "Enter a number" - elif input.type == "boolean": if name in test_inputs: choice = "Yes" if self._test.inputs[name][0] is True else "No" step["content"] = "Choose %s" % choice else: step["content"] = "Choose Yes/No" - elif input.type == "select": params = [] if name in test_inputs: @@ -158,7 +141,6 @@ class TourGenerator: step["content"] = "Select parameter(s): %s" % select_param else: step["content"] = "Select a parameter" - elif input.type == "data": if name in test_inputs: hid = self._hids[name] @@ -166,26 +148,22 @@ class TourGenerator: step["content"] = f"Select dataset: {hid}: {dataset}" else: step["content"] = "Select a dataset" - elif input.type == "conditional": param_id = f"{input.name}|{input.test_param.name}" step["title"] = input.test_param.label - step["element"] = '[tour_id="%s"]' % param_id + step["element"] = "[id='form-element-%s']" % param_id params = [] - if param_id in self._test.inputs.keys(): for option in input.test_param.static_options: for test_option in self._test.inputs[param_id]: if test_option == option[1]: params.append(option[0]) - # Conditional param cases cases = {} for case in input.cases: for key, value in case.inputs.items(): if key not in cases.keys(): cases[key] = value.label - for case_id, case_title in cases.items(): tour_id = f"{input.name}|{case_id}" if tour_id in self._test.inputs.keys(): @@ -199,32 +177,27 @@ class TourGenerator: cond_case_steps.append( { "title": case_title, - "element": '[tour_id="%s"]' % tour_id, + "element": "[id='form-element-%s']" % tour_id, "placement": "right", "content": step_msg, } ) - if params: cond_param = ", ".join(params) step["content"] = "Select parameter(s): %s" % cond_param else: step["content"] = "Select a parameter" - elif input.type == "data_column": if name in test_inputs: column_param = self._test.inputs[name][0] step["content"] = "Select Column: %s" % column_param else: step["content"] = "Select a column" - else: step["content"] = "Select a parameter" - steps.append(step) if cond_case_steps: steps.extend(cond_case_steps) # add conditional input steps - # Add the last step steps.append( { @@ -232,10 +205,8 @@ class TourGenerator: "content": "Click Execute button to run the tool.", "element": "#execute", "placement": "bottom", - # 'postclick': ['#execute'] } ) - self._tour = { "title_default": tour_name, "name": tour_name, @@ -254,21 +225,16 @@ class TourGenerator: def main(trans, webhook, params): error = "" data = {} - try: if not params or "tool_id" not in params.keys(): raise KeyError("Tool id is missing.") - if not params or "tool_version" not in params.keys(): raise KeyError("Tool version is missing.") - tool_id = params["tool_id"] tool_version = params["tool_version"] tour_generator = TourGenerator(trans, tool_id, tool_version) data = tour_generator.get_data() - except Exception as e: error = str(e) log.exception(e) - return {"success": not error, "error": error, "data": data} diff --git a/config/plugins/webhooks/demo/tour_generator/script.js b/config/plugins/webhooks/demo/tour_generator/script.js index 372b52c7334..b790d3b0fcb 100644 --- a/config/plugins/webhooks/demo/tour_generator/script.js +++ b/config/plugins/webhooks/demo/tour_generator/script.js @@ -337,5 +337,5 @@ var global = arguments[3]; var define; var t,e=arguments[3];!function(i){var n="object"==typeof self&&self.self===self&&self||"object"==typeof e&&e.global===e&&e;if("function"==typeof t&&t.amd)t(["underscore","jquery","exports"],function(t,e,s){n.Backbone=i(n,s,t,e)});else if("undefined"!=typeof exports){var s,r=require("underscore");try{s=require("jquery")}catch(o){}i(n,exports,r,s)}else n.Backbone=i(n,{},n._,n.jQuery||n.Zepto||n.ender||n.$)}(function(t,e,i,n){var s=t.Backbone,r=Array.prototype.slice;e.VERSION="1.4.1",e.$=n,e.noConflict=function(){return t.Backbone=s,this},e.emulateHTTP=!1,e.emulateJSON=!1;var o,h=e.Events={},a=/\s+/,u=function(t,e,n,s,r){var o,h=0;if(n&&"object"==typeof n){void 0!==s&&"context"in r&&void 0===r.context&&(r.context=s);for(o=i.keys(n);hthis.length&&(s=this.length),s<0&&(s+=this.length+1);var r,o,h=[],a=[],u=[],c=[],l={},d=e.add,f=e.merge,p=e.remove,g=!1,v=this.comparator&&null==s&&!1!==e.sort,m=i.isString(this.comparator)?this.comparator:null;for(o=0;o7),this._useHashChange=this._wantsHashChange&&this._hasHashChange,this._wantsPushState=!!this.options.pushState,this._hasPushState=!(!this.history||!this.history.pushState),this._usePushState=this._wantsPushState&&this._hasPushState,this.fragment=this.getFragment(),this.root=("/"+this.root+"/").replace(F,"/"),this._wantsHashChange&&this._wantsPushState){if(!this._hasPushState&&!this.atRoot()){var e=this.root.slice(0,-1)||"/";return this.location.replace(e+"#"+this.getPath()),!0}this._hasPushState&&this.atRoot()&&this.navigate(this.getHash(),{replace:!0})}if(!this._hasHashChange&&this._wantsHashChange&&!this._usePushState){this.iframe=document.createElement("iframe"),this.iframe.src="javascript:0",this.iframe.style.display="none",this.iframe.tabIndex=-1;var n=document.body,s=n.insertBefore(this.iframe,n.firstChild).contentWindow;s.document.open(),s.document.close(),s.location.hash="#"+this.fragment}var r=window.addEventListener||function(t,e){return attachEvent("on"+t,e)};if(this._usePushState?r("popstate",this.checkUrl,!1):this._useHashChange&&!this.iframe?r("hashchange",this.checkUrl,!1):this._wantsHashChange&&(this._checkUrlInterval=setInterval(this.checkUrl,this.interval)),!this.options.silent)return this.loadUrl()},stop:function(){var t=window.removeEventListener||function(t,e){return detachEvent("on"+t,e)};this._usePushState?t("popstate",this.checkUrl,!1):this._useHashChange&&!this.iframe&&t("hashchange",this.checkUrl,!1),this.iframe&&(document.body.removeChild(this.iframe),this.iframe=null),this._checkUrlInterval&&clearInterval(this._checkUrlInterval),z.started=!1},route:function(t,e){this.handlers.unshift({route:t,callback:e})},checkUrl:function(t){var e=this.getFragment();if(e===this.fragment&&this.iframe&&(e=this.getHash(this.iframe.contentWindow)),e===this.fragment)return!1;this.iframe&&this.navigate(e),this.loadUrl()},loadUrl:function(t){return!!this.matchRoot()&&(t=this.fragment=this.getFragment(t),i.some(this.handlers,function(e){if(e.route.test(t))return e.callback(t),!0}))},navigate:function(t,e){if(!z.started)return!1;e&&!0!==e||(e={trigger:!!e}),t=this.getFragment(t||"");var i=this.root;""!==t&&"?"!==t.charAt(0)||(i=i.slice(0,-1)||"/");var n=i+t;t=t.replace(B,"");var s=this.decodeFragment(t);if(this.fragment!==s){if(this.fragment=s,this._usePushState)this.history[e.replace?"replaceState":"pushState"]({},document.title,n);else{if(!this._wantsHashChange)return this.location.assign(n);if(this._updateHash(this.location,t,e.replace),this.iframe&&t!==this.getHash(this.iframe.contentWindow)){var r=this.iframe.contentWindow;e.replace||(r.document.open(),r.document.close()),this._updateHash(r.location,t,e.replace)}}return e.trigger?this.loadUrl(t):void 0}},_updateHash:function(t,e,i){if(i){var n=t.href.replace(/(javascript:|#).*$/,"");t.replace(n+"#"+e)}else t.hash="#"+e}}),e.history=new z;m.extend=_.extend=M.extend=A.extend=z.extend=function(t,e){var n,s=this;return n=t&&i.has(t,"constructor")?t.constructor:function(){return s.apply(this,arguments)},i.extend(n,s,e),n.prototype=i.create(s.prototype,t),n.prototype.constructor=n,n.__super__=s.prototype,n};var J=function(){throw new Error('A "url" property or function must be specified')},L=function(t,e){var i=e.error;e.error=function(n){i&&i.call(e.context,t,n,e),t.trigger("error",t,n,e)}};return e}); },{"underscore":"XWoq","jquery":"HlZQ"}],"wXLC":[function(require,module,exports) { -"use strict";var e=o(require("toastr")),t=o(require("backbone")),n=o(require("underscore"));function r(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(r=function(e){return e?n:t})(e)}function o(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=r(t);if(n&&n.has(e))return n.get(e);var o={},a=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&Object.prototype.hasOwnProperty.call(e,i)){var u=a?Object.getOwnPropertyDescriptor(e,i):null;u&&(u.get||u.set)?Object.defineProperty(o,i,u):o[i]=e[i]}return o.default=e,n&&n.set(e,o),o}window.TourGenerator=t.View.extend({initialize:function(t){var n=this,r=window.bundleEntries.getGalaxyInstance(),o=t.toolId,a=t.toolVersion;$("#execute").attr("tour_id","execute"),e.info("Tour generation might take some time."),$.getJSON("".concat(r.root,"api/webhooks/tour_generator/data/"),{tool_id:o,tool_version:a},function(t){t.success?t.data.useDatasets?n._getData(t):n._generateTour(t.data.tour):(e.warning("Cannot generate a tour."),console.error("Tour Generator: "+t.error))})},_getData:function(t){var r=this,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:20,a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1e3,i=[];n.each(t.data.hids,function(e){Galaxy.currHistoryPanel.collection.each(function(e){i.push(e)},"hid=".concat(e," state=ok"))}),i.length===t.data.hids.length?this._generateTour(t.data.tour):o>0?setTimeout(function(){r._getData(t,o-1)},a):(e.warning("Cannot generate a tour."),console.error("Some of the test datasets cannot be found in the history."))},_generateTour:function(e){var t=window.bundleEntries.getGalaxyInstance().giveTourWithData(e);$("#execute").on("mousedown",function(){t&&t.end()})}}); +"use strict";var e=o(require("toastr")),t=o(require("backbone")),n=o(require("underscore"));function r(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(r=function(e){return e?n:t})(e)}function o(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=r(t);if(n&&n.has(e))return n.get(e);var o={},a=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&Object.prototype.hasOwnProperty.call(e,i)){var u=a?Object.getOwnPropertyDescriptor(e,i):null;u&&(u.get||u.set)?Object.defineProperty(o,i,u):o[i]=e[i]}return o.default=e,n&&n.set(e,o),o}window.TourGenerator=t.View.extend({initialize:function(t){var n=this,r=window.bundleEntries.getGalaxyInstance(),o=t.toolId,a=t.toolVersion;$("#execute").attr("tour_id","execute"),e.info("Tour generation might take some time."),$.getJSON("".concat(r.root,"api/webhooks/tour_generator/data/"),{tool_id:o,tool_version:a},function(t){t.success?t.data.useDatasets?n._getData(t):n._generateTour(t.data.tour):(e.warning("Cannot generate a tour."),console.error("Tour Generator: "+t.error))})},_getData:function(t){var r=this,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:20,a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1e3,i=[];n.each(t.data.hids,function(e){Galaxy.currHistoryPanel.collection.each(function(e){i.push(e)},"hid=".concat(e," state=ok"))}),i.length===t.data.hids.length?this._generateTour(t.data.tour):o>0?setTimeout(function(){r._getData(t,o-1)},a):(e.warning("Cannot generate a tour."),console.error("Some of the test datasets cannot be found in the history."))},_generateTour:function(e){var t=window.bundleEntries.runTour("auto.generated",e);$("#execute").on("mousedown",function(){t&&t.end()})}}); },{"toastr":"cfPU","backbone":"kFNo","underscore":"XWoq"}]},{},["wXLC"], null) \ No newline at end of file diff --git a/config/plugins/webhooks/demo/tour_generator/tour_generator.js b/config/plugins/webhooks/demo/tour_generator/tour_generator.js index d2d0f811f32..7712fdc788f 100644 --- a/config/plugins/webhooks/demo/tour_generator/tour_generator.js +++ b/config/plugins/webhooks/demo/tour_generator/tour_generator.js @@ -50,8 +50,7 @@ window.TourGenerator = Backbone.View.extend({ } }, _generateTour: function (data) { - const Galaxy = window.bundleEntries.getGalaxyInstance(); - const tour = Galaxy.giveTourWithData(data); + const tour = window.bundleEntries.runTour("auto.generated", data); // Force ending the tour when pressing the Execute button $("#execute").on("mousedown", () => { if (tour) { diff --git a/lib/galaxy/selenium/navigation.yml b/lib/galaxy/selenium/navigation.yml index f7a5aae6e2b..2b0c98aa570 100644 --- a/lib/galaxy/selenium/navigation.yml +++ b/lib/galaxy/selenium/navigation.yml @@ -658,13 +658,11 @@ invocations: tour: popover: selectors: - _: '.popover' - - title: '${_} .popover-header' - content: '${_} .popover-body' - next: '${_} button[data-role="next"]' - previous: '${_} button[data-role="prev"]' - end: '${_} button[data-role="end"]' + _: '.tour-element' + title: '${_} .tour-title' + content: '${_} .tour-content' + next: '${_} .tour-next' + end: '${_} .tour-end' admin: