mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Use popper.js instead of bootstrap tours
This commit is contained in:
@@ -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"],
|
||||
|
||||
+1
-1
@@ -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",
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<TourStep
|
||||
v-if="currentStep"
|
||||
:step="currentStep"
|
||||
:key="currentIndex"
|
||||
:is-playing="isPlaying"
|
||||
:is-last="isLast"
|
||||
@next="next"
|
||||
@end="end"
|
||||
@play="play" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TourStep from "./TourStep";
|
||||
|
||||
// popup display duration when auto-playing the tour
|
||||
const playDelay = 3000;
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TourStep,
|
||||
},
|
||||
props: {
|
||||
steps: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentIndex: -1,
|
||||
isPlaying: false,
|
||||
};
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener("keyup", this.handleKeyup);
|
||||
},
|
||||
computed: {
|
||||
currentStep() {
|
||||
return this.steps[this.currentIndex];
|
||||
},
|
||||
numberOfSteps() {
|
||||
return this.steps.length;
|
||||
},
|
||||
isLast() {
|
||||
return this.currentIndex === this.steps.length - 1;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.start();
|
||||
},
|
||||
methods: {
|
||||
start() {
|
||||
window.addEventListener("keyup", this.handleKeyup);
|
||||
this.currentIndex = 0;
|
||||
},
|
||||
play(isPlaying) {
|
||||
this.isPlaying = isPlaying;
|
||||
if (this.isPlaying) {
|
||||
this.next();
|
||||
}
|
||||
},
|
||||
async next() {
|
||||
// do post-actions
|
||||
if (this.currentStep && this.currentStep.onNext) {
|
||||
await this.currentStep.onNext();
|
||||
}
|
||||
// do pre-actions
|
||||
const nextIndex = this.currentIndex + 1;
|
||||
if (nextIndex < this.numberOfSteps && this.currentIndex !== -1) {
|
||||
const nextStep = this.steps[nextIndex];
|
||||
if (nextStep.onBefore) {
|
||||
await nextStep.onBefore();
|
||||
// automatically continues to next step if enabled
|
||||
if (this.isPlaying) {
|
||||
setTimeout(() => {
|
||||
if (this.isPlaying) {
|
||||
this.next();
|
||||
}
|
||||
}, playDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
// go to next step
|
||||
this.currentIndex = nextIndex;
|
||||
},
|
||||
end() {
|
||||
this.currentIndex = -1;
|
||||
this.isPlaying = false;
|
||||
},
|
||||
handleKeyup(e) {
|
||||
switch (e.keyCode) {
|
||||
case 39:
|
||||
this.next();
|
||||
break;
|
||||
case 27:
|
||||
this.end();
|
||||
break;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<div
|
||||
class="tour-element"
|
||||
:class="{ 'tour-element-sticky': !targetElement, 'tour-has-title': !!step.title }"
|
||||
:id="'tour-element-' + hash"
|
||||
:ref="'tour-element-' + hash">
|
||||
<div v-if="step.title" class="tour-header">
|
||||
<div class="tour-title" v-html="step.title"></div>
|
||||
</div>
|
||||
<div v-if="step.content" class="tour-content" v-html="step.content" />
|
||||
<div class="tour-buttons">
|
||||
<div v-if="isLast">
|
||||
<button class="tour-button tour-end" @click.prevent="$emit('end')">Close</button>
|
||||
</div>
|
||||
<div v-else-if="isPlaying">
|
||||
<button class="tour-button tour-stop" @click.prevent="$emit('play', false)">Stop</button>
|
||||
</div>
|
||||
<div v-else>
|
||||
<button class="tour-button tour-end" @click.prevent="$emit('end')">Cancel</button>
|
||||
<button class="tour-button tour-play" @click.prevent="$emit('play', true)">Play</button>
|
||||
<button class="tour-button tour-next" @click.prevent="$emit('next')">Continue</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="targetElement" class="tour-arrow" data-popper-arrow />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { createPopper } from "@popperjs/core";
|
||||
import sum from "hash-sum";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
step: {
|
||||
type: Object,
|
||||
},
|
||||
isPlaying: {
|
||||
type: Boolean,
|
||||
},
|
||||
isLast: {
|
||||
type: Boolean,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hash: sum(this.step.target),
|
||||
targetElement: document.querySelector(this.step.target),
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
createStep() {
|
||||
if (this.targetElement) {
|
||||
this.targetElement.scrollIntoView({ behavior: "smooth" });
|
||||
createPopper(this.targetElement, this.$refs["tour-element-" + this.hash], {
|
||||
modifiers: [
|
||||
{
|
||||
name: "preventOverflow",
|
||||
options: {
|
||||
altAxis: true,
|
||||
tether: false,
|
||||
padding: 20,
|
||||
},
|
||||
},
|
||||
],
|
||||
strategy: "absolute",
|
||||
placement: "auto",
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.createStep();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -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 });
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 = `
|
||||
<h2>Galaxy Tours</h2>
|
||||
<p>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).</p>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 btn-group" role="group" aria-label="Tag selector">
|
||||
<% _.each(tourtagorder, function(tag) { %>
|
||||
<button class="btn btn-primary tag-selector-button" tag-selector-button="<%- tag.key %>">
|
||||
<%- tag.name %>
|
||||
</button>
|
||||
<% }); %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-12">
|
||||
<h4>Tours</h4>
|
||||
<ul class="list-group">
|
||||
<% _.each(tours, function(tour) { %>
|
||||
<li class="list-group-item" tags="<%- tour.attributes.tags_lc %>">
|
||||
<a href="/tours/<%- tour.id %>" class="tourItem" data-tour.id=<%- tour.id %>>
|
||||
<%- tour.attributes.name || tour.id %>
|
||||
</a>
|
||||
- <%- tour.attributes.description || "No description given." %>
|
||||
<% _.each(tour.attributes.tags, function(tag) { %>
|
||||
<span class="badge badge-primary">
|
||||
<%- tag.charAt(0).toUpperCase() + tag.slice(1) %>
|
||||
</span>
|
||||
<% }); %>
|
||||
</li>
|
||||
<% }); %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
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("<div/>");
|
||||
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,
|
||||
};
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import Tours from "mvc/tours";
|
||||
|
||||
export function initTours(Galaxy) {
|
||||
console.log("initTours");
|
||||
Tours.activeGalaxyTourRunner();
|
||||
Galaxy.giveTourWithData = Tours.giveTourWithData;
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
+7
-16
@@ -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==
|
||||
|
||||
@@ -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.<br>
|
||||
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.<br>
|
||||
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.<br>
|
||||
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 <b>analysis</b> from here."
|
||||
position: "bottom"
|
||||
intro: "This is the current view. Start your <b>Analysis</b> from here."
|
||||
|
||||
- title: 'Workflow'
|
||||
element: "#workflow"
|
||||
intro: "Create, manage, import, export and share your <b>Workflows</b>."
|
||||
position: "bottom"
|
||||
|
||||
- title: 'Shared data'
|
||||
element: "#shared"
|
||||
intro: "Get access to all <b>Workflows</b>, <b>Histories</b>, <b>Pages</b>, <b>Visualizations</b> and your <b>Data Library</b> 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!<br>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 <b>Community</b> 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!"
|
||||
|
||||
@@ -13,26 +13,22 @@ steps:
|
||||
intro: |
|
||||
At first we upload some data into your Galaxy history.<br>
|
||||
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 <b>History</b>."
|
||||
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']"
|
||||
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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 <test></test> 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): <b>%s</b>" % 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: <b>%s</b>" % 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 <b>%s</b>" % 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): <b>%s</b>" % 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: <b>{hid}: {dataset}</b>"
|
||||
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): <b>%s</b>" % 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 <b>Column: %s</b>" % 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 <b>Execute</b> 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}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -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) {
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user