Merge pull request #5191 from dannon/admin_data_tables_vue

Admin data tables vue
This commit is contained in:
Aysam Guerler
2017-12-14 22:28:18 -05:00
committed by GitHub
16 changed files with 387 additions and 25 deletions
+14 -7
View File
@@ -5,13 +5,13 @@ import GalaxyApp from "galaxy";
import AdminPanel from "./panels/admin-panel";
import FormWrapper from "mvc/form/form-wrapper";
import GridView from "mvc/grid/grid-view";
import Ui from "mvc/ui/ui-misc";
import QueryStringParsing from "utils/query-string-parsing";
import Router from "layout/router";
import Utils from "utils/utils";
import Page from "layout/page";
import UserAPIKeys from "components/admin/UserAPIKeys.vue";
import DataTables from "components/admin/DataTables.vue";
import Vue from "vue";
import UserAPIKeys from "components/UserAPIKeys.vue";
window.app = function app(options, bootstrapped) {
window.Galaxy = new GalaxyApp.GalaxyApp(options, bootstrapped);
@@ -28,10 +28,11 @@ window.app = function app(options, bootstrapped) {
"(/)admin(/)repositories": "show_repositories",
"(/)admin(/)forms": "show_forms",
"(/)admin(/)form(/)(:form_id)": "show_form",
"(/)admin/api_keys": "show_user_api_keys"
"(/)admin/api_keys": "show_user_api_keys",
"(/)admin/data_tables": "show_data_tables"
},
authenticate: function(args, name) {
authenticate: function() {
return Galaxy.user && Galaxy.user.id && Galaxy.user.get("is_admin");
},
@@ -90,9 +91,15 @@ window.app = function app(options, bootstrapped) {
},
show_user_api_keys: function() {
var vuemount = document.createElement("div");
this.page.display(vuemount);
new Vue(UserAPIKeys).$mount(vuemount);
var vueMount = document.createElement("div");
this.page.display(vueMount);
new Vue(UserAPIKeys).$mount(vueMount);
},
show_data_tables: function() {
var vueMount = document.createElement("div");
this.page.display(vueMount);
new Vue(DataTables).$mount(vueMount);
},
show_forms: function() {
@@ -22,7 +22,8 @@ var AdminPanel = Backbone.View.extend({
},
{
title: _l("Data tables"),
url: "admin/view_tool_data_tables"
url: "admin/data_tables",
target: "__use_router__"
},
{
title: _l("Display applications"),
@@ -0,0 +1,20 @@
<template>
<div v-if="message" :class="[status + 'message']">{{ message }}</div>
</template>
<script>
export default {
name: 'Message',
props: {
message: {
type: String,
required: true
},
status: {
type: String,
default: 'done'
}
}
}
</script>
@@ -0,0 +1,43 @@
<template>
<div class="toolForm">
<div class="toolFormTitle">
<slot name="title">{{ title }}</slot>
</div>
<div class="toolFormBody">
<table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" width="100%">
<slot name="columns">
<th v-for="column in columns" bgcolor="#D8D8D8">{{ column.text }}</th>
</slot>
<slot name="rows">
<template v-for="(row, index) in rows">
<tr :class="[index % 2 === 0 ? 'tr' : 'odd_row']">
<td v-for="column in columns">{{ row[column.dataIndex] }}</td>
</tr>
</template>
</slot>
</table>
<div v-if="isLoaded !== undefined && !isLoaded" :style="{ textAlign: 'center', padding: '7px 0' }">
Loading...
</div>
</div>
</div>
</template>
<script>
export default {
props: {
isLoaded: {
type: Boolean
},
title: {
type: String
},
columns: {
type: Array
},
rows: {
type: Array
}
}
}
</script>
@@ -0,0 +1,47 @@
<template>
<table class="tabletip">
<thead>
<tr>
<th :colspan="dataManagerColumns.length" style="font-size:120%">
Data Manager: {{ dataManagerTableName }}
<a class="icon-btn" href="javascript:void(0)"
@click="handleReloadButtonClick"
:title="`Reload ${dataManagerTableName} tool data table`"
><span class="fa fa-refresh"></span></a>
</th>
</tr>
<tr>
<th v-for="column in dataManagerColumns">{{ column }}</th>
</tr>
</thead>
<tbody v-for="item in dataManagerItems">
<tr>
<td v-for="column in dataManagerColumns">{{ item[column] }}</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
props: {
dataManagerTableName: {
type: String,
required: true
},
dataManagerColumns: {
type: Array,
required: true
},
dataManagerItems: {
type: Array,
required: true
}
},
methods: {
handleReloadButtonClick(event) {
this.$emit('reloaddatamanager', this.dataManagerTableName);
}
}
}
</script>
@@ -0,0 +1,117 @@
<template>
<div>
<message :message="message" :status="status"></message>
<component
:is="currentView"
v-if="status !== 'error'"
v-bind="currentProps"
@changeview="showDataManager"
@reloaddatamanager="reloadDataManager">
</component>
</div>
</template>
<script>
import axios from 'axios';
import Message from '../Message.vue';
import DataTablesGrid from './DataTablesGrid.vue';
import DataManagerGrid from './DataManagerGrid.vue';
export default {
data() {
return {
currentView: 'data-tables-grid',
isLoaded: false,
dataTables: [],
dataManagerTableName: '',
dataManagerColumns: [],
dataManagerItems: [],
message: '',
status: ''
}
},
components: {
message: Message,
'data-tables-grid': DataTablesGrid,
'data-manager-grid': DataManagerGrid
},
computed: {
currentProps() {
let props;
if (this.currentView === 'data-tables-grid') {
props = {
isLoaded: this.isLoaded,
rows: this.dataTables
};
} else {
props = {
dataManagerTableName: this.dataManagerTableName,
dataManagerColumns: this.dataManagerColumns,
dataManagerItems: this.dataManagerItems
};
}
return props;
}
},
methods: {
showDataManager(dataManagerTableName) {
axios.get(`${Galaxy.root}data_manager/tool_data_table_items`, {
params: {
table_name: dataManagerTableName
}
})
.then((response) => {
this.message = response.data.message;
this.status = response.data.status;
if (response.data.status !== 'error' && response.data.status !== 'warning') {
this.dataManagerTableName = dataManagerTableName;
this.dataManagerColumns = response.data.data.columns;
this.dataManagerItems = response.data.data.items;
this.currentView = 'data-manager-grid';
}
})
.catch((error) => {
console.error(error);
});
},
reloadDataManager(dataManagerTableName) {
axios.get(`${Galaxy.root}data_manager/reload_tool_data_table`, {
params: {
table_name: dataManagerTableName
}
})
.then((response) => {
this.message = response.data.message;
this.status = response.data.status;
if (response.data.status !== 'error' && response.data.status !== 'warning') {
this.dataManagerItems = response.data.data.items;
}
})
.catch((error) => {
console.error(error);
});
}
},
created() {
axios.get(`${Galaxy.root}admin/data_tables_list`)
.then((response) => {
this.isLoaded = true;
this.dataTables = response.data.data;
this.message = response.data.message;
this.status = response.data.status;
})
.catch((error) => {
console.error(error);
});
}
}
</script>
@@ -0,0 +1,53 @@
<template>
<base-grid :is-loaded="isLoaded" :columns="columns">
<template slot="title">
Current data table registry contains {{ rows.length }} data tables
</template>
<template slot="rows" v-for="(row, index) in rows">
<tr :class="[index % 2 === 0 ? 'tr' : 'odd_row']">
<td><a href="javascript:void(0)" @click="handleTableNameClick">{{ row.name }}</a></td>
<td>{{ row.filename }}</td>
<td>{{ row.tool_data_path }}</td>
<td>{{ row.errors }}</td>
</tr>
</template>
</base-grid>
</template>
<script>
import BaseGrid from './BaseGrid.vue';
export default {
props: {
isLoaded: {
type: Boolean,
required: true
},
rows: {
type: Array,
required: true
}
},
data() {
return {
columns: [
{ text: 'Name', dataIndex: 'name' },
{ text: 'Filename', dataIndex: 'filename' },
{ text: 'Tool data path', dataIndex: 'tool_data_path' },
{ text: 'Errors', dataIndex: 'errors' }
]
}
},
components: {
'base-grid': BaseGrid
},
methods: {
handleTableNameClick(event) {
this.$emit('changeview', event.target.text);
}
}
}
</script>
+1
View File
@@ -93,6 +93,7 @@ def app_factory(global_conf, load_app_kwds={}, **kwargs):
# The following routes don't bootstrap any information, simply provide the
# base analysis interface at which point the application takes over.
webapp.add_client_route('/admin/data_tables', 'admin')
webapp.add_client_route('/admin/users', 'admin')
webapp.add_client_route('/admin/roles', 'admin')
webapp.add_client_route('/admin/forms', 'admin')
+26 -7
View File
@@ -524,6 +524,32 @@ class AdminGalaxy(controller.JSAppLauncher, AdminActions, UsesQuotaMixin, QuotaP
}
return self.template(trans, 'admin', settings=settings, message=message, status=status)
@web.expose
@web.json
@web.require_admin
def data_tables_list(self, trans, **kwd):
data = []
message = kwd.get('message', '')
status = kwd.get('status', 'done')
sorted_data_tables = sorted(
trans.app.tool_data_tables.get_tables().items()
)
for data_table_elem_name, data_table in sorted_data_tables:
for filename, file_dict in data_table.filenames.iteritems():
file_missing = ['file missing'] \
if not file_dict.get('found') else []
data.append({
'name': data_table.name,
'filename': filename,
'tool_data_path': file_dict.get('tool_data_path'),
'errors': ', '.join(file_missing + [
error for error in file_dict.get('errors', [])
]),
})
return {'data': data, 'message': message, 'status': status}
@web.expose
@web.json
@web.require_admin
@@ -849,13 +875,6 @@ class AdminGalaxy(controller.JSAppLauncher, AdminActions, UsesQuotaMixin, QuotaP
status = util.restore_text(kwd.get('status', 'done'))
return trans.fill_template('admin/view_datatypes_registry.mako', message=message, status=status)
@web.expose
@web.require_admin
def view_tool_data_tables(self, trans, **kwd):
message = escape(util.restore_text(kwd.get('message', '')))
status = util.restore_text(kwd.get('status', 'done'))
return trans.fill_template('admin/view_data_tables_registry.mako', message=message, status=status)
@web.expose
@web.require_admin
def display_applications(self, trans, **kwd):
@@ -116,3 +116,57 @@ class DataManager(BaseUIController):
message=message,
status=status)
return trans.response.send_redirect(redirect_url)
@web.expose
@web.json
@web.require_admin
def tool_data_table_items(self, trans, **kwd):
data = {'columns': [], 'items': []}
message = kwd.get('message', '')
status = kwd.get('status', 'info')
table_name = kwd.get('table_name', None)
if not table_name:
return {
'data': data,
'message': 'No Data table name provided.',
'status': 'warning',
}
data_table = trans.app.tool_data_tables.get(table_name, None)
if data_table is None:
return {
'data': data,
'message': 'Invalid Data table (%s) was requested' % table_name,
'status': 'error'
}
columns = data_table.get_column_name_list()
rows = [dict(zip(columns, table_row)) for table_row in data_table.data]
data['columns'] = columns
data['items'] = rows
return {'data': data, 'message': message, 'status': status}
@web.expose
@web.json
@web.require_admin
def reload_tool_data_table(self, trans, **kwd):
table_name = kwd.get('table_name', None)
if not table_name:
return {
'message': 'No data table has been reloaded.',
'status': 'error',
}
redirect_url = web.url_for(
controller='data_manager',
action='tool_data_table_items',
table_name=table_name,
message='The data table "%s" has been reloaded.' % table_name,
status='done',
)
return trans.response.send_redirect(redirect_url)
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long