Merge pull request #7097 from guerler/display_applications

Replace display applications mako with vue component
This commit is contained in:
Dannon
2018-12-21 14:13:17 -05:00
committed by GitHub
9 changed files with 225 additions and 73 deletions
+9
View File
@@ -14,6 +14,7 @@ import DataTables from "components/admin/DataTables.vue";
import DataTypes from "components/admin/DataTypes.vue";
import DataManagerView from "components/admin/DataManager/DataManagerView.vue";
import DataManagerRouter from "components/admin/DataManager/DataManagerRouter.vue";
import DisplayApplications from "components/admin/DisplayApplications.vue";
import Vue from "vue";
import { serverPath } from "utils/serverPath";
@@ -33,6 +34,7 @@ window.app = function app(options, bootstrapped) {
"(/)admin(/)users": "show_users",
"(/)admin(/)roles": "show_roles",
"(/)admin(/)groups": "show_groups",
"(/)admin(/)display_applications": "show_display_applications",
"(/)admin(/)tool_versions": "show_tool_versions",
"(/)admin(/)quotas": "show_quotas",
"(/)admin(/)repositories": "show_repositories",
@@ -111,19 +113,26 @@ window.app = function app(options, bootstrapped) {
})
);
},
_display_vue_helper: function(component, props) {
let instance = Vue.extend(component);
let vm = document.createElement("div");
this.page.display(vm);
new instance(props).$mount(vm);
},
show_data_tables: function() {
this._display_vue_helper(DataTables);
},
show_data_types: function() {
this._display_vue_helper(DataTypes);
},
show_display_applications: function() {
this._display_vue_helper(DisplayApplications);
},
show_data_manager: function(path) {
let vueMount = document.createElement("div");
this.page.display(vueMount);
@@ -34,6 +34,7 @@ var AdminPanel = Backbone.View.extend({
{
title: _l("Display applications"),
url: "admin/display_applications",
target: "__use_router__",
id: "admin-link-display-applications"
},
{
@@ -0,0 +1,12 @@
import { getAppRoot } from "onload/loadConfig";
import axios from "axios";
export function getDisplayApplications() {
let url = `${getAppRoot()}api/display_applications`;
return axios.get(url);
}
export function reloadDisplayApplications(ids) {
let url = `${getAppRoot()}api/display_applications/reload`;
return axios.post(url, {ids: ids});
}
@@ -0,0 +1,124 @@
<template>
<div>
<b-alert :show="messageVisible" :variant="messageVariant">
{{ messageText }}
</b-alert>
<b-alert :show="warningVisible" variant="warning">
No display applications available.
</b-alert>
<div v-if="applicationsVisible" class="card-header">
There are currently {{ applicationsLength }}
<b-button size="sm" @click.prevent="reloadAll()" title="Reload all display applications" data-placement="bottom">
<span class="fa fa-refresh"/>
</b-button>
display applications loaded.
</div>
<b-table id="display-applications-grid" v-if="applicationsVisible" striped :fields="applicationsAttributes" :items="applications">
<template slot="reload" slot-scope="data">
<b-button size="sm" title="Reload display application" data-placement="bottom" @click.prevent="reload(data.item.id, data.index)">
<span class="fa fa-refresh"/>
</b-button>
</template>
<template slot="links" slot-scope="data">
<li v-for="link in data.item.links">{{ link.name }}</li>
</template>
</b-table>
</div>
</template>
<script>
import { getDisplayApplications, reloadDisplayApplications } from "./AdminServices.js"
export default {
data() {
return {
applications: [],
applicationsLoaded: false,
applicationsAttributes: [
{ key: 'reload' },
{ key: 'name', sortable: true },
{ key: 'id', sortable: true },
{ key: 'version' },
{ key: 'links' }
],
messageText: null,
messageVariant: null
};
},
computed: {
applicationsIndex: function() {
let result = {};
for (let app of this.applications) {
result[app.id] = app;
}
return result;
},
applicationsAll: function() {
let result = [];
for (let app of this.applications) {
result.push(app.id);
}
return result;
},
applicationsVisible: function() {
return this.applications.length > 0;
},
applicationsLength: function() {
return this.applications.length;
},
messageVisible: function() {
return this.messageText != null;
},
warningVisible: function() {
return !this.applicationsVisible && this.applicationsLoaded;
}
},
created() {
getDisplayApplications()
.then(response => {
this.applications = response.data;
this.applicationsLoaded = true;
})
.catch(e => {
this._errorMessage(e);
});
},
methods: {
reload: function(id) {
this._reload([id]);
},
reloadAll: function() {
let ids = [];
for (let app of this.applications) {
ids.push(app.id);
}
this._reload(ids);
},
_reload: function(ids) {
this._highlightRows(this.applicationsAll, "default");
reloadDisplayApplications(ids)
.then(response => {
this.messageVariant = "info";
this.messageText = response.data.message;
this._highlightRows(response.data.failed, "danger");
this._highlightRows(response.data.reloaded, "success");
})
.catch(e => {
this._errorMessage(e);
});
},
_highlightRows: function(appList, status) {
for (let appIndex of appList) {
let app = this.applicationsIndex[appIndex];
if (app) {
app._rowVariant = status;
}
}
},
_errorMessage: function(e) {
let message = e && e.response && e.response.data && e.response.data.err_msg;
this.messageText = message || "Request failed for an unknown reason.";
this.messageVariant = "danger";
}
}
};
</script>
@@ -0,0 +1,61 @@
"""
API operations on annotations.
"""
import logging
from galaxy import queue_worker
from galaxy.web import expose_api, require_admin
from galaxy.web.base.controller import BaseAPIController
log = logging.getLogger(__name__)
class DisplayApplicationsController(BaseAPIController):
@expose_api
def index(self, trans, **kwd):
"""
GET /api/display_applications/
Returns the list of display applications.
:returns: list of available display applications
:rtype: list
"""
response = []
for display_app in trans.app.datatypes_registry.display_applications.values():
response.append({
'id' : display_app.id,
'name': display_app.name,
'version': display_app.version,
'filename_': display_app._filename,
'links': [{'name': l.name} for l in display_app.links.values()]
})
return response
@expose_api
@require_admin
def reload(self, trans, payload={}, **kwd):
"""
POST /api/display_applications/reload
Reloads the list of display applications.
:param ids: list containing ids of display to be reloaded
:type ids: list
"""
ids = payload.get('ids')
queue_worker.send_control_task(trans.app,
'reload_display_application',
noop_self=True,
kwargs={'display_application_ids': ids})
reloaded, failed = trans.app.datatypes_registry.reload_display_applications(ids)
if not reloaded and failed:
message = 'Unable to reload any of the %i requested display applications ("%s").' % (len(failed), '", "'.join(failed))
elif failed:
message = 'Reloaded %i display applications ("%s"), but failed to reload %i display applications ("%s").' % (len(reloaded), '", "'.join(reloaded), len(failed), '", "'.join(failed))
elif not reloaded:
message = 'You need to request at least one display application to reload.'
else:
message = 'Reloaded %i requested display applications ("%s").' % (len(reloaded), '", "'.join(reloaded))
return {'message': message, 'reloaded': reloaded, 'failed': failed}
+17
View File
@@ -103,6 +103,7 @@ def app_factory(global_conf, load_app_kwds={}, **kwargs):
webapp.add_client_route('/admin/data_types', 'admin')
webapp.add_client_route('/admin/data_manager{path_info:.*}', 'admin')
webapp.add_client_route('/admin/users', 'admin')
webapp.add_client_route('/admin/display_applications', 'admin')
webapp.add_client_route('/admin/roles', 'admin')
webapp.add_client_route('/admin/forms', 'admin')
webapp.add_client_route('/admin/groups', 'admin')
@@ -553,6 +554,22 @@ def populate_api_routes(webapp, app):
action='get_api_key',
conditions=dict(method=["GET"]))
# ======================================
# ====== DISPLAY APPLICATIONS API ======
# ======================================
webapp.mapper.connect('index',
'/api/display_applications',
controller='display_applications',
action='index',
conditions=dict(method=["GET"]))
webapp.mapper.connect('reload',
'/api/display_applications/reload',
controller='display_applications',
action='reload',
conditions=dict(method=["POST"]))
# =====================
# ===== TOURS API =====
# =====================
@@ -908,29 +908,6 @@ class AdminGalaxy(controller.JSAppLauncher, AdminActions, UsesQuotaMixin, QuotaP
def tool_errors(self, trans, **kwd):
return trans.fill_template('admin/tool_errors.mako', tool_errors=global_tool_errors.error_stack)
@web.expose
@web.require_admin
def display_applications(self, trans, **kwd):
return trans.fill_template('admin/view_display_applications.mako', display_applications=trans.app.datatypes_registry.display_applications)
@web.expose
@web.require_admin
def reload_display_application(self, trans, **kwd):
galaxy.queue_worker.send_control_task(trans.app,
'reload_display_application',
noop_self=True,
kwargs={'display_application_ids': kwd.get('id')})
reloaded, failed = trans.app.datatypes_registry.reload_display_applications(kwd.get('id'))
if not reloaded and failed:
return trans.show_error_message('Unable to reload any of the %i requested display applications ("%s").'
% (len(failed), '", "'.join(failed)))
if failed:
return trans.show_warn_message('Reloaded %i display applications ("%s"), but failed to reload %i display applications ("%s").'
% (len(reloaded), '", "'.join(reloaded), len(failed), '", "'.join(failed)))
if not reloaded:
return trans.show_warn_message('You need to request at least one display application to reload.')
return trans.show_ok_message('Reloaded %i requested display applications ("%s").' % (len(reloaded), '", "'.join(reloaded)))
@web.expose
@web.require_admin
def center(self, trans, **kwd):
@@ -1,48 +0,0 @@
<%inherit file="/base.mako"/>
<%namespace file="/message.mako" import="render_msg" />
%if message:
${render_msg( message, status )}
%endif
<div class="card" id="display-applications-grid">
<div class="card-header">There are currently ${len( display_applications )} <a class="icon-btn" href="${ h.url_for( controller='admin', action='reload_display_application' ) }" title="Reload all display applications" data-placement="bottom">
<span class="fa fa-refresh"></span>
</a> display applications loaded.</div>
<div class="card-body overflow-auto">
<table class="manage-table colored">
<tr>
<th>Reload</th>
<th>Name</th>
<th>ID</th>
<th>Version</th>
<th>Links</th>
<th>Filename</th>
</tr>
<% ctr = 0 %>
%for display_app in display_applications.values():
%if ctr % 2 == 1:
<tr class="odd_row">
%else:
<tr class="tr">
%endif
<td>
<a class="icon-btn" href="${ h.url_for( controller='admin', action='reload_display_application', id=display_app.id ) }" title="Reload ${ display_app.name | h } display application" data-placement="bottom">
<span class="fa fa-refresh"></span>
</a>
</td>
<td>${ display_app.name | h }</td>
<td>${ display_app.id | h }</td>
<td>${ display_app.version | h }</td>
<td><ul>
%for link in display_app.links.values():
<li>${ link.name | h }</li>
%endfor
</ul></td>
<td>${ display_app._filename | h }</td>
</tr>
<% ctr += 1 %>
%endfor
</table>
</div>
</div>
+1 -2
View File
@@ -23,8 +23,7 @@ class AdminAppTestCase(SeleniumTestCase):
self.screenshot("admin_data_tables")
admin_component.index.display_applications.wait_for_and_click()
with self.main_panel():
admin_component.display_applications_grid.wait_for_visible()
self.assert_warning_message("No display applications available.")
self.screenshot("admin_display_applications")
admin_component.index.jobs.wait_for_and_click()