diff --git a/client/galaxy/scripts/admin.toolshed.js b/client/galaxy/scripts/admin.toolshed.js
new file mode 100644
index 00000000000..a1baed3aa77
--- /dev/null
+++ b/client/galaxy/scripts/admin.toolshed.js
@@ -0,0 +1,128 @@
+define(["mvc/toolshed/shed-list-view",
+ "mvc/toolshed/categories-view",
+ "mvc/toolshed/repositories-view",
+ "mvc/toolshed/repository-view",
+ "mvc/toolshed/repository-queue-view",
+ "mvc/toolshed/repo-status-view",
+ "mvc/toolshed/workflows-view"],
+ function(mod_shed_list_view,
+ mod_categories_view,
+ mod_repositories_view,
+ mod_repository_view,
+ mod_repoqueue_view,
+ mod_repo_status_view,
+ mod_workflows_view) {
+
+ var AdminToolshedRouter = Backbone.Router.extend({
+
+ initialize: function() {
+ this.routesHit = 0;
+ // keep count of number of routes handled by the application
+ Backbone.history.on( 'route', function() { this.routesHit++; }, this );
+ this.bind( 'route', this.trackPageview );
+ },
+
+ routes: {
+ "" : "toolsheds",
+ "sheds" : "toolsheds",
+ "queue" : "queue",
+ "workflows" : "workflows",
+ "status/r/:repositories" : "status",
+ "status" : "status",
+ "categories/s/:tool_shed" : "categories",
+ "category/s/:tool_shed/c/:cateory_id" : "repositories",
+ "repository/s/:tool_shed/r/:repository_id" : "repository",
+ },
+
+ /**
+ * If more than one route has been hit the user did not land on current
+ * page directly so we can go back safely. Otherwise go to the home page.
+ * Use replaceState if available so the navigation doesn't create an
+ * extra history entry
+ */
+ back: function() {
+ if( this.routesHit > 1 ) {
+ window.history.back();
+ } else {
+ this.navigate( '#', { trigger:true, replace:true } );
+ }
+ }
+
+ });
+
+ var GalaxyAdminToolshedApp = Backbone.View.extend({
+
+ app_config: {
+ known_views: ['toolsheds', 'queue', 'status', 'categories', 'repositories', 'repoository']
+ },
+
+ initialize: function() {
+ Galaxy.admintoolshedapp = this;
+ this.admin_toolshed_router = new AdminToolshedRouter();
+
+ this.admin_toolshed_router.on('route:queue', function() {
+ if (Galaxy.admintoolshedapp.adminRepoQueueView) {
+ Galaxy.admintoolshedapp.adminRepoQueueView.reDraw();
+ }
+ else {
+ Galaxy.admintoolshedapp.adminRepoQueueView = new mod_repoqueue_view.RepoQueueView();
+ }
+ });
+ this.admin_toolshed_router.on('route:toolsheds', function() {
+ if (Galaxy.admintoolshedapp.adminShedListView) {
+ Galaxy.admintoolshedapp.adminShedListView.reDraw();
+ }
+ else {
+ Galaxy.admintoolshedapp.adminShedListView = new mod_shed_list_view.ShedListView();
+ }
+ });
+ this.admin_toolshed_router.on('route:categories', function(tool_shed) {
+ if (Galaxy.admintoolshedapp.adminShedCategoriesView) {
+ Galaxy.admintoolshedapp.adminShedCategoriesView.reDraw({tool_shed: tool_shed.replace(/\//g, '%2f')});
+ }
+ else {
+ Galaxy.admintoolshedapp.adminShedCategoriesView = new mod_categories_view.CategoryView({tool_shed: tool_shed.replace(/\//g, '%2f')});
+ }
+ });
+ this.admin_toolshed_router.on('route:repositories', function(tool_shed, category_id) {
+ if (Galaxy.admintoolshedapp.adminShedCategoryView) {
+ Galaxy.admintoolshedapp.adminShedCategoryView.reDraw({tool_shed: tool_shed.replace(/\//g, '%2f'), category_id: category_id});
+ }
+ else {
+ Galaxy.admintoolshedapp.adminShedCategoryView = new mod_repositories_view.Category({tool_shed: tool_shed.replace(/\//g, '%2f'), category_id: category_id});
+ }
+ });
+ this.admin_toolshed_router.on('route:repository', function(tool_shed, repository_id) {
+ if (Galaxy.admintoolshedapp.adminRepositoryView) {
+ Galaxy.admintoolshedapp.adminRepositoryView.reDraw({tool_shed: tool_shed.replace(/\//g, '%2f'), repository_id: repository_id});
+ }
+ else {
+ Galaxy.admintoolshedapp.adminRepositoryView = new mod_repository_view.RepoDetails({tool_shed: tool_shed.replace(/\//g, '%2f'), repository_id: repository_id});
+ }
+ });
+ this.admin_toolshed_router.on('route:status', function(repositories) {
+ if (Galaxy.admintoolshedapp.adminRepoStatusView) {
+ Galaxy.admintoolshedapp.adminRepoStatusView.reDraw({repositories: repositories.split('|')});
+ }
+ else {
+ Galaxy.admintoolshedapp.adminRepoStatusView = new mod_repo_status_view.RepoStatus({repositories: repositories.split('|')});
+ }
+ });
+ this.admin_toolshed_router.on('route:workflows', function() {
+ if (Galaxy.admintoolshedapp.adminWorkflowsView) {
+ Galaxy.admintoolshedapp.adminWorkflowsView.reDraw();
+ }
+ else {
+ Galaxy.admintoolshedapp.adminWorkflowsView = new mod_workflows_view.Workflows();
+ }
+ });
+
+ Backbone.history.start({pushState: false});
+ },
+ });
+
+ return {
+ GalaxyApp: GalaxyAdminToolshedApp
+ };
+
+});
\ No newline at end of file
diff --git a/client/galaxy/scripts/mvc/toolshed/categories-view.js b/client/galaxy/scripts/mvc/toolshed/categories-view.js
new file mode 100644
index 00000000000..b914e55fe3a
--- /dev/null
+++ b/client/galaxy/scripts/mvc/toolshed/categories-view.js
@@ -0,0 +1,107 @@
+define(['mvc/toolshed/toolshed-model', 'mvc/toolshed/util'], function(toolshed_model, toolshed_util) {
+
+ var ToolShedCategories = Backbone.View.extend({
+
+ el: '#center',
+
+ defaults: {
+ tool_shed: "https://toolshed.g2.bx.psu.edu/"
+ },
+
+ initialize: function(options) {
+ var self = this;
+ var shed = options.tool_shed.replace(/\//g, '%2f');
+ this.options = _.defaults(this.options || options, this.defaults);
+ this.model = new toolshed_model.Categories();
+ this.listenTo(this.model, 'sync', this.render);
+ this.model.url = this.model.url + '?tool_shed_url=' + this.options.tool_shed;
+ this.model.tool_shed = shed;
+ this.model.fetch();
+ },
+
+ render: function(options) {
+ this.options = _.extend(this.options, options);
+ this.options.categories = this.model.models;
+ this.options.queue = toolshed_util.queueLength();
+ var category_list_template = this.templateCategoryList;
+ this.$el.html(category_list_template(this.options));
+ $("#center").css('overflow', 'auto');
+ this.bindEvents();
+ },
+
+ bindEvents: function() {
+ var that = this;
+ require(['libs/jquery/jquery-ui'], function() {
+ $("#search_box").autocomplete({
+ source: function(request, response) {
+ var shed_url = that.model.tool_shed.replace(/%2f/g, '/');
+ var base_url = Galaxy.root + 'api/tool_shed/search';
+ var params = {term: request.term, tool_shed_url: shed_url};
+ $.post(base_url, params, function(data) {
+ console.log(data);
+ result_list = toolshed_util.shedParser(data);
+ response(result_list);
+ });
+ },
+ minLength: 3,
+ select: function(event, ui) {
+ var tsr_id = ui.item.value;
+ var api_url = Galaxy.root + 'api/tool_shed/repository';
+ var params = {"tool_shed_url": that.model.tool_shed, "tsr_id": tsr_id};
+ var new_route = 'repository/s/' + that.model.tool_shed + '/r/' + tsr_id;
+ Backbone.history.navigate(new_route, {trigger: true, replace:true});
+ },
+ });
+ });
+ },
+
+ reDraw: function(options) {
+ this.$el.empty();
+ this.model.url = this.model.url + '?tool_shed_url=' + this.options.tool_shed;
+ this.initialize(options);
+ },
+
+ templateCategoryList: _.template([
+ '',
+ '
',
+ '',
+ '
',
+ '',
+ '" name="search" placeholder="Search repositories by name or id" size="60" type="text" />',
+ '',
+ '
',
+ '
',
+ '
',
+ '',
+ '<% _.each(categories, function(category) { %>',
+ '',
+ '| ',
+ '"><%= category.get("name") %>',
+ ' | ',
+ '<%= category.get("description") %> | ',
+ '<%= category.get("repositories") %> | ',
+ '
',
+ '<% }); %>',
+ '
',
+ '
',
+ '
',
+ ].join(''))
+ });
+
+ return {
+ CategoryView: ToolShedCategories,
+ };
+
+});
\ No newline at end of file
diff --git a/client/galaxy/scripts/mvc/toolshed/repo-queue-view.js b/client/galaxy/scripts/mvc/toolshed/repo-queue-view.js
new file mode 100644
index 00000000000..bccc87fda59
--- /dev/null
+++ b/client/galaxy/scripts/mvc/toolshed/repo-queue-view.js
@@ -0,0 +1,104 @@
+define(['toolshed/repository-queue-model'], function() {
+
+ var ToolShedRepositoryQueue = Backbone.View.extend({
+
+ el: '#category_list',
+
+ render: function(options) {
+ this.options = _.extend(this.options, options);
+ var repository_queue_template = this.templateRepoQueue();
+ this.$el.html(repository_queue_template({repository: this.model}));
+ },
+
+ templateRepoQueueTab: _.template([
+ '',
+ 'Repository Installation Queue',
+ '',
+ ].join('')),
+
+ templateRepoQueue: _.template([
+ '',
+ '
',
+ '',
+ '',
+ '<\% _.each(repositories, function(repository) { \%>',
+ '',
+ '| ',
+ '',
+ ' | ',
+ '',
+ '',
+ ' | ',
+ '<\%= repository.tool_shed_url \%> | ',
+ '<\%= repository.name \%> | ',
+ '<\%= repository.owner \%> | ',
+ '<\%= repository.changeset \%> | ',
+ '
',
+ '<\% }); \%>',
+ '',
+ '
',
+ '
',
+ '
',
+ ].join('')),
+
+ workflows_missing_tools: _.template([
+ '