mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge pull request #8090 from guerler/new_toolshed
Convert repository client to vue
This commit is contained in:
@@ -136,7 +136,6 @@ GalaxyApp.prototype._patchGalaxy = function _patchGalaxy(patchWith) {
|
||||
|
||||
/** set up the metrics logger (utils/metrics-logger) and pass loggerOptions */
|
||||
GalaxyApp.prototype._initLogger = function _initLogger(loggerOptions) {
|
||||
|
||||
// default to console logging at the debug level if the debug flag is set
|
||||
if (this.config.debug) {
|
||||
loggerOptions.consoleLogger = loggerOptions.consoleLogger || console;
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="loading">
|
||||
<span class="fa fa-spinner fa-spin mb-4 mr-1" />
|
||||
<span>Loading categories...</span>
|
||||
</div>
|
||||
<b-table v-else striped :items="categories" :fields="fields">
|
||||
<template slot="name" slot-scope="data">
|
||||
<b-link href="#" class="font-weight-bold" @click="onCategory(data.value)">
|
||||
{{ data.value }}
|
||||
</b-link>
|
||||
</template>
|
||||
</b-table>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { Services } from "./services.js";
|
||||
export default {
|
||||
props: ["toolshedUrl", "loading"],
|
||||
data() {
|
||||
return {
|
||||
categories: [],
|
||||
fields: {
|
||||
name: {
|
||||
label: "Category",
|
||||
sortable: true
|
||||
},
|
||||
description: {
|
||||
sortable: false
|
||||
},
|
||||
repositories: {
|
||||
sortable: true
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.services = new Services();
|
||||
this.load();
|
||||
},
|
||||
watch: {
|
||||
toolshedUrl() {
|
||||
this.load();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
load() {
|
||||
this.$emit("onLoading", true);
|
||||
this.services
|
||||
.getCategories(this.toolshedUrl)
|
||||
.then(categories => {
|
||||
this.categories = categories;
|
||||
const reducer = (value, entry) => value + entry.repositories;
|
||||
this.$emit("onTotal", this.categories.reduce(reducer, 0));
|
||||
this.$emit("onLoading", false);
|
||||
})
|
||||
.catch(errorMessage => {
|
||||
this.$emit("onError", errorMessage);
|
||||
this.$emit("onLoading", false);
|
||||
});
|
||||
},
|
||||
onCategory(category) {
|
||||
this.$emit("onCategory", category);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div class="overflow-auto h-100 p-1" @scroll="onScroll">
|
||||
<div v-if="error" class="alert alert-danger">{{ error }}</div>
|
||||
<div v-else>
|
||||
<b-input
|
||||
class="mb-3"
|
||||
placeholder="search repositories"
|
||||
v-model="queryInput"
|
||||
@input="delayQuery"
|
||||
@change="setQuery"
|
||||
/>
|
||||
<serverselection
|
||||
:toolshedUrl="toolshedUrl"
|
||||
:toolshedUrls="toolshedUrls"
|
||||
:total="total"
|
||||
:loading="loading"
|
||||
@onToolshed="setToolshed"
|
||||
/>
|
||||
<repositories
|
||||
:query="query"
|
||||
:scrolled="scrolled"
|
||||
:toolshedUrl="toolshedUrl"
|
||||
@onError="setError"
|
||||
v-if="!queryEmpty"
|
||||
/>
|
||||
<categories
|
||||
:toolshedUrl="toolshedUrl"
|
||||
:loading="loading"
|
||||
@onCategory="setQuery"
|
||||
@onTotal="setTotal"
|
||||
@onError="setError"
|
||||
@onLoading="setLoading"
|
||||
v-show="queryEmpty"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getGalaxyInstance } from "app";
|
||||
import Categories from "./Categories.vue";
|
||||
import Repositories from "./Repositories.vue";
|
||||
import ServerSelection from "./ServerSelection.vue";
|
||||
export default {
|
||||
components: {
|
||||
categories: Categories,
|
||||
repositories: Repositories,
|
||||
serverselection: ServerSelection
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
toolshedUrl: null,
|
||||
toolshedUrls: [],
|
||||
queryInput: null,
|
||||
queryDelay: 1000,
|
||||
queryTimer: null,
|
||||
queryLength: 3,
|
||||
query: null,
|
||||
scrolled: false,
|
||||
loading: false,
|
||||
total: 0,
|
||||
error: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.configureToolsheds();
|
||||
},
|
||||
computed: {
|
||||
queryEmpty() {
|
||||
return !this.query || this.query.length < this.queryLength;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
configureToolsheds() {
|
||||
const galaxy = getGalaxyInstance();
|
||||
this.toolshedUrls = galaxy.config.tool_shed_urls;
|
||||
if (!this.toolshedUrls || this.toolshedUrls.length == 0) {
|
||||
this.setError("Toolshed registry is empty, no servers found.");
|
||||
} else {
|
||||
this.toolshedUrl = this.toolshedUrls[0];
|
||||
}
|
||||
},
|
||||
clearTimer() {
|
||||
if (this.queryTimer) {
|
||||
clearTimeout(this.queryTimer);
|
||||
}
|
||||
},
|
||||
delayQuery(query) {
|
||||
this.clearTimer();
|
||||
if (query) {
|
||||
this.queryTimer = setTimeout(() => {
|
||||
this.setQuery(query);
|
||||
}, this.queryDelay);
|
||||
} else {
|
||||
this.setQuery(query);
|
||||
}
|
||||
},
|
||||
setError(error) {
|
||||
this.error = error;
|
||||
},
|
||||
setQuery(query) {
|
||||
this.clearTimer();
|
||||
this.query = this.queryInput = query;
|
||||
},
|
||||
setToolshed(url) {
|
||||
this.toolshedUrl = url;
|
||||
},
|
||||
setTotal(total) {
|
||||
this.total = total;
|
||||
},
|
||||
setLoading(loading) {
|
||||
this.loading = loading;
|
||||
},
|
||||
onScroll: function({ target: { scrollTop, clientHeight, scrollHeight } }) {
|
||||
this.scrolled = scrollTop + clientHeight >= scrollHeight;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-button v-if="installState" :class="buttonClass" variant="primary" @click="onInstall">
|
||||
Install
|
||||
</b-button>
|
||||
<div v-else>
|
||||
<b-button v-if="uninstallState" :class="buttonClass" variant="danger" @click="onUninstall">
|
||||
Uninstall
|
||||
</b-button>
|
||||
<b-button v-else :class="buttonClass" @click="onUninstall">
|
||||
<span v-if="!errorState" class="fa fa-spinner fa-spin" />
|
||||
<span>{{ status }}</span>
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ["installed", "status"],
|
||||
data() {
|
||||
return {
|
||||
buttonClass: "btn-sm text-nowrap"
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
installState() {
|
||||
return !this.status || this.status == "Uninstalled";
|
||||
},
|
||||
uninstallState() {
|
||||
return this.status == "Installed";
|
||||
},
|
||||
errorState() {
|
||||
return this.status == "Error";
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onInstall() {
|
||||
this.$emit("onInstall");
|
||||
},
|
||||
onUninstall() {
|
||||
this.$emit("onUninstall");
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<b-modal v-model="modalShow" @ok="onOk" @hide="onHide">
|
||||
<template slot="modal-header">
|
||||
<h4 class="m-0">
|
||||
{{ modalTitle }}
|
||||
</h4>
|
||||
</template>
|
||||
<div class="mb-1">
|
||||
{{ repo.long_description || repo.description }}
|
||||
</div>
|
||||
<div class="text-muted small mb-3">{{ repo.repo_owner_username }} rev. {{ changesetRevision }}</div>
|
||||
<b-form-group
|
||||
v-if="requiresPanel"
|
||||
label="Target Section:"
|
||||
description="Choose an existing tool panel section or create a new section to contain the installed tools (optional)."
|
||||
>
|
||||
<b-form-input list="sectionSelect" v-model="toolSection" />
|
||||
<datalist id="sectionSelect">
|
||||
<option v-for="section in toolSections" :key="section.name">
|
||||
{{ section.name }}
|
||||
</option>
|
||||
</datalist>
|
||||
</b-form-group>
|
||||
<b-link variant="primary" @click="onAdvanced"> {{ advancedTitle }} advanced settings. </b-link>
|
||||
<b-collapse id="advanced-collapse" v-model="advancedShow" class="mt-2">
|
||||
<b-card>
|
||||
<b-form-group v-if="showConfig" label="Tool Configuration:" description="Choose a tool configuration.">
|
||||
<b-form-radio
|
||||
v-for="filename in toolConfigs"
|
||||
v-model="toolConfig"
|
||||
:value="filename"
|
||||
:key="filename"
|
||||
>
|
||||
{{ filename }}
|
||||
</b-form-radio>
|
||||
</b-form-group>
|
||||
<b-form-group label="Dependencies:" description="Choose how to handle dependencies.">
|
||||
<b-form-checkbox v-model="installResolverDependencies">
|
||||
Install resolvable dependencies
|
||||
</b-form-checkbox>
|
||||
<b-form-checkbox v-model="installRepositoryDependencies">
|
||||
Install repository dependencies
|
||||
</b-form-checkbox>
|
||||
<b-form-checkbox v-model="installToolDependencies">
|
||||
Install tool dependencies
|
||||
</b-form-checkbox>
|
||||
</b-form-group>
|
||||
</b-card>
|
||||
</b-collapse>
|
||||
</b-modal>
|
||||
</template>
|
||||
<script>
|
||||
import { getGalaxyInstance } from "app";
|
||||
import { Services } from "./services.js";
|
||||
export default {
|
||||
props: ["repo", "changesetRevision", "requiresPanel", "toolshedUrl"],
|
||||
data() {
|
||||
return {
|
||||
modalShow: true,
|
||||
advancedShow: false,
|
||||
installToolDependencies: true,
|
||||
installRepositoryDependencies: true,
|
||||
installResolverDependencies: true,
|
||||
toolConfigs: [],
|
||||
toolConfig: null,
|
||||
toolSections: [],
|
||||
toolSection: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
advancedTitle() {
|
||||
return this.advancedShow ? "Hide" : "Show";
|
||||
},
|
||||
modalTitle() {
|
||||
return `Installing '${this.repo.name}'`;
|
||||
},
|
||||
showConfig() {
|
||||
return this.toolConfigs.length > 1;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.services = new Services();
|
||||
this.loadConfig();
|
||||
},
|
||||
methods: {
|
||||
findSection: function(name) {
|
||||
const result = ['', ''];
|
||||
if (name) {
|
||||
const found = this.toolSections.find(s => {
|
||||
return s.name.toLowerCase().trim() == name.toLowerCase().trim();
|
||||
});
|
||||
if (found) {
|
||||
result[0] = found.id;
|
||||
} else {
|
||||
result[1] = name;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
loadConfig: function() {
|
||||
const galaxy = getGalaxyInstance();
|
||||
const sections = galaxy.config.toolbox_in_panel;
|
||||
this.toolSections = sections.filter(x => x.model_class == "ToolSection");
|
||||
this.toolConfigs = galaxy.config.tool_dynamic_configs || [];
|
||||
if (this.toolConfigs.length > 0) {
|
||||
this.toolConfig = this.toolConfigs[0];
|
||||
}
|
||||
},
|
||||
onAdvanced: function() {
|
||||
this.advancedShow = !this.advancedShow;
|
||||
},
|
||||
onOk: function() {
|
||||
const [sectionId, sectionLabel] = this.findSection(this.toolSection);
|
||||
this.services
|
||||
.installRepository({
|
||||
tool_shed_url: this.toolshedUrl,
|
||||
name: this.repo.name,
|
||||
owner: this.repo.repo_owner_username,
|
||||
changeset_revision: this.changesetRevision,
|
||||
new_tool_panel_section_label: sectionLabel,
|
||||
tool_panel_section_id: sectionId,
|
||||
shed_tool_conf: this.toolConfig,
|
||||
install_resolver_dependencies: this.installResolverDependencies,
|
||||
install_tool_dependencies: this.installToolDependencies,
|
||||
install_repository_dependencies: this.installRepositoryDependencies
|
||||
})
|
||||
.then(response => {
|
||||
window.console.log(response);
|
||||
this.$emit("ok");
|
||||
})
|
||||
.catch(error => {});
|
||||
},
|
||||
onHide: function() {
|
||||
this.$emit("hide");
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-table striped :items="repositories" :fields="fields">
|
||||
<template slot="name" slot-scope="row">
|
||||
<b-link href="#" class="font-weight-bold" @click="row.toggleDetails">
|
||||
{{ row.item.name }}
|
||||
</b-link>
|
||||
</template>
|
||||
<template slot="row-details" slot-scope="row">
|
||||
<repositorydetails :repo="row.item" :toolshedUrl="toolshedUrl" />
|
||||
</template>
|
||||
</b-table>
|
||||
<div v-if="noResultsFound">
|
||||
No matching repositories found.
|
||||
</div>
|
||||
<div v-if="pageLoading">
|
||||
<span class="fa fa-spinner fa-spin mb-4" />
|
||||
<span>Loading repositories...</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import RepositoryDetails from "./RepositoryDetails.vue";
|
||||
import { Services } from "./services.js";
|
||||
const READY = 0;
|
||||
const LOADING = 1;
|
||||
const COMPLETE = 2;
|
||||
export default {
|
||||
components: {
|
||||
repositorydetails: RepositoryDetails
|
||||
},
|
||||
props: ["query", "scrolled", "toolshedUrl"],
|
||||
data() {
|
||||
return {
|
||||
repositories: [],
|
||||
fields: [
|
||||
{ key: "name" },
|
||||
{ key: "description" },
|
||||
{ key: "last_updated", label: "Updated" },
|
||||
{ key: "repo_owner_username", label: "Owner" },
|
||||
{ key: "times_downloaded", label: "Downloaded" }
|
||||
],
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
pageState: READY,
|
||||
error: null
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
toolshedUrl() {
|
||||
this.load();
|
||||
},
|
||||
query() {
|
||||
this.load();
|
||||
},
|
||||
scrolled() {
|
||||
if (this.scrolled && this.pageState === READY) {
|
||||
this.load(this.page + 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
pageLoading() {
|
||||
return this.pageState === LOADING;
|
||||
},
|
||||
noResultsFound() {
|
||||
return this.repositories.length === 0 && !this.pageLoading;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.services = new Services();
|
||||
this.load();
|
||||
},
|
||||
methods: {
|
||||
load(page = 1) {
|
||||
this.page = page;
|
||||
this.pageState = LOADING;
|
||||
if (page == 1) {
|
||||
this.repositories = [];
|
||||
}
|
||||
this.services
|
||||
.getRepositories({
|
||||
tool_shed_url: this.toolshedUrl,
|
||||
q: this.query,
|
||||
page: this.page,
|
||||
page_size: this.pageSize
|
||||
})
|
||||
.then(incoming => {
|
||||
this.repositories = this.repositories.concat(incoming);
|
||||
if (incoming.length < this.pageSize) {
|
||||
this.pageState = COMPLETE;
|
||||
} else {
|
||||
this.pageState = READY;
|
||||
}
|
||||
})
|
||||
.catch(errorMessage => {
|
||||
this.$emit("onError", errorMessage);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<b-card>
|
||||
<div class="mb-1">{{ repo.long_description }}</div>
|
||||
<div class="mb-3">
|
||||
<b-link :href="repo.repository_url" target="_blank">Show additional details and dependencies.</b-link>
|
||||
</div>
|
||||
<div>
|
||||
<span v-if="loading">
|
||||
<span class="fa fa-spinner fa-spin" />
|
||||
Loading repository details...
|
||||
</span>
|
||||
<div v-else>
|
||||
<b-alert v-if="error" variant="danger" show>
|
||||
{{ error }}
|
||||
</b-alert>
|
||||
<div v-else class="border rounded">
|
||||
<b-table borderless :items="repoTable" :fields="repoFields" class="text-center m-0">
|
||||
<template slot="numeric_revision" slot-scope="data">
|
||||
<span class="font-weight-bold">{{ data.value }}</span>
|
||||
</template>
|
||||
<template slot="tools" slot-scope="data">
|
||||
<repositorytools :tools="data.value" />
|
||||
</template>
|
||||
<template slot="profile" slot-scope="data">
|
||||
{{ data.value ? `+${data.value}` : "-" }}
|
||||
</template>
|
||||
<template slot="missing_test_components" slot-scope="data">
|
||||
<span v-if="!data.value" :class="repoChecked" />
|
||||
<span v-else :class="repoUnchecked" />
|
||||
</template>
|
||||
<template slot="actions" slot-scope="row">
|
||||
<installationbutton
|
||||
:installed="row.item.installed"
|
||||
:status="row.item.status"
|
||||
@onInstall="setupRepository(row.item)"
|
||||
@onUninstall="uninstallRepository(row.item)"
|
||||
/>
|
||||
</template>
|
||||
</b-table>
|
||||
<installationsettings
|
||||
v-if="showSettings"
|
||||
:repo="repo"
|
||||
:toolshedUrl="toolshedUrl"
|
||||
:changesetRevision="selectedChangeset"
|
||||
:requiresPanel="selectedRequiresPanel"
|
||||
@hide="onHide"
|
||||
@ok="onOk"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</b-card>
|
||||
</template>
|
||||
<script>
|
||||
import { Services } from "./services.js";
|
||||
import InstallationSettings from "./InstallationSettings.vue";
|
||||
import InstallationButton from "./InstallationButton.vue";
|
||||
import RepositoryTools from "./RepositoryTools.vue";
|
||||
export default {
|
||||
components: {
|
||||
installationsettings: InstallationSettings,
|
||||
installationbutton: InstallationButton,
|
||||
repositorytools: RepositoryTools
|
||||
},
|
||||
props: ["repo", "toolshedUrl"],
|
||||
data() {
|
||||
return {
|
||||
repoChecked: "fa fa-check text-success",
|
||||
repoUnchecked: "fa fa-times text-danger",
|
||||
selectedChangeset: null,
|
||||
selectedRequiresPanel: false,
|
||||
repoTable: [],
|
||||
repoFields: {
|
||||
numeric_revision: {
|
||||
label: "Revision"
|
||||
},
|
||||
tools: {
|
||||
label: "Tools and Versions"
|
||||
},
|
||||
profile: {
|
||||
label: "Requires"
|
||||
},
|
||||
missing_test_components: {
|
||||
label: "Tests"
|
||||
},
|
||||
actions: {
|
||||
label: ""
|
||||
}
|
||||
},
|
||||
showSettings: false,
|
||||
error: null,
|
||||
loading: true,
|
||||
delay: 2000
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.services = new Services();
|
||||
this.loadDetails();
|
||||
},
|
||||
destroyed() {
|
||||
this.clearTimeout();
|
||||
},
|
||||
methods: {
|
||||
clearTimeout() {
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
},
|
||||
loadDetails() {
|
||||
this.services
|
||||
.getDetails(this.toolshedUrl, this.repo.id)
|
||||
.then(response => {
|
||||
this.repoTable = response;
|
||||
this.loadInstalledRepositories();
|
||||
})
|
||||
.catch(error => {
|
||||
this.error = error;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
listenInstalledRepositories() {
|
||||
this.clearTimeout();
|
||||
this.timeout = setTimeout(() => {
|
||||
this.loadInstalledRepositories();
|
||||
}, this.delay);
|
||||
},
|
||||
loadInstalledRepositories() {
|
||||
this.services
|
||||
.getInstalledRepositories(this.repo)
|
||||
.then(revisions => {
|
||||
let changed = false;
|
||||
this.repoTable.forEach(x => {
|
||||
const revision = revisions[x.changeset_revision];
|
||||
if (revision && revision.status !== x.status) {
|
||||
x.status = revision.status;
|
||||
x.installed = revision.installed;
|
||||
changed = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (changed) {
|
||||
this.repoTable = [...this.repoTable];
|
||||
}
|
||||
this.listenInstalledRepositories();
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(error => {
|
||||
this.error = error;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
onOk: function() {
|
||||
this.showSettings = false;
|
||||
},
|
||||
onHide: function() {
|
||||
this.showSettings = false;
|
||||
},
|
||||
setupRepository: function(details) {
|
||||
this.selectedChangeset = details.changeset_revision;
|
||||
this.selectedRequiresPanel = details.includes_tools_for_display_in_tool_panel || details.repository.type == "repository_suite_definition";
|
||||
this.showSettings = true;
|
||||
},
|
||||
uninstallRepository: function(details) {
|
||||
this.services
|
||||
.uninstallRepository({
|
||||
tool_shed_url: this.toolshedUrl,
|
||||
name: this.repo.name,
|
||||
owner: this.repo.repo_owner_username,
|
||||
changeset_revision: details.changeset_revision
|
||||
})
|
||||
.catch(error => {
|
||||
this.error = error;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<table v-if="tools" class="table table-borderless">
|
||||
<tbody>
|
||||
<tr v-if="canExpand && expanded" class="bg-transparent">
|
||||
<td :class="clsFirstColumn">
|
||||
<a href="#" @click.stop.prevent="onExpand">
|
||||
<span class="fa fa-angle-double-up" />
|
||||
<span>Show less</span>
|
||||
</a>
|
||||
</td>
|
||||
<td :class="clsSecondColumn" />
|
||||
</tr>
|
||||
<tr v-for="tool in visibleTools" :key="tool.guid" :class="clsRow">
|
||||
<td :class="clsFirstColumn">
|
||||
{{ tool.id }}
|
||||
</td>
|
||||
<td :class="clsSecondColumn">
|
||||
{{ tool.version }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="canExpand && !expanded" class="bg-transparent">
|
||||
<td :class="clsFirstColumn">
|
||||
<a href="#" @click.stop.prevent="onExpand">
|
||||
<span class="fa fa-angle-double-down" />
|
||||
<span>Show more</span>
|
||||
</a>
|
||||
</td>
|
||||
<td :class="clsSecondColumn" />
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ["tools"],
|
||||
data() {
|
||||
return {
|
||||
clsExpanded: "bg-transparent border-bottom",
|
||||
clsCollapsed: "bg-transparent",
|
||||
clsFirstColumn: "p-0 w-50 text-left",
|
||||
clsSecondColumn: "p-0 w-50 text-center",
|
||||
expanded: false,
|
||||
preview: 2
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
clsRow() {
|
||||
return this.expanded ? this.clsExpanded : this.clsCollapsed;
|
||||
},
|
||||
canExpand() {
|
||||
return this.tools && this.tools.length > this.preview;
|
||||
},
|
||||
visibleTools() {
|
||||
if (this.canExpand && !this.expanded) {
|
||||
return this.tools.slice(0, this.preview);
|
||||
}
|
||||
return this.tools;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onExpand() {
|
||||
this.expanded = !this.expanded;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div v-if="!loading" class="m-1 text-muted">
|
||||
{{ total }} repositories available at
|
||||
<span v-if="showDropdown" class="dropdown">
|
||||
<b-link id="dropdownToolshedUrl" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{{ toolshedUrl }}
|
||||
</b-link>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownToolshedUrl">
|
||||
<a
|
||||
v-for="url in toolshedUrls"
|
||||
:key="url"
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
@click.prevent="onToolshed(url)"
|
||||
>{{ url }}</a
|
||||
>
|
||||
</div>
|
||||
</span>
|
||||
<span v-else>
|
||||
<b-link :href="toolshedUrl" target="_blank">
|
||||
{{ toolshedUrl }}
|
||||
</b-link>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ["toolshedUrl", "toolshedUrls", "loading", "total"],
|
||||
computed: {
|
||||
showDropdown() {
|
||||
return this.toolshedUrls.length > 1;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onToolshed(url) {
|
||||
this.$emit("onToolshed", url);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,110 @@
|
||||
import axios from "axios";
|
||||
import { getAppRoot } from "onload/loadConfig";
|
||||
|
||||
/** Request repositories, categories etc from toolshed server **/
|
||||
export class Services {
|
||||
async getCategories(toolshedUrl) {
|
||||
const paramString = `tool_shed_url=${toolshedUrl}&controller=categories`;
|
||||
const url = `${getAppRoot()}api/tool_shed/request?${paramString}`;
|
||||
try {
|
||||
const response = await axios.get(url);
|
||||
return response.data;
|
||||
} catch (e) {
|
||||
return this._errorMessage(e);
|
||||
}
|
||||
}
|
||||
async getRepositories(params) {
|
||||
params["controller"] = "repositories";
|
||||
const paramString = this._getParamString(params);
|
||||
const url = `${getAppRoot()}api/tool_shed/request?${paramString}`;
|
||||
try {
|
||||
const response = await axios.get(url);
|
||||
const data = response.data;
|
||||
const incoming = data.hits.map(x => x.repository);
|
||||
incoming.forEach(x => {
|
||||
x.times_downloaded = this._formatCount(x.times_downloaded);
|
||||
x.repository_url = `${data.hostname}repository?repository_id=${x.id}`;
|
||||
});
|
||||
return incoming;
|
||||
} catch (e) {
|
||||
return this._errorMessage(e);
|
||||
}
|
||||
}
|
||||
async getDetails(toolshedUrl, repository_id) {
|
||||
const paramString = `tool_shed_url=${toolshedUrl}&id=${repository_id}&controller=repositories&action=metadata`;
|
||||
const url = `${getAppRoot()}api/tool_shed/request?${paramString}`;
|
||||
try {
|
||||
const response = await axios.get(url);
|
||||
const data = response.data;
|
||||
const table = Object.keys(data).map(key => data[key]);
|
||||
table.sort((a, b) => b.numeric_revision - a.numeric_revision);
|
||||
table.forEach(x => {
|
||||
if (Array.isArray(x.tools)) {
|
||||
x.profile = x.tools.reduce(
|
||||
(value, current) => (current.profile > value ? current.profile : value),
|
||||
null
|
||||
);
|
||||
}
|
||||
});
|
||||
return table;
|
||||
} catch (e) {
|
||||
return `${this._errorMessage(e)}, ${url}`;
|
||||
}
|
||||
}
|
||||
async getInstalledRepositories(repo) {
|
||||
const paramsString = `name=${repo.name}&owner=${repo.repo_owner_username}`;
|
||||
const url = `${getAppRoot()}api/tool_shed_repositories?${paramsString}`;
|
||||
try {
|
||||
const response = await axios.get(url);
|
||||
const data = response.data;
|
||||
const result = {};
|
||||
data.forEach(x => {
|
||||
const d = {
|
||||
status: x.status,
|
||||
installed: !x.deleted && !x.uninstalled
|
||||
};
|
||||
result[x.changeset_revision] = result[x.installed_changeset_revision] = d;
|
||||
});
|
||||
return result;
|
||||
} catch (e) {
|
||||
this._errorMessage(e);
|
||||
}
|
||||
}
|
||||
async installRepository(payload) {
|
||||
const url = `${getAppRoot()}api/tool_shed_repositories`;
|
||||
try {
|
||||
const response = await axios.post(url, payload);
|
||||
return response.data;
|
||||
} catch (e) {
|
||||
return this._errorMessage(e);
|
||||
}
|
||||
}
|
||||
async uninstallRepository(params) {
|
||||
const paramsString = Object.keys(params).reduce(function(previous, key) {
|
||||
return `${previous}${key}=${params[key]}&`;
|
||||
}, "");
|
||||
const url = `${getAppRoot()}api/tool_shed_repositories?${paramsString}`;
|
||||
try {
|
||||
const response = await axios.delete(url);
|
||||
return response.data;
|
||||
} catch (e) {
|
||||
return this._errorMessage(e);
|
||||
}
|
||||
}
|
||||
_formatCount(value) {
|
||||
if (value > 1000) return `>${Math.floor(value / 1000)}k`;
|
||||
return value;
|
||||
}
|
||||
_errorMessage(e) {
|
||||
let message = "Request failed.";
|
||||
if (e.response) {
|
||||
message = e.response.data.err_msg || `${e.response.statusText} (${e.response.status})`;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
_getParamString(params) {
|
||||
return Object.keys(params).reduce(function(previous, key) {
|
||||
return `${previous}${key}=${params[key]}&`;
|
||||
}, "");
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import DataManagerRouter from "components/admin/DataManager/DataManagerRouter.vu
|
||||
import Register from "components/login/Register.vue";
|
||||
import ErrorStack from "components/admin/ErrorStack.vue";
|
||||
import DisplayApplications from "components/admin/DisplayApplications.vue";
|
||||
import Toolshed from "components/Toolshed/Index.vue";
|
||||
import Vue from "vue";
|
||||
|
||||
export const getAdminRouter = (Galaxy, options) => {
|
||||
@@ -25,6 +26,7 @@ export const getAdminRouter = (Galaxy, options) => {
|
||||
"(/)admin(/)users(/)create": "show_users_create",
|
||||
"(/)admin(/)roles": "show_roles",
|
||||
"(/)admin(/)groups": "show_groups",
|
||||
"(/)admin(/)toolshed": "show_toolshed",
|
||||
"(/)admin(/)error_stack": "show_error_stack",
|
||||
"(/)admin(/)display_applications": "show_display_applications",
|
||||
"(/)admin(/)tool_versions": "show_tool_versions",
|
||||
@@ -84,6 +86,10 @@ export const getAdminRouter = (Galaxy, options) => {
|
||||
this._show_grid_view("admin_toolshed/browse_repositories");
|
||||
},
|
||||
|
||||
show_toolshed: function() {
|
||||
this._display_vue_helper(Toolshed);
|
||||
},
|
||||
|
||||
show_tool_versions: function() {
|
||||
this._show_grid_view("admin/tool_versions_list");
|
||||
},
|
||||
|
||||
@@ -88,7 +88,13 @@ const AdminPanel = Backbone.View.extend({
|
||||
title: _l("Tool Management"),
|
||||
items: [
|
||||
{
|
||||
title: _l("Install new tools"),
|
||||
title: _l("Install or Uninstall"),
|
||||
url: "admin/toolshed",
|
||||
target: "__use_router__",
|
||||
enabled: this.settings.is_tool_shed_installed
|
||||
},
|
||||
{
|
||||
title: _l("Install new tools (Legacy)"),
|
||||
url: "admin_toolshed/browse_tool_sheds",
|
||||
enabled: this.settings.is_tool_shed_installed
|
||||
},
|
||||
|
||||
@@ -113,36 +113,36 @@ const SidePanel = Backbone.View.extend({
|
||||
},
|
||||
|
||||
show: function() {
|
||||
if (!this.hidden) {
|
||||
return;
|
||||
if (this.hidden && !this.motionQueue) {
|
||||
this.motionQueue = 2;
|
||||
const animation = {};
|
||||
const whichSide = this.id;
|
||||
animation[whichSide] = 0;
|
||||
this.$el
|
||||
.css(whichSide, -this.saved_size)
|
||||
.css("width", this.saved_size)
|
||||
.animate(animation, "fast", () => this.motionQueue--);
|
||||
animation[whichSide] = this.saved_size;
|
||||
this.$center().animate(animation, "fast", () => this.motionQueue--);
|
||||
this.hidden = false;
|
||||
this.$toggleButton().removeClass("hidden");
|
||||
}
|
||||
const self = this;
|
||||
const animation = {};
|
||||
const whichSide = this.id;
|
||||
animation[whichSide] = 0;
|
||||
self.$el
|
||||
.css(whichSide, -this.saved_size)
|
||||
.show()
|
||||
.animate(animation, "fast", () => {
|
||||
self.resize(self.saved_size);
|
||||
});
|
||||
self.hidden = false;
|
||||
self.$toggleButton().removeClass("hidden");
|
||||
return this;
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
if (this.hidden) {
|
||||
return;
|
||||
if (!this.hidden && !this.motionQueue) {
|
||||
this.motionQueue = 2;
|
||||
const animation = {};
|
||||
const whichSide = this.id;
|
||||
this.saved_size = this.$el.width();
|
||||
animation[whichSide] = -this.saved_size;
|
||||
this.$el.animate(animation, "fast", () => this.motionQueue--);
|
||||
animation[whichSide] = 0;
|
||||
this.$center().animate(animation, "fast", () => this.motionQueue--);
|
||||
this.hidden = true;
|
||||
this.$toggleButton().addClass("hidden");
|
||||
}
|
||||
const animation = {};
|
||||
const whichSide = this.id;
|
||||
this.saved_size = this.$el.width();
|
||||
animation[whichSide] = -this.saved_size;
|
||||
this.$el.animate(animation, "fast");
|
||||
this.$center().css(whichSide, 0);
|
||||
this.hidden = true;
|
||||
this.$toggleButton().addClass("hidden");
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
@@ -278,7 +278,7 @@ function _makeSection(output_id, label, options) {
|
||||
options: extensions,
|
||||
help: "This action will change the datatype of the output to the indicated datatype.",
|
||||
onchange: function(new_value) {
|
||||
if (new_value === '__empty__') {
|
||||
if (new_value === "__empty__") {
|
||||
new_value = null;
|
||||
}
|
||||
workflow.updateDatatype(node, output_id, new_value);
|
||||
|
||||
@@ -66,13 +66,13 @@ var Node = Backbone.Model.extend({
|
||||
output_terminal.force_datatype = datatype;
|
||||
output.force_datatype = datatype;
|
||||
if (datatype) {
|
||||
this.post_job_actions['ChangeDatatypeAction' + outputName] = {
|
||||
action_arguments: {newtype: datatype},
|
||||
this.post_job_actions["ChangeDatatypeAction" + outputName] = {
|
||||
action_arguments: { newtype: datatype },
|
||||
action_type: "ChangeDatatypeAction",
|
||||
output_name: outputName,
|
||||
output_name: outputName
|
||||
};
|
||||
} else {
|
||||
delete this.post_job_actions['ChangeDatatypeAction' + outputName];
|
||||
delete this.post_job_actions["ChangeDatatypeAction" + outputName];
|
||||
}
|
||||
this.markChanged();
|
||||
output_terminal.destroyInvalidConnections();
|
||||
|
||||
@@ -94,8 +94,8 @@ export default Backbone.View.extend({
|
||||
const terminalView = new terminalViewClass({
|
||||
node: this.node,
|
||||
output: output
|
||||
})
|
||||
return terminalView
|
||||
});
|
||||
return terminalView;
|
||||
},
|
||||
|
||||
outputViewforOutput: function(output, terminalView) {
|
||||
@@ -105,7 +105,7 @@ export default Backbone.View.extend({
|
||||
terminalElement: terminalView.el,
|
||||
nodeView: this
|
||||
});
|
||||
return outputView
|
||||
return outputView;
|
||||
},
|
||||
|
||||
addDataOutput: function(output) {
|
||||
|
||||
@@ -292,7 +292,7 @@ var OutputTerminalView = BaseOutputTerminalView.extend({
|
||||
var terminal = new Terminals.OutputTerminal({
|
||||
element: this.el,
|
||||
datatypes: type,
|
||||
force_datatype: output.force_datatype,
|
||||
force_datatype: output.force_datatype
|
||||
});
|
||||
return terminal;
|
||||
}
|
||||
@@ -309,7 +309,7 @@ var OutputCollectionTerminalView = BaseOutputTerminalView.extend({
|
||||
collection_type: collection_type,
|
||||
collection_type_source: collection_type_source,
|
||||
datatypes: output.extensions,
|
||||
force_datatype: output.force_datatype,
|
||||
force_datatype: output.force_datatype
|
||||
});
|
||||
return terminal;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ QUnit.module("Input terminal model test", {
|
||||
};
|
||||
}
|
||||
return this.input_terminal.canAccept(other).canAccept;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test("test update", function(assert) {
|
||||
@@ -136,12 +136,12 @@ QUnit.test("cannot accept incorrect datatype", function(assert) {
|
||||
});
|
||||
|
||||
QUnit.test("can accept incorrect datatype if converted with PJA", function(assert) {
|
||||
var other = { node: {}, datatypes: ["binary"], force_datatype: 'txt', name: "out1" }; // Was binary but converted to txt
|
||||
var other = { node: {}, datatypes: ["binary"], force_datatype: "txt", name: "out1" }; // Was binary but converted to txt
|
||||
assert.ok(this.test_accept(other));
|
||||
});
|
||||
|
||||
QUnit.test("cannot accept incorrect datatype if converted with PJA to incompatible type", function(assert) {
|
||||
var other = { node: {}, datatypes: ["binary"], force_datatype: 'bam', name: "out1" };
|
||||
var other = { node: {}, datatypes: ["binary"], force_datatype: "bam", name: "out1" };
|
||||
assert.ok(!this.test_accept(other));
|
||||
});
|
||||
|
||||
|
||||
@@ -140,7 +140,6 @@ body {
|
||||
}
|
||||
|
||||
// Panels
|
||||
|
||||
#left,
|
||||
#center,
|
||||
#right {
|
||||
@@ -148,19 +147,22 @@ body {
|
||||
top: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
background: white;
|
||||
}
|
||||
#left {
|
||||
left: 0px;
|
||||
width: $panel-width;
|
||||
z-index: 200;
|
||||
border-right: $layout-border;
|
||||
}
|
||||
#right {
|
||||
right: 0px;
|
||||
width: $panel-width;
|
||||
border-left: $layout-border;
|
||||
}
|
||||
#center {
|
||||
left: $panel-width;
|
||||
right: $panel-width;
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
.center-container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
@@ -189,21 +191,6 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
#right {
|
||||
width: $panel-width;
|
||||
right: 0px;
|
||||
z-index: 200;
|
||||
border-left: $layout-border;
|
||||
}
|
||||
|
||||
#left,
|
||||
#right,
|
||||
.unified-panel {
|
||||
background: $panel-bg-color;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#left,
|
||||
#right,
|
||||
.unified-panel {
|
||||
@@ -216,7 +203,6 @@ body {
|
||||
@extend .unselectable;
|
||||
@extend .mx-3;
|
||||
height: $panel_header_height;
|
||||
z-index: 1000;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
@@ -255,7 +241,6 @@ body {
|
||||
height: $panel_footer_height;
|
||||
line-height: $panel_footer_height;
|
||||
width: 100%;
|
||||
z-index: 1000; // Above #dd-helper
|
||||
border-top: $layout-border;
|
||||
background: $panel-footer-bg-color;
|
||||
color: $panel-header-text-color;
|
||||
@@ -285,42 +270,48 @@ body {
|
||||
|
||||
// Needs to be outside panel to show when hidden
|
||||
.panel-collapse {
|
||||
@extend .unified-panel-footer;
|
||||
font-size: 4/3em;
|
||||
@extend .fa-icon;
|
||||
&:before {
|
||||
content: "\f053";
|
||||
}
|
||||
&.hidden:before {
|
||||
content: "\f054";
|
||||
}
|
||||
z-index: 201;
|
||||
$border-color: darken($panel-footer-bg-color, 20%);
|
||||
font-size: 4/3em;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: inherit;
|
||||
bottom: 0;
|
||||
padding: 0 5px;
|
||||
text-align: center;
|
||||
height: $panel_footer_height;
|
||||
line-height: $panel_footer_height;
|
||||
width: $panel_footer_height - 5;
|
||||
background: none;
|
||||
border-right: $layout-border;
|
||||
border-top: $layout-border;
|
||||
width: $panel_footer_height;
|
||||
background: $panel-footer-bg-color;
|
||||
border: solid $panel-footer-bg-color 1px;
|
||||
z-index: 1;
|
||||
&.right {
|
||||
left: inherit;
|
||||
right: 0;
|
||||
border-right: none;
|
||||
border-left: $layout_border;
|
||||
&.right:before {
|
||||
border-top-left-radius: $border-radius-base;
|
||||
line-height: inherit;
|
||||
&:before {
|
||||
content: "\f054";
|
||||
}
|
||||
&.right.hidden:before {
|
||||
&.hidden:before {
|
||||
content: "\f053";
|
||||
}
|
||||
&.hidden {
|
||||
border-top-color: $border-color;
|
||||
border-left-color: $border-color;
|
||||
}
|
||||
}
|
||||
&.left {
|
||||
left: 0;
|
||||
border-top-right-radius: $border-radius-base;
|
||||
line-height: inherit;
|
||||
&:before {
|
||||
content: "\f053";
|
||||
}
|
||||
&.hidden:before {
|
||||
content: "\f054";
|
||||
}
|
||||
&.hidden {
|
||||
border-top-color: $border-color;
|
||||
border-right-color: $border-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ from galaxy.job_execution import output_collect
|
||||
from galaxy.managers.jobs import JobSearch
|
||||
from galaxy.metadata import get_metadata_compute_strategy
|
||||
from galaxy.model.tags import GalaxyTagHandler
|
||||
from galaxy.queue_worker import send_control_task
|
||||
from galaxy.tool_util.deps import (
|
||||
CachedDependencyManager,
|
||||
)
|
||||
@@ -242,16 +241,6 @@ class ToolBox(BaseGalaxyToolBox):
|
||||
app=app,
|
||||
)
|
||||
|
||||
def handle_panel_update(self, section_dict):
|
||||
"""
|
||||
Sends a panel update to all threads/processes.
|
||||
"""
|
||||
send_control_task(self.app, 'create_panel_section', kwargs=section_dict)
|
||||
# The following local call to self.create_section should be unnecessary
|
||||
# but occasionally the local ToolPanelElements instance appears to not
|
||||
# get updated.
|
||||
self.create_section(section_dict)
|
||||
|
||||
def has_reloaded(self, other_toolbox):
|
||||
return self._reload_count != other_toolbox._reload_count
|
||||
|
||||
|
||||
@@ -98,13 +98,6 @@ class AbstractToolBox(Dictifiable, ManagesIntegratedToolPanelMixin):
|
||||
self._load_tool_panel()
|
||||
self._save_integrated_tool_panel()
|
||||
|
||||
def handle_panel_update(self, section_dict):
|
||||
"""Extension-point for Galaxy-app specific reload logic.
|
||||
|
||||
This abstract representation of the toolbox shouldn't have details about
|
||||
interacting with the rest of the Galaxy app or message queues, etc....
|
||||
"""
|
||||
|
||||
def create_tool(self, config_file, tool_shed_repository=None, guid=None, **kwds):
|
||||
raise NotImplementedError()
|
||||
|
||||
@@ -264,7 +257,7 @@ class AbstractToolBox(Dictifiable, ManagesIntegratedToolPanelMixin):
|
||||
'id': section_id,
|
||||
'version': '',
|
||||
}
|
||||
self.handle_panel_update(section_dict)
|
||||
self.create_section(section_dict)
|
||||
tool_section = self._tool_panel[tool_panel_section_key]
|
||||
self._save_integrated_tool_panel()
|
||||
else:
|
||||
|
||||
@@ -306,7 +306,9 @@ class JSAppLauncher(BaseUIController):
|
||||
'toolbox' : trans.app.toolbox.to_dict(trans, in_panel=False),
|
||||
'toolbox_in_panel' : trans.app.toolbox.to_dict(trans),
|
||||
'message_box_visible' : trans.app.config.message_box_visible,
|
||||
'show_inactivity_warning' : trans.app.config.user_activation_on and trans.user and not trans.user.active
|
||||
'show_inactivity_warning' : trans.app.config.user_activation_on and trans.user and not trans.user.active,
|
||||
'tool_shed_urls' : list(trans.app.tool_shed_registry.tool_sheds.values()) if trans.app.tool_shed_registry else [],
|
||||
'tool_dynamic_configs' : list(trans.app.toolbox.dynamic_conf_filenames())
|
||||
}
|
||||
|
||||
# TODO: move to user
|
||||
|
||||
@@ -12,6 +12,7 @@ from galaxy import (
|
||||
util,
|
||||
web
|
||||
)
|
||||
from galaxy.exceptions import MessageException
|
||||
from galaxy.web import expose_api
|
||||
from galaxy.web.base.controller import BaseAPIController
|
||||
from tool_shed.util import (
|
||||
@@ -314,3 +315,26 @@ class ToolShedController(BaseAPIController):
|
||||
return {}
|
||||
response = json.loads(util.url_get(tool_shed_url, params=dict(q=q), pathspec=['api', 'repositories']))
|
||||
return response
|
||||
|
||||
@expose_api
|
||||
@web.require_admin
|
||||
def request(self, trans, **params):
|
||||
"""
|
||||
GET /api/tool_shed/request
|
||||
"""
|
||||
tool_shed_url = params.pop("tool_shed_url")
|
||||
controller = params.pop("controller")
|
||||
if controller is None:
|
||||
raise MessageException("Please provide a toolshed controller name.")
|
||||
tool_shed_registry = trans.app.tool_shed_registry
|
||||
if tool_shed_registry is None:
|
||||
raise MessageException("Toolshed registry not available.")
|
||||
if tool_shed_url in tool_shed_registry.tool_sheds.values():
|
||||
pathspec = ["api", controller]
|
||||
if "id" in params:
|
||||
pathspec.append(params.pop("id"))
|
||||
if "action" in params:
|
||||
pathspec.append(params.pop("action"))
|
||||
return json.loads(util.url_get(tool_shed_url, params=dict(params), pathspec=pathspec))
|
||||
else:
|
||||
raise MessageException("Invalid toolshed url.")
|
||||
|
||||
@@ -112,6 +112,7 @@ def app_factory(global_conf, load_app_kwds={}, **kwargs):
|
||||
webapp.add_client_route('/admin/groups', 'admin')
|
||||
webapp.add_client_route('/admin/repositories', 'admin')
|
||||
webapp.add_client_route('/admin/tool_versions', 'admin')
|
||||
webapp.add_client_route('/admin/toolshed', 'admin')
|
||||
webapp.add_client_route('/admin/quotas', 'admin')
|
||||
webapp.add_client_route('/admin/form/{form_id}', 'admin')
|
||||
webapp.add_client_route('/admin/api_keys', 'admin')
|
||||
@@ -960,6 +961,12 @@ def populate_api_routes(webapp, app):
|
||||
action='search',
|
||||
conditions=dict(method=["GET", "POST"]))
|
||||
|
||||
webapp.mapper.connect('tool_shed_request',
|
||||
'/api/tool_shed/request',
|
||||
controller='toolshed',
|
||||
action='request',
|
||||
conditions=dict(method=["GET"]))
|
||||
|
||||
webapp.mapper.connect('tool_shed_status',
|
||||
'/api/tool_shed/status',
|
||||
controller='toolshed',
|
||||
|
||||
@@ -195,7 +195,7 @@
|
||||
<div id="left">
|
||||
${self.left_panel()}
|
||||
<div class="unified-panel-footer">
|
||||
<div id="left-panel-collapse" class="panel-collapse"></div>
|
||||
<div id="left-panel-collapse" class="panel-collapse left"></div>
|
||||
<div id="left-panel-drag" class="drag"></div>
|
||||
</div>
|
||||
</div><!--end left-->
|
||||
|
||||
@@ -57,6 +57,9 @@
|
||||
${parent.stylesheets()}
|
||||
|
||||
<style type="text/css">
|
||||
#center {
|
||||
z-index: 0;
|
||||
}
|
||||
canvas { position: absolute; z-index: 10; }
|
||||
canvas.dragging { position: absolute; z-index: 1000; }
|
||||
</style>
|
||||
|
||||
@@ -562,9 +562,6 @@ class SimplifiedToolBox(ToolBox):
|
||||
# Need to start thread now for new reload callback to take effect
|
||||
self.app.watchers.start()
|
||||
|
||||
def handle_panel_update(self, section_dict):
|
||||
self.create_section(section_dict)
|
||||
|
||||
|
||||
def reload_callback(test_case):
|
||||
test_case.app.tool_cache.cleanup()
|
||||
|
||||
Reference in New Issue
Block a user