mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge pull request #5191 from dannon/admin_data_tables_vue
Admin data tables vue
This commit is contained in:
@@ -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>
|
||||
@@ -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')
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user