mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-10-29 17:42:12 +08:00
Merge pull request #14630 from guerler/remove_display_structured
Remove outdated display structured history view
This commit is contained in:
@@ -1,164 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- eslint-disable-next-line vue/require-v-for-key -->
|
||||
<div v-for="error in errorMessages">
|
||||
<div class="alert alert-danger" role="alert">{{ error }}</div>
|
||||
</div>
|
||||
<div v-html="historyTemplate"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import $ from "jquery";
|
||||
import { getGalaxyInstance } from "app";
|
||||
import { getAppRoot } from "onload/loadConfig";
|
||||
import axios from "axios";
|
||||
import HDAModel from "mvc/history/hda-model";
|
||||
import HDAListItemEdit from "mvc/history/hda-li-edit";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
historyTemplate: "",
|
||||
historyJSON: {},
|
||||
// TODO: Error message standardization -- use bootstrap-vue component or the like.
|
||||
errorMessages: [],
|
||||
};
|
||||
},
|
||||
created: function () {
|
||||
const historyId = this.id;
|
||||
let url = "";
|
||||
if (historyId !== undefined && historyId !== "" && historyId !== null) {
|
||||
url = getAppRoot() + "history/display_structured?id=" + historyId;
|
||||
} else {
|
||||
url = getAppRoot() + "history/display_structured";
|
||||
}
|
||||
this.ajaxCall(url);
|
||||
},
|
||||
updated: function () {
|
||||
this.makeHistoryView(this.historyJSON);
|
||||
},
|
||||
methods: {
|
||||
ajaxCall: function (url) {
|
||||
axios
|
||||
.get(url)
|
||||
.then((response) => {
|
||||
this._updateHistoryData(response);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
this.errorMessages.push(
|
||||
"Error fetching history data -- reload the page to retry this request. Please contact an administrator if the problem persists."
|
||||
);
|
||||
});
|
||||
},
|
||||
_updateHistoryData: function (response) {
|
||||
const historyItems = response.data;
|
||||
this.historyTemplate = historyItems.template;
|
||||
this.historyJSON = historyItems.history_json;
|
||||
},
|
||||
makeHistoryView: function (historyDict) {
|
||||
window.hdas = historyDict.map((hda) => {
|
||||
const Galaxy = getGalaxyInstance();
|
||||
return new HDAListItemEdit.HDAListItemEdit({
|
||||
model: new HDAModel.HistoryDatasetAssociation(hda),
|
||||
el: $("#hda-" + hda.id),
|
||||
linkTarget: "galaxy_main",
|
||||
purgeAllowed: Galaxy.config.allow_user_dataset_purge,
|
||||
logger: Galaxy.logger,
|
||||
}).render(0);
|
||||
});
|
||||
// toggle the body section of each item in the structure
|
||||
$(function () {
|
||||
$(".workflow, .tool").each((index, element) => {
|
||||
const body = $(element).children(".body");
|
||||
$(element)
|
||||
.children(".header")
|
||||
.click((e) => {
|
||||
body.toggle();
|
||||
})
|
||||
.addClass("clickable");
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.light {
|
||||
font-weight: lighter;
|
||||
color: grey;
|
||||
}
|
||||
.right-aligned {
|
||||
text-align: right;
|
||||
}
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.workflow {
|
||||
border: solid gray 1px;
|
||||
margin-bottom: 1%;
|
||||
}
|
||||
.workflow > .header {
|
||||
background: lightgray;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
.workflow > .light {
|
||||
color: gray;
|
||||
}
|
||||
.workflow > .body {
|
||||
border-top: solid gray 1px;
|
||||
}
|
||||
.workflow > .body > .tool {
|
||||
border: 0px;
|
||||
margin: 0;
|
||||
}
|
||||
div.tool {
|
||||
margin-bottom: 5px;
|
||||
border: 1px solid gray;
|
||||
}
|
||||
.tool > .header {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
.job-inputs {
|
||||
margin: 0px 6px 0px 6px;
|
||||
text-align: left;
|
||||
}
|
||||
.job-inputs td:nth-child(1) {
|
||||
text-align: right;
|
||||
font-weight: lighter;
|
||||
color: gray;
|
||||
}
|
||||
.job-inputs td:nth-child(1):after {
|
||||
content: ":";
|
||||
}
|
||||
.job-inputs td:nth-child(2) {
|
||||
padding-left: 4px;
|
||||
}
|
||||
.job-inputs-show {
|
||||
float: right;
|
||||
}
|
||||
.copied-from {
|
||||
border: 1px solid lightgrey;
|
||||
border-width: 1px 1px 0px 1px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.copied-from .header {
|
||||
border-bottom: 1px solid lightgrey;
|
||||
padding: 5px;
|
||||
}
|
||||
.copied-from .header .bold,
|
||||
.copied-from .header a {
|
||||
color: #888;
|
||||
}
|
||||
</style>
|
||||
@@ -64,14 +64,6 @@
|
||||
<span v-localize>Resume Paused Jobs</span>
|
||||
</b-dropdown-item>
|
||||
|
||||
<b-dropdown-item
|
||||
data-description="show structure"
|
||||
:title="l('Show Detailed Structure View of History')"
|
||||
@click="$router.push('/histories/show_structure')">
|
||||
<Icon fixed-width icon="code-branch" class="mr-1" />
|
||||
<span v-localize>Show Structure</span>
|
||||
</b-dropdown-item>
|
||||
|
||||
<b-dropdown-divider></b-dropdown-divider>
|
||||
|
||||
<b-dropdown-item
|
||||
@@ -136,16 +128,6 @@
|
||||
<Icon fixed-width icon="lock" class="mr-1" />
|
||||
<span v-localize>Make Private</span>
|
||||
</b-dropdown-item>
|
||||
|
||||
<b-dropdown-divider></b-dropdown-divider>
|
||||
|
||||
<b-dropdown-item
|
||||
data-description="switch to legacy history view"
|
||||
:title="l('Switch to Legacy History Panel')"
|
||||
@click="switchToLegacyHistoryPanel">
|
||||
<Icon fixed-width class="mr-1" icon="arrow-up" />
|
||||
<span v-localize>Return to legacy panel</span>
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
</b-button-group>
|
||||
</nav>
|
||||
@@ -186,7 +168,6 @@
|
||||
|
||||
<script>
|
||||
import { legacyNavigationMixin } from "components/plugins/legacyNavigation";
|
||||
import { switchToLegacyHistoryPanel } from "components/History/adapters/betaToggle";
|
||||
import CopyModal from "components/History/Modals/CopyModal";
|
||||
import SelectorModal from "components/History/Modals/SelectorModal";
|
||||
import { mapGetters } from "vuex";
|
||||
@@ -207,7 +188,6 @@ export default {
|
||||
...mapGetters("user", ["currentUser"]),
|
||||
},
|
||||
methods: {
|
||||
switchToLegacyHistoryPanel,
|
||||
userTitle(title) {
|
||||
if (this.currentUser.isAnonymous) {
|
||||
return this.l("Log in to") + " " + this.l(title);
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
const USE_LEGACY_HISTORY_STORAGE_KEY = "useLegacyHistory";
|
||||
|
||||
export const shouldUseLegacyHistory = (instanceDefaultUseLegacyHistory) => {
|
||||
// If there's a value set, respect it. Otherwise get instance default from config.
|
||||
const userPrefLegacyHistory = sessionStorage.getItem(USE_LEGACY_HISTORY_STORAGE_KEY);
|
||||
if (userPrefLegacyHistory != null) {
|
||||
return userPrefLegacyHistory === "1";
|
||||
} else {
|
||||
return instanceDefaultUseLegacyHistory;
|
||||
}
|
||||
};
|
||||
|
||||
export const switchToLegacyHistoryPanel = () => {
|
||||
sessionStorage.setItem(USE_LEGACY_HISTORY_STORAGE_KEY, 1);
|
||||
location.reload();
|
||||
};
|
||||
|
||||
export const switchToBetaHistoryPanel = () => {
|
||||
sessionStorage.setItem(USE_LEGACY_HISTORY_STORAGE_KEY, 0);
|
||||
location.reload();
|
||||
};
|
||||
@@ -23,7 +23,6 @@ import DatasetDetails from "components/DatasetInformation/DatasetDetails";
|
||||
import DatasetError from "components/DatasetInformation/DatasetError";
|
||||
import DatasetList from "components/Dataset/DatasetList";
|
||||
import AvailableDatatypes from "components/AvailableDatatypes/AvailableDatatypes";
|
||||
import DisplayStructured from "components/DisplayStructured";
|
||||
import FormGeneric from "components/Form/FormGeneric";
|
||||
import Grid from "components/Grid/Grid";
|
||||
import GridShared from "components/Grid/GridShared";
|
||||
@@ -196,13 +195,6 @@ export function getRouter(Galaxy) {
|
||||
component: HistoryMultipleView,
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: "histories/show_structure",
|
||||
component: DisplayStructured,
|
||||
props: (route) => ({
|
||||
id: route.query.id,
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "histories/:historyId/export",
|
||||
component: HistoryExport,
|
||||
|
||||
@@ -6,7 +6,6 @@ import _l from "utils/localization";
|
||||
import PopupMenu from "mvc/ui/popup-menu";
|
||||
import historyCopyDialog from "mvc/history/copy-dialog";
|
||||
import Webhooks from "mvc/webhooks";
|
||||
import { switchToBetaHistoryPanel } from "../../components/History/adapters/betaToggle";
|
||||
|
||||
// ============================================================================
|
||||
var menu = [
|
||||
@@ -164,13 +163,6 @@ var menu = [
|
||||
anon: false,
|
||||
header: true,
|
||||
},
|
||||
{
|
||||
html: _l("Use Beta History Panel"),
|
||||
anon: false,
|
||||
func: function () {
|
||||
switchToBetaHistoryPanel();
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// Webhooks
|
||||
|
||||
@@ -279,10 +279,6 @@ history_panel:
|
||||
options_menu_item:
|
||||
type: sizzle
|
||||
selector: '.history-options-button-menu > a:contains("${option_label}")'
|
||||
|
||||
options_show_history_structure:
|
||||
type: xpath
|
||||
selector: '//a[contains(text(), "Show Structure")]'
|
||||
options_show_export_history_to_file: 'a[data-description="export to file"]'
|
||||
options_use_beta_history:
|
||||
type: xpath
|
||||
@@ -307,14 +303,6 @@ history_panel:
|
||||
tooltip_name: 'Rename history...'
|
||||
new_name: 'Unnamed history'
|
||||
|
||||
|
||||
history_structure:
|
||||
selectors:
|
||||
_: '.tool'
|
||||
header: '.tool > .header.clickable'
|
||||
dataset: '.tool div.list-item.dataset.history-content'
|
||||
details: '.tool .details'
|
||||
|
||||
edit_dataset_attributes:
|
||||
selectors:
|
||||
database_build_dropdown: '[data-label="Database/Build"]'
|
||||
|
||||
@@ -1668,12 +1668,6 @@ class NavigatesGalaxy(HasDriver):
|
||||
else:
|
||||
self.components.history_panel.multi_view_button.wait_for_and_click()
|
||||
|
||||
def history_panel_show_structure(self):
|
||||
if self.is_beta_history():
|
||||
self.use_bootstrap_dropdown(option="show structure", menu="history options")
|
||||
else:
|
||||
self.click_history_option(self.components.history_panel.options_show_history_structure)
|
||||
|
||||
def history_multi_view_display_collection_contents(self, collection_hid, collection_type="list"):
|
||||
self.open_history_multi_view()
|
||||
|
||||
|
||||
@@ -240,7 +240,6 @@ def app_pair(global_conf, load_app_kwds=None, wsgi_preflight=True, **kwargs):
|
||||
webapp.add_client_route("/histories/permissions")
|
||||
webapp.add_client_route("/histories/view")
|
||||
webapp.add_client_route("/histories/view_multiple")
|
||||
webapp.add_client_route("/histories/show_structure")
|
||||
webapp.add_client_route("/datasets/list")
|
||||
webapp.add_client_route("/datasets/edit")
|
||||
webapp.add_client_route("/datasets/{dataset_id}/error")
|
||||
|
||||
@@ -1,225 +0,0 @@
|
||||
"""
|
||||
Methods to create template for history details recursively.
|
||||
Used in dataset and history controllers
|
||||
"""
|
||||
|
||||
from galaxy.util import listify
|
||||
from galaxy.web import url_for
|
||||
|
||||
|
||||
def render_item(trans, entity, children):
|
||||
"""
|
||||
Form HTML template for each item in the history
|
||||
"""
|
||||
template = ""
|
||||
entity_name = entity.__class__.__name__
|
||||
if entity_name == "HistoryDatasetAssociation":
|
||||
template = render_item_hda(trans, entity, children)
|
||||
elif entity_name == "Job":
|
||||
template = render_item_job(trans, entity, children)
|
||||
elif entity_name == "WorkflowInvocation":
|
||||
template = render_item_wf(trans, entity, children)
|
||||
return template
|
||||
|
||||
|
||||
def render_item_hda(trans, hda, children):
|
||||
"""
|
||||
Render hdas as a id'd stub for js to fill later
|
||||
"""
|
||||
template = ""
|
||||
if hda.copied_from_history_dataset_association:
|
||||
template = render_hda_copied_from_history(trans, hda, children)
|
||||
elif hda.copied_from_library_dataset_dataset_association:
|
||||
template = render_hda_copied_from_library(trans, hda, children)
|
||||
else:
|
||||
template = f'<div id="hda-{trans.security.encode_id(hda.id)}" class="dataset hda state-{hda.state}"></div>'
|
||||
return template
|
||||
|
||||
|
||||
def render_hda_copied_from_history(trans, hda, children):
|
||||
"""
|
||||
Wrap an hda in info about the history from where it was copied
|
||||
"""
|
||||
template = ""
|
||||
id = trans.security.encode_id(hda.id)
|
||||
history_id = trans.security.encode_id(hda.copied_from_history_dataset_association.history_id)
|
||||
url = url_for(f"/histories/view?id={history_id}")
|
||||
template = '<div class="copied-from"><div class="header"><div>'
|
||||
template += '<span class="light"> Copied from history dataset: </span>'
|
||||
template += f'<span class="bold">{hda.copied_from_history_dataset_association.name}</span>'
|
||||
template += '</div><div class="copied-from-source">'
|
||||
template += '<span class="light">History: </span>'
|
||||
template += '<span class="bold">'
|
||||
template += f'<a href="{url}">{hda.copied_from_history_dataset_association.history.name}</a>'
|
||||
template += "</span></div></div>"
|
||||
template += f'<div id="hda-{id}" class="dataset hda state-{hda.state}"></div></div>'
|
||||
return template
|
||||
|
||||
|
||||
def render_hda_copied_from_library(trans, hda, children):
|
||||
"""
|
||||
Wrap an hda in info about the library from where it was copied
|
||||
"""
|
||||
template = ""
|
||||
id = trans.security.encode_id(hda.id)
|
||||
folder = hda.copied_from_library_dataset_dataset_association.library_dataset.folder
|
||||
folder_id = f"F{trans.security.encode_id(folder.id)}"
|
||||
url = url_for(f"/libraries/folders/{folder_id}")
|
||||
template = '<div class="copied-from">'
|
||||
template += '<div class="header">'
|
||||
template += "<div>"
|
||||
template += '<span class="light">Copied from library dataset:</span>'
|
||||
template += f'<span class="bold">{hda.copied_from_library_dataset_dataset_association.name}</span>'
|
||||
template += "</div>"
|
||||
template += '<div class="copied-from-source">'
|
||||
template += '<span class="light">Library: </span>'
|
||||
template += '<span class="bold">'
|
||||
template += f'<a href="{url}">{folder.name}</a></span></div></div>'
|
||||
template += f'<div id="hda-{id}" class="dataset hda state-{hda.state}"></div></div>'
|
||||
return template
|
||||
|
||||
|
||||
def render_item_job(trans, job, children):
|
||||
"""
|
||||
Render a job and its children (hdas)
|
||||
"""
|
||||
template = ""
|
||||
template = '<div class="tool">'
|
||||
tool = trans.app.toolbox.get_tool(job.tool_id, tool_version=job.tool_version)
|
||||
if tool:
|
||||
tool_name = tool.name
|
||||
tool_desc = tool.description
|
||||
else:
|
||||
tool_name = f"Unknown tool with id: {job.tool_id}"
|
||||
tool_desc = ""
|
||||
params_object = None
|
||||
try:
|
||||
params_object = job.get_param_values(trans.app, ignore_errors=True)
|
||||
except Exception:
|
||||
pass
|
||||
template += f'<div class="header"><div><span class="bold">{tool_name}</span>'
|
||||
template += f'<span class="light"> - {tool_desc}</span></div>'
|
||||
if tool and params_object:
|
||||
template += '<table class="job-inputs">'
|
||||
template += inputs_recursive(trans, tool.inputs, params_object, depth=1)
|
||||
template += "</table>"
|
||||
else:
|
||||
template += "<em>No parameter data available</em>"
|
||||
template += "</div>"
|
||||
template += '<div class="body">'
|
||||
child_template = ""
|
||||
for e, c in reversed(children):
|
||||
child_template += render_item(trans, e, c)
|
||||
template += child_template
|
||||
template += "</div></div>"
|
||||
return template
|
||||
|
||||
|
||||
def render_item_wf(trans, wf, children):
|
||||
"""
|
||||
Render a workflow and its children (jobs)
|
||||
"""
|
||||
template = f'<div class="workflow"><div class="header"><span class="bold">{wf.workflow.name}</span>'
|
||||
template += '<span class="light">- Workflow</span></div><div class="body">'
|
||||
for e, c in reversed(children):
|
||||
template += render_item(trans, e, c)
|
||||
template += "</div></div>"
|
||||
return template
|
||||
|
||||
|
||||
def inputs_recursive_indent(text, depth):
|
||||
"""
|
||||
Add an indentation depending on the depth in a <tr>
|
||||
"""
|
||||
return f'<td style="padding-left:{str((depth - 1) * 10)}px">{text}</td>'
|
||||
|
||||
|
||||
def inputs_recursive(trans, input_params, param_values, depth=1, upgrade_messages=None):
|
||||
"""
|
||||
Recursive method for tool parameter section
|
||||
"""
|
||||
tool_parameter_template = ""
|
||||
if upgrade_messages is None:
|
||||
upgrade_messages = {}
|
||||
|
||||
for input in input_params.values():
|
||||
if input.name in param_values:
|
||||
if input.type == "repeat":
|
||||
for i in range(len(param_values[input.name])):
|
||||
inputs_recursive(trans, input.inputs, param_values[input.name][i], depth=depth + 1)
|
||||
elif input.type == "section":
|
||||
tool_parameter_template += "<tr>"
|
||||
tool_parameter_template += inputs_recursive_indent(text=input.name, depth=depth)
|
||||
tool_parameter_template += "<td></td></tr>"
|
||||
inputs_recursive(
|
||||
trans,
|
||||
input.inputs,
|
||||
param_values[input.name],
|
||||
depth=depth + 1,
|
||||
upgrade_messages=upgrade_messages.get(input.name),
|
||||
)
|
||||
elif input.type == "conditional":
|
||||
try:
|
||||
current_case = param_values[input.name]["__current_case__"]
|
||||
is_valid = True
|
||||
except Exception:
|
||||
current_case = None
|
||||
is_valid = False
|
||||
if is_valid:
|
||||
tool_parameter_template += "<tr>"
|
||||
tool_parameter_template += inputs_recursive_indent(text=input.test_param.label, depth=depth)
|
||||
tool_parameter_template += f"<td>{input.cases[current_case].value}</td><td></td></tr>"
|
||||
inputs_recursive(
|
||||
trans,
|
||||
input.cases[current_case].inputs,
|
||||
param_values[input.name],
|
||||
depth=depth + 1,
|
||||
upgrade_messages=upgrade_messages.get(input.name),
|
||||
)
|
||||
else:
|
||||
tool_parameter_template += "<tr>"
|
||||
tool_parameter_template += inputs_recursive_indent(text=input.name, depth=depth)
|
||||
tool_parameter_template += (
|
||||
"<td><em> The previously used value is no longer valid </em></td><td></td></tr>"
|
||||
)
|
||||
elif input.type == "upload_dataset":
|
||||
tool_parameter_template += "<tr>"
|
||||
tool_parameter_template += inputs_recursive_indent(text=input.group_title(param_values), depth=depth)
|
||||
tool_parameter_template += (
|
||||
f"<td>{str(len(param_values[input.name]))} uploaded datasets</td><td></td></tr>"
|
||||
)
|
||||
elif input.type == "data":
|
||||
tool_parameter_template += "<tr>"
|
||||
tool_parameter_template += inputs_recursive_indent(text=input.label, depth=depth)
|
||||
tool_parameter_template += "<td>"
|
||||
for i, element in enumerate(listify(param_values[input.name])):
|
||||
if i > 0:
|
||||
tool_parameter_template += ","
|
||||
if element.history_content_type == "dataset":
|
||||
hda = element
|
||||
encoded_id = trans.security.encode_id(hda.id)
|
||||
dataset_info_url = url_for(controller="dataset", action="details", dataset_id=encoded_id)
|
||||
tool_parameter_template += f'<a target="galaxy_main" data-hda-id="{encoded_id}"'
|
||||
tool_parameter_template += f'href="{dataset_info_url}">{str(hda.hid)}:{hda.name}</a>'
|
||||
else:
|
||||
tool_parameter_template += f"{str(element.hid)}:{element.name}"
|
||||
tool_parameter_template += "</td><td></td></tr>"
|
||||
elif input.visible:
|
||||
label = input.label if (hasattr(input, "label") and input.label) else input.name
|
||||
tool_parameter_template += "<tr>"
|
||||
tool_parameter_template += inputs_recursive_indent(text=label, depth=depth)
|
||||
tool_parameter_template += f"<td>{input.value_to_display_text(param_values[input.name])}</td>"
|
||||
tool_parameter_template += f"<td>{upgrade_messages.get(input.name, '')}</td></tr>"
|
||||
else:
|
||||
tool_parameter_template += "<tr>"
|
||||
if input.type == "conditional":
|
||||
label = input.test_param.label
|
||||
elif input.type == "repeat":
|
||||
label = input.label()
|
||||
else:
|
||||
label = input.label or input.name
|
||||
tool_parameter_template += inputs_recursive_indent(text=label, depth=depth)
|
||||
tool_parameter_template += (
|
||||
"<td><em> not used (parameter was added after this job was run)</em></td><td></td></tr>"
|
||||
)
|
||||
return tool_parameter_template
|
||||
@@ -47,7 +47,6 @@ from galaxy.webapps.base.controller import (
|
||||
SUCCESS,
|
||||
WARNING,
|
||||
)
|
||||
from ._create_history_template import render_item
|
||||
from ..api import depends
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -520,106 +519,6 @@ class HistoryController(BaseUIController, SharableMixin, UsesAnnotations, UsesIt
|
||||
show_hidden=string_as_bool(show_hidden),
|
||||
)
|
||||
|
||||
@web.expose
|
||||
@web.json
|
||||
def display_structured(self, trans, id=None):
|
||||
"""
|
||||
Display a history as a nested structure showing the jobs and workflow
|
||||
invocations that created each dataset (if any).
|
||||
"""
|
||||
# Get history
|
||||
if id is None:
|
||||
id = trans.history.id
|
||||
else:
|
||||
id = self.decode_id(id)
|
||||
# Expunge history from the session to allow us to force a reload
|
||||
# with a bunch of eager loaded joins
|
||||
trans.sa_session.expunge(trans.history)
|
||||
history = (
|
||||
trans.sa_session.query(model.History)
|
||||
.options(
|
||||
joinedload("active_datasets")
|
||||
.joinedload("creating_job_associations")
|
||||
.joinedload("job")
|
||||
.joinedload("workflow_invocation_step")
|
||||
.joinedload("workflow_invocation")
|
||||
.joinedload("workflow"),
|
||||
)
|
||||
.get(id)
|
||||
)
|
||||
if not (
|
||||
history
|
||||
and (
|
||||
(history.user and trans.user and history.user.id == trans.user.id)
|
||||
or (trans.history and history.id == trans.history.id)
|
||||
or trans.user_is_admin
|
||||
)
|
||||
):
|
||||
return trans.show_error_message("Cannot display history structure.")
|
||||
# Resolve jobs and workflow invocations for the datasets in the history
|
||||
# items is filled with items (hdas, jobs, or workflows) that go at the
|
||||
# top level
|
||||
items = []
|
||||
# First go through and group hdas by job, if there is no job they get
|
||||
# added directly to items
|
||||
jobs = {}
|
||||
for hda in history.active_datasets:
|
||||
if hda.visible is False:
|
||||
continue
|
||||
# Follow "copied from ..." association until we get to the original
|
||||
# instance of the dataset
|
||||
original_hda = hda
|
||||
# while original_hda.copied_from_history_dataset_association:
|
||||
# original_hda = original_hda.copied_from_history_dataset_association
|
||||
# Check if the job has a creating job, most should, datasets from
|
||||
# before jobs were tracked, or from the upload tool before it
|
||||
# created a job, may not
|
||||
if not original_hda.creating_job_associations:
|
||||
items.append((hda, None))
|
||||
# Attach hda to correct job
|
||||
# -- there should only be one creating_job_association, so this
|
||||
# loop body should only be hit once
|
||||
for assoc in original_hda.creating_job_associations:
|
||||
job = assoc.job
|
||||
if job in jobs:
|
||||
jobs[job].append((hda, None))
|
||||
else:
|
||||
jobs[job] = [(hda, None)]
|
||||
# Second, go through the jobs and connect to workflows
|
||||
wf_invocations = {}
|
||||
for job, hdas in jobs.items():
|
||||
# Job is attached to a workflow step, follow it to the
|
||||
# workflow_invocation and group
|
||||
if job.workflow_invocation_step:
|
||||
wf_invocation = job.workflow_invocation_step.workflow_invocation
|
||||
if wf_invocation in wf_invocations:
|
||||
wf_invocations[wf_invocation].append((job, hdas))
|
||||
else:
|
||||
wf_invocations[wf_invocation] = [(job, hdas)]
|
||||
# Not attached to a workflow, add to items
|
||||
else:
|
||||
items.append((job, hdas))
|
||||
# Finally, add workflow invocations to items, which should now
|
||||
# contain all hdas with some level of grouping
|
||||
items.extend(wf_invocations.items())
|
||||
# Sort items by age
|
||||
items.sort(key=(lambda x: x[0].create_time), reverse=True)
|
||||
# logic taken from mako files
|
||||
from galaxy.managers import hdas
|
||||
|
||||
hda_serializer = hdas.HDASerializer(trans.app)
|
||||
hda_dicts = []
|
||||
id_hda_dict_map = {}
|
||||
for hda in history.active_datasets:
|
||||
hda_dict = hda_serializer.serialize_to_view(hda, user=trans.user, trans=trans, view="detailed")
|
||||
id_hda_dict_map[hda_dict["id"]] = hda_dict
|
||||
hda_dicts.append(hda_dict)
|
||||
|
||||
html_template = ""
|
||||
for entity, children in items:
|
||||
html_template += render_item(trans, entity, children)
|
||||
return {"name": history.name, "history_json": hda_dicts, "template": html_template}
|
||||
|
||||
@expose_api_anonymous
|
||||
def view(self, trans, id=None, show_deleted=False, show_hidden=False, use_panels=True):
|
||||
"""
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
from .framework import (
|
||||
managed_history,
|
||||
selenium_test,
|
||||
SeleniumTestCase,
|
||||
)
|
||||
|
||||
|
||||
class HistoryStructureTestCase(SeleniumTestCase):
|
||||
|
||||
ensure_registered = True
|
||||
|
||||
@selenium_test
|
||||
@managed_history
|
||||
def test_history_structure(self):
|
||||
def assert_details(expected_to_be_visible):
|
||||
|
||||
error_message = "details are visible!"
|
||||
if expected_to_be_visible:
|
||||
error_message = "details are not visible!"
|
||||
|
||||
assert expected_to_be_visible == self.components.history_structure.details.is_displayed, error_message
|
||||
|
||||
self.perform_upload(self.get_filename("1.fasta"))
|
||||
self.wait_for_history()
|
||||
self.components.history_structure.header.assert_absent_or_hidden()
|
||||
self.components.history_structure.dataset.assert_absent_or_hidden()
|
||||
|
||||
self.history_panel_show_structure()
|
||||
|
||||
# assert details are not visible before expand
|
||||
self.components.history_structure.details.assert_absent_or_hidden()
|
||||
|
||||
self.components.history_structure.dataset.wait_for_and_click()
|
||||
self.sleep_for(self.wait_types.UX_RENDER)
|
||||
|
||||
assert_details(True)
|
||||
self.components.history_structure.header.wait_for_and_click()
|
||||
self.sleep_for(self.wait_types.UX_RENDER)
|
||||
|
||||
assert_details(False)
|
||||
self.components.history_structure.dataset.assert_absent_or_hidden()
|
||||
Reference in New Issue
Block a user