Skip to content

Commit

Permalink
rewrite Admin/DataTables with Vue
Browse files Browse the repository at this point in the history
  • Loading branch information
anatskiy authored and dannon committed Dec 7, 2017
1 parent 30196f5 commit ab4db89
Show file tree
Hide file tree
Showing 10 changed files with 375 additions and 12 deletions.
16 changes: 12 additions & 4 deletions client/galaxy/scripts/apps/admin.js
Expand Up @@ -12,6 +12,7 @@ import Utils from "utils/utils";
import Page from "layout/page";
import Vue from "libs/vue";
import UserAPIKeys from "components/UserAPIKeys.vue";
import DataTables from "components/admin/data-tables.vue";

window.app = function app(options, bootstrapped) {
window.Galaxy = new GalaxyApp.GalaxyApp(options, bootstrapped);
Expand All @@ -28,7 +29,8 @@ 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) {
Expand Down Expand Up @@ -96,9 +98,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() {
Expand Down
3 changes: 2 additions & 1 deletion client/galaxy/scripts/apps/panels/admin-panel.js
Expand Up @@ -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"),
Expand Down
43 changes: 43 additions & 0 deletions client/galaxy/scripts/components/admin/base-grid.vue
@@ -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>
47 changes: 47 additions & 0 deletions client/galaxy/scripts/components/admin/data-manager-grid.vue
@@ -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>
53 changes: 53 additions & 0 deletions client/galaxy/scripts/components/admin/data-tables-grid.vue
@@ -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 './base-grid.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>
117 changes: 117 additions & 0 deletions client/galaxy/scripts/components/admin/data-tables.vue
@@ -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 './data-tables-grid.vue';
import DataManagerGrid from './data-manager-grid.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>
20 changes: 20 additions & 0 deletions client/galaxy/scripts/components/message.vue
@@ -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>

1 change: 1 addition & 0 deletions lib/galaxy/webapps/galaxy/buildapp.py
Expand Up @@ -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')
Expand Down
33 changes: 26 additions & 7 deletions lib/galaxy/webapps/galaxy/controllers/admin.py
Expand Up @@ -529,6 +529,32 @@ def index(self, trans, **kwd):
}
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
Expand Down Expand Up @@ -856,13 +882,6 @@ def view_datatypes_registry(self, trans, **kwd):
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):
Expand Down

0 comments on commit ab4db89

Please sign in to comment.