diff --git a/client/galaxy/scripts/components/Masthead/Masthead.test.js b/client/galaxy/scripts/components/Masthead/Masthead.test.js
new file mode 100644
index 000000000000..e90fa9448c1a
--- /dev/null
+++ b/client/galaxy/scripts/components/Masthead/Masthead.test.js
@@ -0,0 +1,112 @@
+import Masthead from "./Masthead.vue";
+import { mount, createLocalVue } from "@vue/test-utils";
+import Scratchbook from "layout/scratchbook";
+
+describe("Masthead.vue", () => {
+ let wrapper;
+ let localVue;
+ let scratchbook;
+ let quotaRendered, quotaEl;
+
+ beforeEach(() => {
+ localVue = createLocalVue();
+ quotaRendered = false;
+ quotaEl = null;
+
+ const quotaMeter = {
+ setElement: function (el) {
+ quotaEl = el;
+ },
+ render: function () {
+ quotaRendered = true;
+ },
+ };
+
+ const tabs = [
+ // Main Analysis Tab..
+ {
+ id: "analysis",
+ title: "Analyze",
+ menu: false,
+ url: "root",
+ },
+ {
+ id: "shared",
+ title: "Shared Items",
+ menu: [{ title: "_menu_title", url: "_menu_url", target: "_menu_target" }],
+ },
+ // Hidden tab (pre-Vue framework supported this, not sure it is used
+ // anywhere?)
+ {
+ id: "hiddentab",
+ title: "Hidden Title",
+ menu: false,
+ hidden: true,
+ },
+ ];
+ const activeTab = "shared";
+
+ // scratchbook assumes this is a Backbone collection - mock that out.
+ tabs.add = (x) => {
+ tabs.push(x);
+ return x;
+ };
+ scratchbook = new Scratchbook({
+ collection: tabs,
+ });
+ const frames = scratchbook.getFrames();
+
+ wrapper = mount(Masthead, {
+ propsData: {
+ quotaMeter,
+ frames,
+ tabs,
+ activeTab,
+ appRoot: "prefix/",
+ },
+ localVue,
+ attachToDocument: true,
+ });
+ });
+
+ it("set quota element and renders it", () => {
+ expect(quotaEl).to.not.equals(null);
+ expect(quotaRendered).to.equals(true);
+ });
+
+ it("should render simple tab item links", () => {
+ expect(wrapper.findAll("li.nav-item").length).to.equals(5);
+ // Ensure specified link title respected.
+ expect(wrapper.find("#analysis a").text()).to.equals("Analyze");
+ expect(wrapper.find("#analysis a").attributes("href")).to.equals("prefix/root");
+ });
+
+ it("should render tab items with menus", () => {
+ // Ensure specified link title respected.
+ expect(wrapper.find("#shared a").text()).to.equals("Shared Items");
+ expect(wrapper.find("#shared").classes("dropdown")).to.equals(true);
+
+ expect(wrapper.findAll("#shared .dropdown-menu li").length).to.equals(1);
+ expect(wrapper.find("#shared .dropdown-menu li a").attributes().href).to.equals("prefix/_menu_url");
+ expect(wrapper.find("#shared .dropdown-menu li a").attributes().target).to.equals("_menu_target");
+ expect(wrapper.find("#shared .dropdown-menu li a").text()).to.equals("_menu_title");
+ });
+
+ it("should make hidden tabs hidden", () => {
+ expect(wrapper.find("#analysis").attributes().style).to.not.contain("display: none");
+ expect(wrapper.find("#hiddentab").attributes().style).to.contain("display: none");
+ });
+
+ it("should highlight the active tab", () => {
+ expect(wrapper.find("#analysis").classes("active")).to.equals(false);
+ expect(wrapper.find("#shared").classes("active")).to.equals(true);
+ });
+
+ it("should display scratchbook button", async () => {
+ expect(wrapper.find("#enable-scratchbook a span").classes("fa-th")).to.equals(true);
+ expect(scratchbook.active).to.equals(false);
+ // wrapper.find("#enable-scratchbook a").trigger("click");
+ // await localVue.nextTick();
+ // expect(scratchbook.active).to.equals(true);
+ });
+});
diff --git a/client/galaxy/scripts/components/Masthead/Masthead.vue b/client/galaxy/scripts/components/Masthead/Masthead.vue
new file mode 100644
index 000000000000..f3e27aaad4e8
--- /dev/null
+++ b/client/galaxy/scripts/components/Masthead/Masthead.vue
@@ -0,0 +1,116 @@
+
+
+
+
+ {{ brandTitle }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/client/galaxy/scripts/components/Masthead/MastheadItem.test.js b/client/galaxy/scripts/components/Masthead/MastheadItem.test.js
new file mode 100644
index 000000000000..9bd4145fa9a3
--- /dev/null
+++ b/client/galaxy/scripts/components/Masthead/MastheadItem.test.js
@@ -0,0 +1,42 @@
+import MastheadItem from "./MastheadItem.vue";
+import { mount, createLocalVue } from "@vue/test-utils";
+
+describe("Masthead.vue", () => {
+ let wrapper;
+ let localVue;
+ let active, menu;
+
+ beforeEach(() => {
+ localVue = createLocalVue();
+ });
+
+ function m() {
+ const tab = {
+ id: "mytab",
+ menu: menu,
+ };
+ return mount(MastheadItem, {
+ propsData: {
+ tab,
+ activeTab: active,
+ },
+ localVue,
+ });
+ }
+
+ it("should render active tab with menus", async () => {
+ active = "mytab";
+ menu = true;
+ wrapper = m();
+ expect(wrapper.vm.active).to.equals(true);
+ expect(wrapper.vm.menu).to.equals(true);
+ });
+
+ it("should render inactive tabs without menus", async () => {
+ active = "othertab";
+ menu = false;
+ wrapper = m();
+ expect(wrapper.vm.active).to.equals(false);
+ expect(wrapper.vm.menu).to.equals(false);
+ });
+});
diff --git a/client/galaxy/scripts/components/Masthead/MastheadItem.vue b/client/galaxy/scripts/components/Masthead/MastheadItem.vue
new file mode 100644
index 000000000000..81fb2da36fb9
--- /dev/null
+++ b/client/galaxy/scripts/components/Masthead/MastheadItem.vue
@@ -0,0 +1,182 @@
+
+
+
+
+ {{ tab.note }}
+
+
+ {{ tab.title }}
+
+
+
+
+
+ {{ item.title }}
+
+
+
+
+
+
+
+
+
diff --git a/client/galaxy/scripts/components/Masthead/initMasthead.js b/client/galaxy/scripts/components/Masthead/initMasthead.js
index 5eba73b2ecdf..796fa052e15c 100644
--- a/client/galaxy/scripts/components/Masthead/initMasthead.js
+++ b/client/galaxy/scripts/components/Masthead/initMasthead.js
@@ -2,15 +2,31 @@
* Temporary function used to mount the masthead inside the current application.
* This function is exposed with the rest of the page-globals in bundledEntries.
*/
-import Vue from "vue";
-import Masthead from "components/Masthead";
+// import Vue from "vue";
+// import Masthead from "./Masthead";
+import Masthead from "../../layout/masthead";
+import $ from "jquery";
export function initMasthead(config, container) {
console.log("initMasthead");
- const Component = Vue.extend(Masthead);
- return new Component({
- props: Object.keys(config),
- propsData: config,
- el: container,
- });
+
+ const masthead = new Masthead.View(config);
+ masthead.render();
+
+ const $masthead = $("#masthead");
+
+ if (config.hide_masthead) {
+ $masthead.remove();
+ } else {
+ if (container) {
+ $(container).replaceWith(masthead.el);
+ }
+ }
+
+ // const Component = Vue.extend(Masthead);
+ // return new Component({
+ // props: Object.keys(config),
+ // propsData: config,
+ // el: container
+ // });
}
diff --git a/client/galaxy/scripts/layout/masthead.js b/client/galaxy/scripts/layout/masthead.js
index d5eb3816c09e..f88d0dbd1fe4 100644
--- a/client/galaxy/scripts/layout/masthead.js
+++ b/client/galaxy/scripts/layout/masthead.js
@@ -4,30 +4,20 @@ import Menu from "layout/menu";
import Scratchbook from "layout/scratchbook";
import QuotaMeter from "mvc/user/user-quotameter";
import { getGalaxyInstance } from "app";
+import Masthead from "../components/Masthead/Masthead";
+import { mountVueComponent } from "../utils/mountVueComponent";
+import { getAppRoot } from "onload/loadConfig";
/** Masthead **/
const View = Backbone.View.extend({
initialize: function (options) {
const Galaxy = getGalaxyInstance();
-
const self = this;
this.options = options;
- this.setElement(this._template());
- this.$navbarBrandLink = this.$(".navbar-brand");
- this.$navbarBrandImage = this.$(".navbar-brand-image");
- this.$navbarBrandTitle = this.$(".navbar-brand-title");
- this.$navbarTabs = this.$(".navbar-nav");
- this.$quoteMeter = this.$(".quota-meter-container");
// build tabs
this.collection = new Menu.Collection();
this.collection
- .on("add", (model) => {
- self.$navbarTabs.append(new Menu.Tab({ model: model }).render().$el);
- })
- .on("reset", () => {
- self.$navbarTabs.empty();
- })
.on("dispatch", (callback) => {
self.collection.each((m) => {
callback(m);
@@ -36,7 +26,7 @@ const View = Backbone.View.extend({
.fetch(this.options);
// highlight initial active view
- this.highlight(options.active_view);
+ this.highlight(options.active_view); // covered
// scratchbook
Galaxy.frame = this.frame = new Scratchbook({
@@ -47,7 +37,6 @@ const View = Backbone.View.extend({
// add quota meter to masthead
Galaxy.quotaMeter = this.quotaMeter = new QuotaMeter.UserQuotaMeter({
model: Galaxy.user,
- el: this.$quoteMeter,
});
// loop through beforeunload functions if the user attempts to unload the page
@@ -77,35 +66,38 @@ const View = Backbone.View.extend({
},
render: function () {
- let brand = this.options.display_galaxy_brand ? "Galaxy " : "";
+ const el = document.createElement("div");
+ this.el.appendChild(el); // use this.el directly when feature parity is accomplished
+ let brandTitle = this.options.display_galaxy_brand ? "Galaxy " : "";
if (this.options.brand) {
- brand += this.options.brand;
+ brandTitle += this.options.brand;
}
- this.$navbarBrandTitle.html(brand);
- this.$navbarBrandLink.attr("href", this.options.logo_url);
- this.$navbarBrandImage.attr("src", this.options.logo_src);
- this.quotaMeter.render();
+ const tabs = this.collection.models.map((el) => {
+ return el.toJSON();
+ });
+ mountVueComponent(Masthead)(
+ {
+ brandTitle: brandTitle,
+ brandLink: this.options.logo_url,
+ brandImage: this.options.logo_src,
+ quotaMeter: this.quotaMeter,
+ activeTab: this.activeView,
+ tabs: tabs,
+ frames: this.frame.getFrames(),
+ appRoot: getAppRoot(),
+ Galaxy: getGalaxyInstance(),
+ },
+ el
+ );
return this;
},
highlight: function (id) {
+ this.activeView = id;
this.collection.forEach(function (model) {
model.set("active", model.id == id);
});
},
-
- /** body template */
- _template: function () {
- return `
- `;
- },
});
export default {
diff --git a/client/galaxy/scripts/layout/menu.js b/client/galaxy/scripts/layout/menu.js
index e258419dbdee..f649715bf1be 100644
--- a/client/galaxy/scripts/layout/menu.js
+++ b/client/galaxy/scripts/layout/menu.js
@@ -1,9 +1,7 @@
/** Masthead Collection **/
-import _ from "underscore";
import $ from "jquery";
import axios from "axios";
import Backbone from "backbone";
-import { getAppRoot } from "onload/loadConfig";
import { getGalaxyInstance } from "app";
import _l from "utils/localization";
import { CommunicationServerView } from "layout/communication-server-view";
@@ -345,197 +343,6 @@ const Collection = Backbone.Collection.extend({
},
});
-/** Masthead tab **/
-const Tab = Backbone.View.extend({
- initialize: function (options) {
- this.model = options.model;
- this.setElement(this._template());
- this.$link = this.$(".nav-link");
- this.$note = this.$(".nav-note");
- this.$menu = this.$(".dropdown-menu");
- this.listenTo(this.model, "change", this.render, this);
- },
-
- events: {
- "click .nav-link": "_toggleClick",
- },
-
- render: function () {
- $(".tooltip").remove();
- this.$el
- .removeClass()
- .addClass(this.model.get("disabled") && "disabled")
- .addClass(this.model.get("active") && "active")
- .addClass(this.model.get("menu") && "dropdown")
- .attr("id", this.model.id)
- .css({
- visibility: (this.model.get("visible") && "visible") || "hidden",
- });
- this.model.set("url", this._formatUrl(this.model.get("url")));
- this.$note
- .html(this.model.get("note") || "")
- .removeClass()
- .addClass("nav-note")
- .addClass(this.model.get("note_cls"))
- .css({
- display: (this.model.get("show_note") && "block") || "none",
- });
- this.$link
- .html(this.model.get("title") || "")
- .removeClass()
- .addClass("nav-link")
- .addClass(this.model.get("cls"))
- .addClass(this.model.get("icon") && `nav-icon fa ${this.model.get("icon")}`)
- .addClass(this.model.get("menu") && "dropdown-toggle")
- .addClass(this.model.get("toggle") && "toggle")
- .attr("id", this.model.get("menu") && `dropdown-button-${this.model.get("id")}`)
- .attr("aria-haspopup", this.model.get("menu") && "true")
- .attr("target", this.model.get("target"))
- .attr("href", this.model.get("url"))
- .attr("title", this.model.get("tooltip"))
- .tooltip("dispose");
- if (this.model.get("tooltip")) {
- this.$link.tooltip({ placement: "bottom" });
- }
- if (this.model.get("menu") && this.model.get("show_menu")) {
- this.$menu.show();
- $("#dd-helper")
- .show()
- .off()
- .on("click", () => {
- $("#dd-helper").hide();
- this.model.set("show_menu", false);
- });
- } else {
- this.$menu.hide();
- $("#dd-helper").hide();
- }
- this.$menu.empty().removeClass();
- if (this.model.get("menu")) {
- _.each(this.model.get("menu"), (menuItem) => {
- this.$menu.append(this._buildMenuItem(menuItem));
- if (menuItem.divider) {
- this.$menu.append($("
").addClass("dropdown-divider"));
- }
- });
- this.$menu.addClass("dropdown-menu");
- this.$menu.attr("aria-labelledby", this.$menu.siblings(".dropdown-toggle").attr("id"));
- this.$menu.attr("role", "menu");
- this.$link.append($("").addClass("caret"));
- }
- return this;
- },
-
- /** Add new menu item */
- _buildMenuItem: function (options) {
- options = _.defaults(options || {}, {
- title: "",
- url: "",
- target: "_parent",
- noscratchbook: false,
- });
- options.url = this._formatUrl(options.url);
- return $("")
- .addClass("dropdown-item")
- .attr("href", options.url)
- .attr("target", options.target)
- .attr("class", options.class)
- .attr("role", "menuitem")
- .html(options.title)
- .on("click", (e) => {
- e.preventDefault();
- this.model.set("show_menu", false);
- if (options.onclick) {
- options.onclick();
- } else {
- const Galaxy = getGalaxyInstance();
- if (options.target == "__use_router__" && typeof Galaxy.page != "undefined") {
- Galaxy.page.router.executeUseRouter(options.url);
- } else {
- try {
- Galaxy.frame.add(options);
- } catch (err) {
- console.warn("Missing frame element on galaxy instance", err);
- }
- }
- }
- });
- },
-
- buildLink: function (label, url) {
- return $("")
- .append(
- $("")
- .attr("href", getAppRoot() + url)
- .html(label)
- )
- .html();
- },
-
- /** Handle click event */
- _toggleClick: function (e) {
- const model = this.model;
- e.preventDefault();
- $(".tooltip").hide();
- model.trigger("dispatch", (m) => {
- if (model.id !== m.id && m.get("menu")) {
- m.set("show_menu", false);
- }
- });
- if (!model.get("disabled")) {
- if (!model.get("menu")) {
- if (model.get("onclick")) {
- model.get("onclick")();
- } else {
- const Galaxy = getGalaxyInstance();
- if (model.attributes.target == "__use_router__" && typeof Galaxy.page != "undefined") {
- Galaxy.page.router.executeUseRouter(model.attributes.url);
- } else {
- Galaxy.frame.add(model.attributes);
- }
- }
- } else {
- model.set("show_menu", true);
- }
- } else {
- if (this.$link.popover) {
- this.$link.popover("dispose");
- }
- this.$link
- .popover({
- html: true,
- placement: "bottom",
- content: `Please ${this.buildLink("login or register", "login")} to use this feature.`,
- })
- .popover("show");
- window.setTimeout(() => {
- this.$link.popover("dispose");
- }, 3000);
- }
- },
-
- /** Url formatting */
- _formatUrl: function (url) {
- return typeof url == "string" &&
- url.indexOf("mailto:") === -1 &&
- url.indexOf("//") === -1 &&
- url.charAt(0) != "/"
- ? getAppRoot() + url
- : url;
- },
-
- /** body tempate */
- _template: function () {
- return `
-
-
-
-
- `;
- },
-});
-
export default {
Collection: Collection,
- Tab: Tab,
};
diff --git a/client/galaxy/scripts/layout/scratchbook.js b/client/galaxy/scripts/layout/scratchbook.js
index ba1d06cc0b6b..1d2a9288d907 100644
--- a/client/galaxy/scripts/layout/scratchbook.js
+++ b/client/galaxy/scripts/layout/scratchbook.js
@@ -70,6 +70,11 @@ export default Backbone.View.extend({
this.history_cache = {};
},
+ getFrames() {
+ // needed for Vue.js integration
+ return this.frames;
+ },
+
/** Add a dataset to the frames */
addDataset: function (dataset_id) {
const self = this;
diff --git a/client/galaxy/scripts/qunit/test.js b/client/galaxy/scripts/qunit/test.js
index 41abaa55e995..2702237bedef 100644
--- a/client/galaxy/scripts/qunit/test.js
+++ b/client/galaxy/scripts/qunit/test.js
@@ -11,7 +11,6 @@ import "./tests/form_tests";
import "./tests/list_of_pairs_collection_creator_tests";
import "./tests/workflow_editor_tests";
-import "./tests/masthead_tests";
import "./tests/graph_tests";
import "./tests/job_dag_tests";
import "./tests/history_contents_model_tests";
diff --git a/client/galaxy/scripts/qunit/tests/masthead_tests.js b/client/galaxy/scripts/qunit/tests/masthead_tests.js
deleted file mode 100644
index 88021ed15adb..000000000000
--- a/client/galaxy/scripts/qunit/tests/masthead_tests.js
+++ /dev/null
@@ -1,124 +0,0 @@
-/* global QUnit */
-import $ from "jquery";
-import testApp from "qunit/test-app";
-import Masthead from "layout/masthead";
-import { getAppRoot } from "onload";
-import { getGalaxyInstance } from "app";
-
-QUnit.module("Masthead test", {
- beforeEach: function () {
- testApp.create();
- this.masthead = new Masthead.View({
- brand: "brand",
- use_remote_user: "use_remote_user",
- remote_user_logout_href: "remote_user_logout_href",
- lims_doc_url: "lims_doc_url",
- support_url: "support_url",
- search_url: "search_url",
- mailing_lists: "mailing_lists",
- screencasts_url: "screencasts_url",
- wiki_url: "wiki_url",
- citation_url: "citation_url",
- terms_url: "terms_url",
- logo_url: "logo_url",
- logo_src: "../../../static/favicon.png",
- is_admin_user: "is_admin_user",
- active_view: "analysis",
- ftp_upload_site: "ftp_upload_site",
- datatypes_disable_auto: true,
- allow_user_creation: true,
- enable_cloud_launch: true,
- user_requests: true,
- });
- this.container = this.masthead.render().$el;
- $("body").append(this.container);
- },
- afterEach: function () {
- testApp.destroy();
- this.container.remove();
- },
-});
-
-QUnit.test("tabs", function (assert) {
- var tab = this.masthead.collection.findWhere({ id: "analysis" });
- var $tab = $("#analysis");
- var $toggle = $tab.find(".nav-link");
- var $note = $tab.find(".nav-note");
- var $menu = $tab.find(".dropdown-menu");
- assert.ok(tab && $tab.length == 1, "Found analysis tab");
- tab.set("title", "Analyze");
- assert.ok($toggle.html() == "Analyze", "Correct title");
- assert.ok($toggle.css("visibility") == "visible", "Tab visible");
- tab.set("visible", false);
- assert.ok($toggle.css("visibility") == "hidden", "Tab hidden");
- tab.set("visible", true);
- assert.ok($toggle.css("visibility") == "visible", "Tab visible, again");
- assert.ok($toggle.attr("href") == getAppRoot(), "Correct initial url");
- tab.set("url", "_url");
- assert.ok($toggle.attr("href") == "/_url", "Correct test url");
- tab.set("url", "http://_url");
- assert.ok($toggle.attr("href") == "http://_url", "Correct http url");
- tab.set("tooltip", "_tooltip");
- $toggle.trigger("mouseover");
- assert.ok($(".tooltip-inner").html() == "_tooltip", "Correct tooltip");
- tab.set("tooltip", null);
- $toggle.trigger("mouseover");
- assert.ok($(".tooltip-inner").length === 0, "Tooltip removed");
- tab.set("tooltip", "_tooltip_new");
- $toggle.trigger("mouseover");
- assert.ok($(".tooltip-inner").html() == "_tooltip_new", "Correct new tooltip");
- tab.set("cls", "_cls");
- assert.ok($toggle.hasClass("_cls"), "Correct extra class");
- tab.set("cls", "_cls_new");
- assert.ok($toggle.hasClass("_cls_new") && !$toggle.hasClass("_cls"), "Correct new extra class");
- assert.ok($note.html() === "", "Correct empty note");
- tab.set({ note: "_note", show_note: true });
- assert.ok($note.html() == "_note", "Correct new note");
- tab.set("toggle", true);
- assert.ok($toggle.hasClass("toggle"), "Toggled");
- tab.set("toggle", false);
- assert.ok(!$tab.hasClass("toggle"), "Untoggled");
- tab.set("disabled", true);
- assert.ok($tab.hasClass("disabled"), "Correctly disabled");
- tab.set("disabled", false);
- assert.ok(!$tab.hasClass("disabled"), "Correctly enabled");
- assert.ok($tab.hasClass("active"), "Highlighted");
- tab.set("active", false);
- assert.ok(!$tab.hasClass("active"), "Not highlighted");
- tab.set("active", true);
- assert.ok($tab.hasClass("active"), "Highlighted, again");
- assert.ok($menu.length === 0, "Dropdown menu correctly empty");
- tab.set("menu", [{ title: "_menu_title", url: "_menu_url", target: "_menu_target" }]);
- $menu = $tab.find(".dropdown-menu");
- assert.ok($menu.hasClass("dropdown-menu"), "Menu has correct class");
- assert.ok($menu.css("display") == "none", "Menu hidden");
- $toggle.trigger("click");
- assert.ok($menu.css("display") == "block", "Menu shown");
- var $item = $menu.find("a");
- assert.ok($item.length == 1, "Added one menu item");
- assert.ok($item.html() == "_menu_title", "Menu item has correct title");
- assert.ok($item.attr("href") == "/_menu_url", "Menu item has correct url");
- assert.ok($item.attr("target") == "_menu_target", "Menu item has correct target");
- tab.set("menu", null);
- $item = $menu.find("a");
- assert.ok($item.length === 0, "All menu items removed");
- tab.set("menu", [
- { title: "_menu_title_0", url: "_menu_url_0", target: "_menu_target_0" },
- { title: "_menu_title_1", url: "_menu_url_1", target: "_menu_target_1" },
- ]);
- $item = $menu.find("a");
- assert.ok($item.length == 2, "Two menu items added");
- tab.set("show_menu", false);
- assert.ok($menu.css("display", "none"), "Menu manually hidden");
- tab.set("show_menu", true);
- assert.ok($menu.css("display", "block"), "Menu manually shown, again");
- tab = this.masthead.collection.findWhere({ id: "enable-scratchbook" });
- $tab = $("#enable-scratchbook");
- $toggle = $tab.find(".nav-link");
- assert.ok(tab && $toggle.length == 1, "Found tab to enable scratchbook");
- assert.ok(!$toggle.hasClass("toggle"), "Untoggled before click");
- $toggle.trigger("click");
- assert.ok($toggle.hasClass("toggle"), "Toggled after click");
- let galaxy = getGalaxyInstance();
- assert.ok(galaxy.frame.active, "Scratchbook is active");
-});
diff --git a/client/galaxy/style/scss/base.scss b/client/galaxy/style/scss/base.scss
index 93d1db5807fa..9a7084a5abee 100644
--- a/client/galaxy/style/scss/base.scss
+++ b/client/galaxy/style/scss/base.scss
@@ -359,7 +359,7 @@ body {
background-color: $brand-masthead;
height: $masthead-height;
.navbar-nav {
- min-height: 100%;
+ height: $masthead-height;
> li {
// This allows the background color to fill the full height of the
// masthead, while still keeping the contents centered (using flex)
diff --git a/lib/galaxy/selenium/navigates_galaxy.py b/lib/galaxy/selenium/navigates_galaxy.py
index d84922aa153c..5290c65b14c5 100644
--- a/lib/galaxy/selenium/navigates_galaxy.py
+++ b/lib/galaxy/selenium/navigates_galaxy.py
@@ -362,7 +362,7 @@ def click_grid_popup_option(self, item_name, option_label):
def published_grid_search_for(self, search_term=None):
return self._inline_search_for(
- '#input-free-text-search-filter',
+ self.navigation.grids.free_text_search,
search_term,
)
@@ -374,7 +374,9 @@ def is_logged_in(self):
@retry_during_transitions
def _inline_search_for(self, selector, search_term=None):
- search_box = self.wait_for_and_click_selector(selector)
+ # Clear tooltip resulting from clicking on the masthead to get here.
+ self.clear_tooltips()
+ search_box = self.wait_for_and_click(selector)
search_box.clear()
if search_term is not None:
search_box.send_keys(search_term)
@@ -406,7 +408,7 @@ def submit_login(self, email, password=None, assert_valid=True, retries=0):
'login': email,
'password': password,
}
- self.click_masthead_user()
+ self.components.masthead.register_or_login.wait_for_and_click()
self.sleep_for(WAIT_TYPES.UX_RENDER)
form = self.wait_for_visible(self.navigation.login.selectors.form)
self.fill(form, login_info)
@@ -435,7 +437,7 @@ def register(self, email=None, password=None, username=None, confirm=None, asser
username = email.split("@")[0]
self.home()
- self.click_masthead_user()
+ self.components.masthead.register_or_login.wait_for_and_click()
self.wait_for_and_click(self.navigation.registration.selectors.toggle)
form = self.wait_for_visible(self.navigation.registration.selectors.form)
self.fill(form, dict(
@@ -470,8 +472,8 @@ def register(self, email=None, password=None, username=None, confirm=None, asser
assert email in text
assert self.get_logged_in_user()["email"] == email
- # Hide masthead menu click
- self.click_center()
+ # clicking away no longer closes menu post Masthead -> VueJS
+ self.click_masthead_user()
def wait_for_logged_in(self):
try:
@@ -954,6 +956,12 @@ def wait_for_overlays_cleared(self):
self.wait_for_selector_absent_or_hidden(".ui-modal", wait_type=WAIT_TYPES.UX_POPUP)
self.wait_for_selector_absent_or_hidden(".toast", wait_type=WAIT_TYPES.UX_POPUP)
+ def clear_tooltips(self):
+ action_chains = self.action_chains()
+ center_element = self.driver.find_element_by_css_selector("#center")
+ action_chains.move_to_element(center_element).perform()
+ self.wait_for_selector_absent_or_hidden(".b-tooltip", wait_type=WAIT_TYPES.UX_POPUP)
+
def workflow_index_open(self):
self.home()
self.click_masthead_workflow()
@@ -977,7 +985,7 @@ def workflow_index_click_search(self):
def workflow_index_search_for(self, search_term=None):
return self._inline_search_for(
- "#workflow-search",
+ self.navigation.workflows.search_box,
search_term,
)
diff --git a/lib/galaxy/selenium/navigation.yml b/lib/galaxy/selenium/navigation.yml
index 99c230c83474..87d1cbbda52c 100644
--- a/lib/galaxy/selenium/navigation.yml
+++ b/lib/galaxy/selenium/navigation.yml
@@ -31,21 +31,19 @@ masthead:
selectors:
_: '#masthead'
- user:
- type: xpath
- selector: '//li[@id="user"]'
+ # bootstrap-vue a tag doesn't work as link target, need to hit span inside
+ user: '#user.loggedin-only > a.nav-link.dropdown-toggle > span'
+ register_or_login: '#user.loggedout-only > .nav-link'
- user_menu: 'li#user .dropdown-menu'
- workflow:
- type: xpath
- selector: '//li[@id="workflow"]'
+ user_menu: '#user .dropdown-menu a'
+ workflow: '#workflow .nav-link'
user_email:
type: xpath
selector: '//a[contains(text(), "Logged in as")]'
- logged_in_only: 'a.loggedin-only'
- logged_out_only: 'a.loggedout-only'
+ logged_in_only: '.loggedin-only'
+ logged_out_only: '.loggedout-only'
labels:
# top-level menus
@@ -303,6 +301,7 @@ workflows:
new_button: '#workflow-create'
import_button: '#workflow-import'
save_button: '#workflow-save-button'
+ search_box: "#workflow-search"
workflow_run: