From 0b931f1ad20fea525e199a929e62cc15c8a6ee04 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Sat, 23 May 2020 16:07:12 -0400 Subject: [PATCH 01/11] self -> this in page.js --- client/galaxy/scripts/layout/page.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/client/galaxy/scripts/layout/page.js b/client/galaxy/scripts/layout/page.js index 3078d83c08d5..5e3c2f362b6e 100644 --- a/client/galaxy/scripts/layout/page.js +++ b/client/galaxy/scripts/layout/page.js @@ -14,7 +14,6 @@ const View = Backbone.View.extend({ _panelids: ["left", "right"], initialize: function (options) { - const self = this; this.config = _.defaults(options.config || {}, { message_box_visible: false, message_box_content: "", @@ -28,7 +27,7 @@ const View = Backbone.View.extend({ // attach global objects, build mastheads const Galaxy = getGalaxyInstance(); Galaxy.modal = this.modal = new Modal.View(); - Galaxy.router = this.router = options.Router && new options.Router(self, options); + Galaxy.router = this.router = options.Router && new options.Router(this, options); this.masthead = new Masthead.View(this.config); this.center = new Panel.CenterPanel(); @@ -42,9 +41,9 @@ const View = Backbone.View.extend({ view.allow_title_display = true; } if (view.active_tab) { - self.masthead.highlight(view.active_tab); + this.masthead.highlight(view.active_tab); } - self.center.display(view); + this.center.display(view); }; // build page template @@ -73,10 +72,10 @@ const View = Backbone.View.extend({ const panel_class_name = panel_id.charAt(0).toUpperCase() + panel_id.slice(1); const panel_class = options[panel_class_name]; if (panel_class) { - const panel_instance = new panel_class(self, options); - const panel_el = self.$(`#${panel_id}`); - self[panel_instance.toString()] = panel_instance; - self.panels[panel_id] = new Panel.SidePanel({ + const panel_instance = new panel_class(this, options); + const panel_el = this.$(`#${panel_id}`); + this[panel_instance.toString()] = panel_instance; + this.panels[panel_id] = new Panel.SidePanel({ id: panel_id, el: panel_el, view: panel_instance, @@ -143,14 +142,13 @@ const View = Backbone.View.extend({ /** Render panels */ renderPanels: function () { - const self = this; _.each(this._panelids, (panel_id) => { - const panel = self.panels[panel_id]; + const panel = this.panels[panel_id]; if (panel) { panel.render(); } else { - self.$center.css(panel_id, 0); - self.$(`#${panel_id}`).hide(); + this.$center.css(panel_id, 0); + this.$(`#${panel_id}`).hide(); } }); return this; From a7042e5c0157dffc5ed83ca5cec8652f8e37ed35 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Sat, 23 May 2020 17:06:38 -0400 Subject: [PATCH 02/11] Eliminate some scratchbook ported to Masthead.vue. --- client/galaxy/scripts/layout/scratchbook.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/client/galaxy/scripts/layout/scratchbook.js b/client/galaxy/scripts/layout/scratchbook.js index 1d2a9288d907..4f65855a07f5 100644 --- a/client/galaxy/scripts/layout/scratchbook.js +++ b/client/galaxy/scripts/layout/scratchbook.js @@ -51,22 +51,6 @@ export default Backbone.View.extend({ } }, }); - this.frames - .on("add remove", () => { - if (this.frames.visible && this.frames.length() === 0) { - this.frames.hide(); - } - this.buttonLoad.set({ - note: this.frames.length(), - visible: this.frames.length() > 0, - }); - }) - .on("show hide ", () => { - this.buttonLoad.set({ - toggle: this.frames.visible, - icon: (this.frames.visible && "fa-eye") || "fa-eye-slash", - }); - }); this.history_cache = {}; }, From 11848894cf87b10f89f8998a1e60afde51db5f11 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Sat, 23 May 2020 17:56:05 -0400 Subject: [PATCH 03/11] Fix placing webhooks in masthead. --- .../scripts/components/Masthead/Masthead.vue | 3 +++ client/galaxy/scripts/layout/masthead.js | 8 ++++-- client/galaxy/scripts/layout/menu.js | 25 ++++++++++++------- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/client/galaxy/scripts/components/Masthead/Masthead.vue b/client/galaxy/scripts/components/Masthead/Masthead.vue index f3e27aaad4e8..5b1e4447a4c2 100644 --- a/client/galaxy/scripts/components/Masthead/Masthead.vue +++ b/client/galaxy/scripts/components/Masthead/Masthead.vue @@ -87,6 +87,9 @@ export default { } }); }, + addItem(item) { + this.tabs.push(item); + }, }, mounted() { this.quotaMeter.setElement(this.$refs["quota-meter-container"]); diff --git a/client/galaxy/scripts/layout/masthead.js b/client/galaxy/scripts/layout/masthead.js index f88d0dbd1fe4..9a57dd27be60 100644 --- a/client/galaxy/scripts/layout/masthead.js +++ b/client/galaxy/scripts/layout/masthead.js @@ -14,7 +14,7 @@ const View = Backbone.View.extend({ const Galaxy = getGalaxyInstance(); const self = this; this.options = options; - + this._component = null; // build tabs this.collection = new Menu.Collection(); this.collection @@ -75,7 +75,7 @@ const View = Backbone.View.extend({ const tabs = this.collection.models.map((el) => { return el.toJSON(); }); - mountVueComponent(Masthead)( + this._component = mountVueComponent(Masthead)( { brandTitle: brandTitle, brandLink: this.options.logo_url, @@ -92,6 +92,10 @@ const View = Backbone.View.extend({ return this; }, + addItem(item) { + this._component.addItem(item); + }, + highlight: function (id) { this.activeView = id; this.collection.forEach(function (model) { diff --git a/client/galaxy/scripts/layout/menu.js b/client/galaxy/scripts/layout/menu.js index f649715bf1be..c8cca192a10a 100644 --- a/client/galaxy/scripts/layout/menu.js +++ b/client/galaxy/scripts/layout/menu.js @@ -8,6 +8,16 @@ import { CommunicationServerView } from "layout/communication-server-view"; import Webhooks from "mvc/webhooks"; import Utils from "utils/utils"; +function appendToPageMenu(item) { + const Galaxy = getGalaxyInstance(); + // Galaxy.page is undefined for data libraries, workflows pages + if (Galaxy.page) { + Galaxy.page.masthead.addItem(item); + } else if (Galaxy.masthead) { + Galaxy.masthead.addItem(item); + } +} + export function logoutClick() { const galaxy = getGalaxyInstance(); const session_csrf_token = galaxy.session_csrf_token; @@ -153,16 +163,13 @@ const Collection = Backbone.Collection.extend({ tooltip: webhook.config.tooltip, /*jslint evil: true */ onclick: webhook.config.function && new Function(webhook.config.function), + // fill in model defaults because this isn't added to + // collection first, will make more sense when other + // items aren't defined using backbone + visible: true, + target: "_parent", }; - - // Galaxy.page is undefined for data libraries, workflows pages - const Galaxy = getGalaxyInstance(); - if (Galaxy.page) { - Galaxy.page.masthead.collection.add(obj); - } else if (Galaxy.masthead) { - Galaxy.masthead.collection.add(obj); - } - + appendToPageMenu(obj); // Append masthead script and styles to Galaxy main Utils.appendScriptStyle(webhook); } From 330a02edcab924ad6eff5a2a9a0a6b21d1decff2 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Sat, 23 May 2020 20:43:19 -0400 Subject: [PATCH 04/11] Fix masthead highlight functionality... maybe? --- client/galaxy/scripts/components/Masthead/Masthead.vue | 3 +++ client/galaxy/scripts/layout/masthead.js | 10 ++-------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/client/galaxy/scripts/components/Masthead/Masthead.vue b/client/galaxy/scripts/components/Masthead/Masthead.vue index 5b1e4447a4c2..28b257d28436 100644 --- a/client/galaxy/scripts/components/Masthead/Masthead.vue +++ b/client/galaxy/scripts/components/Masthead/Masthead.vue @@ -90,6 +90,9 @@ export default { addItem(item) { this.tabs.push(item); }, + highlight(activeTab) { + this.activeTab = activeTab; + }, }, mounted() { this.quotaMeter.setElement(this.$refs["quota-meter-container"]); diff --git a/client/galaxy/scripts/layout/masthead.js b/client/galaxy/scripts/layout/masthead.js index 9a57dd27be60..235d9ce02f44 100644 --- a/client/galaxy/scripts/layout/masthead.js +++ b/client/galaxy/scripts/layout/masthead.js @@ -25,9 +25,6 @@ const View = Backbone.View.extend({ }) .fetch(this.options); - // highlight initial active view - this.highlight(options.active_view); // covered - // scratchbook Galaxy.frame = this.frame = new Scratchbook({ collection: this.collection, @@ -96,11 +93,8 @@ const View = Backbone.View.extend({ this._component.addItem(item); }, - highlight: function (id) { - this.activeView = id; - this.collection.forEach(function (model) { - model.set("active", model.id == id); - }); + highlight(activeTab) { + this._component.highlight(activeTab); }, }); From 300b6383002d2c834f9ac09b74a0648bed105b67 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Sat, 23 May 2020 20:49:48 -0400 Subject: [PATCH 05/11] Another self -> this. --- client/galaxy/scripts/layout/masthead.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/galaxy/scripts/layout/masthead.js b/client/galaxy/scripts/layout/masthead.js index 235d9ce02f44..48adbeeb2389 100644 --- a/client/galaxy/scripts/layout/masthead.js +++ b/client/galaxy/scripts/layout/masthead.js @@ -12,7 +12,6 @@ import { getAppRoot } from "onload/loadConfig"; const View = Backbone.View.extend({ initialize: function (options) { const Galaxy = getGalaxyInstance(); - const self = this; this.options = options; this._component = null; // build tabs @@ -50,7 +49,7 @@ const View = Backbone.View.extend({ }) .on("beforeunload", () => { let text = ""; - self.collection.each((model) => { + this.collection.each((model) => { const q = model.get("onbeforeunload") && model.get("onbeforeunload")(); if (q) { text += `${q} `; From b8439fa026615f4c53c3d988fa5680e31c61586f Mon Sep 17 00:00:00 2001 From: John Chilton Date: Sat, 23 May 2020 17:03:12 -0400 Subject: [PATCH 06/11] Refactor menu.js from Backbone collection into POJO. --- client/galaxy/scripts/layout/masthead.js | 25 +- client/galaxy/scripts/layout/menu.js | 525 ++++++++++---------- client/galaxy/scripts/layout/scratchbook.js | 6 +- 3 files changed, 273 insertions(+), 283 deletions(-) diff --git a/client/galaxy/scripts/layout/masthead.js b/client/galaxy/scripts/layout/masthead.js index 48adbeeb2389..91e8340ef8c1 100644 --- a/client/galaxy/scripts/layout/masthead.js +++ b/client/galaxy/scripts/layout/masthead.js @@ -1,6 +1,6 @@ import $ from "jquery"; import Backbone from "backbone"; -import Menu from "layout/menu"; +import { fetchMenu } from "layout/menu"; import Scratchbook from "layout/scratchbook"; import QuotaMeter from "mvc/user/user-quotameter"; import { getGalaxyInstance } from "app"; @@ -15,14 +15,7 @@ const View = Backbone.View.extend({ this.options = options; this._component = null; // build tabs - this.collection = new Menu.Collection(); - this.collection - .on("dispatch", (callback) => { - self.collection.each((m) => { - callback(m); - }); - }) - .fetch(this.options); + this.collection = fetchMenu(options); // scratchbook Galaxy.frame = this.frame = new Scratchbook({ @@ -68,8 +61,18 @@ const View = Backbone.View.extend({ if (this.options.brand) { brandTitle += this.options.brand; } - const tabs = this.collection.models.map((el) => { - return el.toJSON(); + const defaults = { + visible: true, + target: "_parent", + }; + const tabs = this.collection.map((el) => { + let asJson; + if (el.toJSON instanceof Function) { + asJson = el.toJSON(); + } else { + asJson = el; + } + return Object.assign({}, defaults, asJson); }); this._component = mountVueComponent(Masthead)( { diff --git a/client/galaxy/scripts/layout/menu.js b/client/galaxy/scripts/layout/menu.js index c8cca192a10a..8b83276765aa 100644 --- a/client/galaxy/scripts/layout/menu.js +++ b/client/galaxy/scripts/layout/menu.js @@ -1,7 +1,5 @@ -/** Masthead Collection **/ import $ from "jquery"; import axios from "axios"; -import Backbone from "backbone"; import { getGalaxyInstance } from "app"; import _l from "utils/localization"; import { CommunicationServerView } from "layout/communication-server-view"; @@ -44,312 +42,301 @@ export function logoutClick() { }); } -const Collection = Backbone.Collection.extend({ - model: Backbone.Model.extend({ - defaults: { - visible: true, - target: "_parent", - }, - }), - fetch: function (options) { - options = options || {}; - this.reset(); - - const Galaxy = getGalaxyInstance(); - - // - // Chat server tab - // - const extendedNavItem = new CommunicationServerView(); - this.add(extendedNavItem.render()); +export function fetchMenu(options = {}) { + const Galaxy = getGalaxyInstance(); + const menu = []; - // - // Analyze data tab. - // - this.add({ - id: "analysis", - title: _l("Analyze Data"), - url: "", - tooltip: _l("Analysis home view"), - }); + // + // Chat server tab + // + const extendedNavItem = new CommunicationServerView(); + menu.push(extendedNavItem.render()); - // - // Workflow tab. - // - this.add({ - id: "workflow", - title: _l("Workflow"), - tooltip: _l("Chain tools into workflows"), - disabled: !Galaxy.user.id, - url: "workflows/list", - target: "__use_router__", - }); + // + // Analyze data tab. + // + menu.push({ + id: "analysis", + title: _l("Analyze Data"), + url: "", + tooltip: _l("Analysis home view"), + }); - // - // Visualization tab. - // - if (Galaxy.config.visualizations_visible) { - this.add({ - id: "visualization", - title: _l("Visualize"), - url: "javascript:void(0)", - tooltip: _l("Visualize datasets"), - disabled: !Galaxy.user.id, - menu: [ - { - title: _l("Create Visualization"), - url: "visualizations", - target: "__use_router__", - }, - { - title: _l("Interactive Environments"), - url: "visualization/gie_list", - target: "galaxy_main", - }, - ], - }); - } + // + // Workflow tab. + // + menu.push({ + id: "workflow", + title: _l("Workflow"), + tooltip: _l("Chain tools into workflows"), + disabled: !Galaxy.user.id, + url: "workflows/list", + target: "__use_router__", + }); - // - // 'Shared Items' or Libraries tab. - // - this.add({ - id: "shared", - title: _l("Shared Data"), + // + // Visualization tab. + // + if (Galaxy.config.visualizations_visible) { + menu.push({ + id: "visualization", + title: _l("Visualize"), url: "javascript:void(0)", - tooltip: _l("Access published resources"), + tooltip: _l("Visualize datasets"), + disabled: !Galaxy.user.id, menu: [ { - title: _l("Data Libraries"), - url: "library/list", - }, - { - title: _l("Histories"), - url: "histories/list_published", - target: "__use_router__", - }, - { - title: _l("Workflows"), - url: "workflows/list_published", - target: "__use_router__", - }, - { - title: _l("Visualizations"), - url: "visualizations/list_published", + title: _l("Create Visualization"), + url: "visualizations", target: "__use_router__", }, { - title: _l("Pages"), - url: "pages/list_published", - target: "__use_router__", + title: _l("Interactive Environments"), + url: "visualization/gie_list", + target: "galaxy_main", }, ], }); + } - // - // Webhooks - // - Webhooks.load({ - type: "masthead", - callback: function (webhooks) { - $(document).ready(() => { - webhooks.each((model) => { - const webhook = model.toJSON(); - if (webhook.activate) { - const obj = { - id: webhook.id, - icon: webhook.config.icon, - url: webhook.config.url, - tooltip: webhook.config.tooltip, - /*jslint evil: true */ - onclick: webhook.config.function && new Function(webhook.config.function), - // fill in model defaults because this isn't added to - // collection first, will make more sense when other - // items aren't defined using backbone - visible: true, - target: "_parent", - }; - appendToPageMenu(obj); - // Append masthead script and styles to Galaxy main - Utils.appendScriptStyle(webhook); - } - }); - }); + // + // 'Shared Items' or Libraries tab. + // + menu.push({ + id: "shared", + title: _l("Shared Data"), + url: "javascript:void(0)", + tooltip: _l("Access published resources"), + menu: [ + { + title: _l("Data Libraries"), + url: "library/list", }, + { + title: _l("Histories"), + url: "histories/list_published", + target: "__use_router__", + }, + { + title: _l("Workflows"), + url: "workflows/list_published", + target: "__use_router__", + }, + { + title: _l("Visualizations"), + url: "visualizations/list_published", + target: "__use_router__", + }, + { + title: _l("Pages"), + url: "pages/list_published", + target: "__use_router__", + }, + ], + }); + + // + // Admin. + // + if (Galaxy.user.get("is_admin")) { + menu.push({ + id: "admin", + title: _l("Admin"), + url: "admin", + tooltip: _l("Administer this Galaxy"), + cls: "admin-only", }); + } - // - // Admin. - // - if (Galaxy.user.get("is_admin")) { - this.add({ - id: "admin", - title: _l("Admin"), - url: "admin", - tooltip: _l("Administer this Galaxy"), - cls: "admin-only", - }); + // + // User tab. + // + let userTab = {}; + if (!Galaxy.user.id) { + if (options.allow_user_creation) { + userTab = { + id: "user", + title: _l("Login or Register"), + cls: "loggedout-only", + url: "login", + tooltip: _l("Log in or register a new account"), + }; + } else { + userTab = { + id: "user", + title: _l("Login"), + cls: "loggedout-only", + tooltip: _l("Login"), + url: "login", + noscratchbook: true, + }; } - - // - // Help tab. - // - const helpTab = { - id: "help", - title: _l("Help"), + } else { + userTab = { + id: "user", + title: _l("User"), + cls: "loggedin-only", url: "javascript:void(0)", - tooltip: _l("Support, contact, and community"), + tooltip: _l("Account and saved data"), menu: [ { - title: _l("Support"), - url: options.support_url, - target: "_blank", + title: `${_l("Logged in as")} ${Galaxy.user.get("email")}`, + class: "dropdown-item disabled", }, { - title: _l("Search"), - url: options.search_url, - target: "_blank", + title: _l("Preferences"), + url: "user", + target: "__use_router__", }, { - title: _l("Mailing Lists"), - url: options.mailing_lists, - target: "_blank", + title: _l("Custom Builds"), + url: "custom_builds", + target: "__use_router__", }, { - title: _l("Videos"), - url: options.screencasts_url, - target: "_blank", + title: _l("Logout"), + divider: true, + onclick: logoutClick, }, { - title: _l("Wiki"), - url: options.wiki_url, - target: "_blank", + title: _l("Datasets"), + url: "datasets/list", + target: "__use_router__", }, { - title: _l("How to Cite Galaxy"), - url: options.citation_url, - target: "_blank", + title: _l("Histories"), + url: "histories/list", + target: "__use_router__", }, { - title: _l("Interactive Tours"), - url: "tours", + title: _l("Histories shared with me"), + url: "histories/list_shared", + target: "__use_router__", + }, + { + title: _l("Pages"), + url: "pages/list", + target: "__use_router__", + }, + { + title: _l("Workflow Invocations"), + url: "workflows/invocations", + target: "__use_router__", }, ], }; - if (options.terms_url) { - helpTab.menu.push({ - title: _l("Terms and Conditions"), - url: options.terms_url, - target: "_blank", + if (Galaxy.config.visualizations_visible) { + userTab.menu.push({ + title: _l("Visualizations"), + url: "visualizations/list", + target: "__use_router__", }); } - if (options.helpsite_url) { - helpTab.menu.unshift({ - title: _l("Galaxy Help"), - url: options.helpsite_url, - target: "_blank", + if (Galaxy.config.interactivetools_enable) { + userTab.menu[userTab.menu.length - 1].divider = true; + userTab.menu.push({ + title: _l("Active InteractiveTools"), + url: "interactivetool_entry_points/list", + target: "__use_router__", }); } - this.add(helpTab); + } + menu.push(userTab); - // - // User tab. - // - let userTab = {}; - if (!Galaxy.user.id) { - if (options.allow_user_creation) { - userTab = { - id: "user", - title: _l("Login or Register"), - cls: "loggedout-only", - url: "login", - tooltip: _l("Log in or register a new account"), - }; - } else { - userTab = { - id: "user", - title: _l("Login"), - cls: "loggedout-only", - tooltip: _l("Login"), - url: "login", - noscratchbook: true, - }; - } - } else { - userTab = { - id: "user", - title: _l("User"), - cls: "loggedin-only", - url: "javascript:void(0)", - tooltip: _l("Account and saved data"), - menu: [ - { - title: `${_l("Logged in as")} ${Galaxy.user.get("email")}`, - class: "dropdown-item disabled", - }, - { - title: _l("Preferences"), - url: "user", - target: "__use_router__", - }, - { - title: _l("Custom Builds"), - url: "custom_builds", - target: "__use_router__", - }, - { - title: _l("Logout"), - divider: true, - onclick: logoutClick, - }, - { - title: _l("Datasets"), - url: "datasets/list", - target: "__use_router__", - }, - { - title: _l("Histories"), - url: "histories/list", - target: "__use_router__", - }, - { - title: _l("Histories shared with me"), - url: "histories/list_shared", - target: "__use_router__", - }, - { - title: _l("Pages"), - url: "pages/list", - target: "__use_router__", - }, - { - title: _l("Workflow Invocations"), - url: "workflows/invocations", - target: "__use_router__", - }, - ], - }; - if (Galaxy.config.visualizations_visible) { - userTab.menu.push({ - title: _l("Visualizations"), - url: "visualizations/list", - target: "__use_router__", - }); - } - if (Galaxy.config.interactivetools_enable) { - userTab.menu[userTab.menu.length - 1].divider = true; - userTab.menu.push({ - title: _l("Active InteractiveTools"), - url: "interactivetool_entry_points/list", - target: "__use_router__", - }); - } - } - this.add(userTab); - return new $.Deferred().resolve().promise(); - }, -}); + // + // Help tab. + // + const helpTab = { + id: "help", + title: _l("Help"), + url: "javascript:void(0)", + tooltip: _l("Support, contact, and community"), + menu: [ + { + title: _l("Support"), + url: options.support_url, + target: "_blank", + }, + { + title: _l("Search"), + url: options.search_url, + target: "_blank", + }, + { + title: _l("Mailing Lists"), + url: options.mailing_lists, + target: "_blank", + }, + { + title: _l("Videos"), + url: options.screencasts_url, + target: "_blank", + }, + { + title: _l("Wiki"), + url: options.wiki_url, + target: "_blank", + }, + { + title: _l("How to Cite Galaxy"), + url: options.citation_url, + target: "_blank", + }, + { + title: _l("Interactive Tours"), + url: "tours", + }, + ], + }; + if (options.terms_url) { + helpTab.menu.push({ + title: _l("Terms and Conditions"), + url: options.terms_url, + target: "_blank", + }); + } + if (options.helpsite_url) { + helpTab.menu.unshift({ + title: _l("Galaxy Help"), + url: options.helpsite_url, + target: "_blank", + }); + } + menu.push(helpTab); + + // Load Webhook menu items, find better place to put this. + loadWebhookMenuItems(); -export default { - Collection: Collection, -}; + return menu; +} + +function loadWebhookMenuItems() { + // + // Webhooks + // + Webhooks.load({ + type: "masthead", + callback: function (webhooks) { + $(document).ready(() => { + webhooks.each((model) => { + const webhook = model.toJSON(); + if (webhook.activate) { + const obj = { + id: webhook.id, + icon: webhook.config.icon, + url: webhook.config.url, + tooltip: webhook.config.tooltip, + /*jslint evil: true */ + onclick: webhook.config.function && new Function(webhook.config.function), + visible: true, + target: "_parent", + }; + appendToPageMenu(obj); + // Append masthead script and styles to Galaxy main + Utils.appendScriptStyle(webhook); + } + }); + }); + }, + }); +} diff --git a/client/galaxy/scripts/layout/scratchbook.js b/client/galaxy/scripts/layout/scratchbook.js index 4f65855a07f5..218ecc430461 100644 --- a/client/galaxy/scripts/layout/scratchbook.js +++ b/client/galaxy/scripts/layout/scratchbook.js @@ -16,13 +16,13 @@ export default Backbone.View.extend({ this.frames = new Frames.View({ visible: false }); this.setElement(this.frames.$el); this.active = false; - this.buttonActive = options.collection.add({ + this.buttonActive = options.collection.push({ id: "enable-scratchbook", icon: "fa-th", tooltip: _l("Enable/Disable Scratchbook"), onclick: () => { this.active = !this.active; - this.buttonActive.set({ + Object.assign(this.buttonActive, { toggle: this.active, show_note: this.active, note_cls: this.active && "fa fa-check", @@ -37,7 +37,7 @@ export default Backbone.View.extend({ } }, }); - this.buttonLoad = options.collection.add({ + this.buttonLoad = options.collection.push({ id: "show-scratchbook", icon: "fa-eye", tooltip: _l("Show/Hide Scratchbook"), From 7b7358f94198f85dff7b97ee2c952df39df37f40 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Tue, 26 May 2020 20:01:15 -0400 Subject: [PATCH 07/11] Fix onbeforeload handling in masthead. --- .../scripts/components/Masthead/MastheadItem.vue | 7 ------- client/galaxy/scripts/layout/masthead.js | 10 ++-------- client/galaxy/scripts/layout/scratchbook.js | 13 ++++++++----- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/client/galaxy/scripts/components/Masthead/MastheadItem.vue b/client/galaxy/scripts/components/Masthead/MastheadItem.vue index 90c0ca4d8f25..262a66c9a71c 100644 --- a/client/galaxy/scripts/components/Masthead/MastheadItem.vue +++ b/client/galaxy/scripts/components/Masthead/MastheadItem.vue @@ -118,13 +118,6 @@ export default { return document.getElementById("galaxy_main"); }, }, - created() { - if (this.tab.onbeforeunload) { - document.addEventListener("beforeunload", () => { - this.tab.onbeforeunload(); - }); - } - }, mounted() { if (this.galaxyIframe) { this.galaxyIframe.addEventListener("load", this.iframeListener); diff --git a/client/galaxy/scripts/layout/masthead.js b/client/galaxy/scripts/layout/masthead.js index 91e8340ef8c1..aa7a667ccf6f 100644 --- a/client/galaxy/scripts/layout/masthead.js +++ b/client/galaxy/scripts/layout/masthead.js @@ -41,14 +41,8 @@ const View = Backbone.View.extend({ } }) .on("beforeunload", () => { - let text = ""; - this.collection.each((model) => { - const q = model.get("onbeforeunload") && model.get("onbeforeunload")(); - if (q) { - text += `${q} `; - } - }); - if (text !== "") { + const text = this.frame.beforeUnload(); + if(text) { return text; } }); diff --git a/client/galaxy/scripts/layout/scratchbook.js b/client/galaxy/scripts/layout/scratchbook.js index 218ecc430461..b63c8100df5e 100644 --- a/client/galaxy/scripts/layout/scratchbook.js +++ b/client/galaxy/scripts/layout/scratchbook.js @@ -31,11 +31,6 @@ export default Backbone.View.extend({ this.frames.hide(); } }, - onbeforeunload: () => { - if (this.frames.length() > 0) { - return `You opened ${this.frames.length()} frame(s) which will be lost.`; - } - }, }); this.buttonLoad = options.collection.push({ id: "show-scratchbook", @@ -59,6 +54,14 @@ export default Backbone.View.extend({ return this.frames; }, + beforeUnload() { + let confirmText = ''; + if (this.frames.length() > 0) { + confirmText = `You opened ${this.frames.length()} frame(s) which will be lost.`; + } + return confirmText; + }, + /** Add a dataset to the frames */ addDataset: function (dataset_id) { const self = this; From 7aa10bca2c14c2f59c40dc2f04424bc087a18e73 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Tue, 26 May 2020 20:01:37 -0400 Subject: [PATCH 08/11] Remove jQuery dependency from menu.js --- client/galaxy/scripts/layout/menu.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/client/galaxy/scripts/layout/menu.js b/client/galaxy/scripts/layout/menu.js index 8b83276765aa..c7beb2c1bc0f 100644 --- a/client/galaxy/scripts/layout/menu.js +++ b/client/galaxy/scripts/layout/menu.js @@ -1,4 +1,3 @@ -import $ from "jquery"; import axios from "axios"; import { getGalaxyInstance } from "app"; import _l from "utils/localization"; @@ -310,6 +309,14 @@ export function fetchMenu(options = {}) { return menu; } +// https://stackoverflow.com/questions/799981/document-ready-equivalent-without-jquery +function ready(callback){ + // in case the document is already rendered + if (document.readyState!='loading') callback(); + // modern browsers + else if (document.addEventListener) document.addEventListener('DOMContentLoaded', callback); +} + function loadWebhookMenuItems() { // // Webhooks @@ -317,7 +324,7 @@ function loadWebhookMenuItems() { Webhooks.load({ type: "masthead", callback: function (webhooks) { - $(document).ready(() => { + ready(() => { webhooks.each((model) => { const webhook = model.toJSON(); if (webhook.activate) { From 9f2acfe6818d82303b5495216c11cc3f074de2e2 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Wed, 27 May 2020 09:09:47 -0400 Subject: [PATCH 09/11] Make masthead brand title logic reactive. --- .../components/Masthead/Masthead.test.js | 10 ++++++ .../scripts/components/Masthead/Masthead.vue | 15 +++++++- client/galaxy/scripts/layout/masthead.js | 36 ++++++++++++++++--- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/client/galaxy/scripts/components/Masthead/Masthead.test.js b/client/galaxy/scripts/components/Masthead/Masthead.test.js index e90fa9448c1a..46d3f82e20a8 100644 --- a/client/galaxy/scripts/components/Masthead/Masthead.test.js +++ b/client/galaxy/scripts/components/Masthead/Masthead.test.js @@ -69,6 +69,16 @@ describe("Masthead.vue", () => { }); }); + it("should disable brand when displayGalaxyBrand is true", async () => { + expect(wrapper.find(".navbar-brand-title").text()).to.equals("Galaxy"); + wrapper.setProps({ brand: "Foo "}); + await localVue.nextTick(); + expect(wrapper.find(".navbar-brand-title").text()).to.equals("Galaxy Foo"); + wrapper.setProps({displayGalaxyBrand: false}); + await localVue.nextTick(); + expect(wrapper.find(".navbar-brand-title").text()).to.equals("Foo"); + }); + it("set quota element and renders it", () => { expect(quotaEl).to.not.equals(null); expect(quotaRendered).to.equals(true); diff --git a/client/galaxy/scripts/components/Masthead/Masthead.vue b/client/galaxy/scripts/components/Masthead/Masthead.vue index 28b257d28436..0bce953ea5ed 100644 --- a/client/galaxy/scripts/components/Masthead/Masthead.vue +++ b/client/galaxy/scripts/components/Masthead/Masthead.vue @@ -38,7 +38,11 @@ import _ from "underscore"; export default { name: "Masthead", props: { - brandTitle: { + displayGalaxyBrand: { + type: Boolean, + default: true, + }, + brand: { type: String, }, brandLink: { @@ -94,6 +98,15 @@ export default { this.activeTab = activeTab; }, }, + computed: { + brandTitle() { + let brandTitle = this.displayGalaxyBrand ? "Galaxy " : ""; + if (this.brand) { + brandTitle += this.brand; + } + return brandTitle; + } + }, mounted() { this.quotaMeter.setElement(this.$refs["quota-meter-container"]); this.quotaMeter.render(); diff --git a/client/galaxy/scripts/layout/masthead.js b/client/galaxy/scripts/layout/masthead.js index aa7a667ccf6f..96c308f41d29 100644 --- a/client/galaxy/scripts/layout/masthead.js +++ b/client/galaxy/scripts/layout/masthead.js @@ -46,15 +46,40 @@ const View = Backbone.View.extend({ return text; } }); + } + +} + +export function mountMasthead(el, options, mastheadState) { + +} + + +/** Masthead **/ +const View = Backbone.View.extend({ + initialize: function (options) { + const Galaxy = getGalaxyInstance(); + this.options = options; + this._component = null; + // build tabs + this.collection = fetchMenu(options); + + // scratchbook + Galaxy.frame = this.frame = new Scratchbook({ + collection: this.collection, + }); + + // set up the quota meter (And fetch the current user data from trans) + // add quota meter to masthead + Galaxy.quotaMeter = this.quotaMeter = new QuotaMeter.UserQuotaMeter({ + model: Galaxy.user, + }); + }, render: function () { 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) { - brandTitle += this.options.brand; - } const defaults = { visible: true, target: "_parent", @@ -70,7 +95,8 @@ const View = Backbone.View.extend({ }); this._component = mountVueComponent(Masthead)( { - brandTitle: brandTitle, + displayGalaxyBrand: this.options.display_galaxy_brand, + brand: this.options.brand, brandLink: this.options.logo_url, brandImage: this.options.logo_src, quotaMeter: this.quotaMeter, From 0aaebc70a7e1d49259da5ffa3fdeef66b3c8ce1d Mon Sep 17 00:00:00 2001 From: John Chilton Date: Wed, 27 May 2020 13:15:35 -0400 Subject: [PATCH 10/11] More reactive, less Backbone-y masthead. --- .../components/Masthead/Masthead.test.js | 44 +++++-- .../scripts/components/Masthead/Masthead.vue | 90 ++++++++------- .../components/Masthead/MastheadItem.vue | 1 + .../components/Masthead/initMasthead.js | 17 +-- client/galaxy/scripts/layout/masthead.js | 109 ++++-------------- client/galaxy/scripts/layout/menu.js | 55 --------- client/galaxy/scripts/layout/page.js | 10 +- client/galaxy/scripts/layout/scratchbook.js | 20 ++-- 8 files changed, 123 insertions(+), 223 deletions(-) diff --git a/client/galaxy/scripts/components/Masthead/Masthead.test.js b/client/galaxy/scripts/components/Masthead/Masthead.test.js index 46d3f82e20a8..327e500546e9 100644 --- a/client/galaxy/scripts/components/Masthead/Masthead.test.js +++ b/client/galaxy/scripts/components/Masthead/Masthead.test.js @@ -1,4 +1,4 @@ -import Masthead from "./Masthead.vue"; +import { default as Masthead, __RewireAPI__ as rewire } from "./Masthead.vue"; import { mount, createLocalVue } from "@vue/test-utils"; import Scratchbook from "layout/scratchbook"; @@ -7,8 +7,25 @@ describe("Masthead.vue", () => { let localVue; let scratchbook; let quotaRendered, quotaEl; + let tabs; + + function stubFetchMenu() { + return tabs; + } + + function stubLoadWebhooks(items) { + items.push({ + id: "extension", + title: "Extension Point", + menu: false, + url: "extension_url", + }); + } beforeEach(() => { + rewire.__Rewire__("fetchMenu", stubFetchMenu); + rewire.__Rewire__("loadWebhookMenuItems", stubLoadWebhooks); + localVue = createLocalVue(); quotaRendered = false; quotaEl = null; @@ -22,7 +39,7 @@ describe("Masthead.vue", () => { }, }; - const tabs = [ + tabs = [ // Main Analysis Tab.. { id: "analysis", @@ -51,16 +68,15 @@ describe("Masthead.vue", () => { tabs.push(x); return x; }; - scratchbook = new Scratchbook({ - collection: tabs, - }); - const frames = scratchbook.getFrames(); + scratchbook = new Scratchbook({}); + const mastheadState = { + quotaMeter, + frame: scratchbook, + }; wrapper = mount(Masthead, { propsData: { - quotaMeter, - frames, - tabs, + mastheadState, activeTab, appRoot: "prefix/", }, @@ -71,10 +87,10 @@ describe("Masthead.vue", () => { it("should disable brand when displayGalaxyBrand is true", async () => { expect(wrapper.find(".navbar-brand-title").text()).to.equals("Galaxy"); - wrapper.setProps({ brand: "Foo "}); + wrapper.setProps({ brand: "Foo " }); await localVue.nextTick(); expect(wrapper.find(".navbar-brand-title").text()).to.equals("Galaxy Foo"); - wrapper.setProps({displayGalaxyBrand: false}); + wrapper.setProps({ displayGalaxyBrand: false }); await localVue.nextTick(); expect(wrapper.find(".navbar-brand-title").text()).to.equals("Foo"); }); @@ -85,7 +101,7 @@ describe("Masthead.vue", () => { }); it("should render simple tab item links", () => { - expect(wrapper.findAll("li.nav-item").length).to.equals(5); + expect(wrapper.findAll("li.nav-item").length).to.equals(6); // 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"); @@ -119,4 +135,8 @@ describe("Masthead.vue", () => { // await localVue.nextTick(); // expect(scratchbook.active).to.equals(true); }); + + it("should load webhooks on creation", async () => { + expect(wrapper.find("#extension a").text()).to.equals("Extension Point"); + }); }); diff --git a/client/galaxy/scripts/components/Masthead/Masthead.vue b/client/galaxy/scripts/components/Masthead/Masthead.vue index 0bce953ea5ed..b8b4383fb975 100644 --- a/client/galaxy/scripts/components/Masthead/Masthead.vue +++ b/client/galaxy/scripts/components/Masthead/Masthead.vue @@ -21,7 +21,6 @@ :appRoot="appRoot" :Galaxy="Galaxy" v-show="!(tab.hidden === undefined ? false : tab.hidden)" - @updateScratchbookTab="updateScratchbookTab" > @@ -33,7 +32,8 @@