forked from enviPath/enviPy
443 lines
20 KiB
HTML
443 lines
20 KiB
HTML
{% extends "framework.html" %}
|
|
{% load static %}
|
|
{% block content %}
|
|
|
|
<script src="https://d3js.org/d3.v7.min.js"></script>
|
|
<style>
|
|
#vizdiv {
|
|
width: 100%;
|
|
height: 600px;
|
|
background: white;
|
|
}
|
|
|
|
#pwsvg {
|
|
width: 100%;
|
|
height: 100%;
|
|
color: red;
|
|
}
|
|
|
|
.link {
|
|
stroke: #999;
|
|
stroke-opacity: 0.6;
|
|
//marker-end: url(#arrow);
|
|
}
|
|
|
|
.link_no_arrow {
|
|
stroke: #999;
|
|
stroke-opacity: 0.6;
|
|
}
|
|
|
|
.node image {
|
|
cursor: pointer;
|
|
}
|
|
|
|
.node circle {
|
|
fill: lightblue;
|
|
stroke: steelblue;
|
|
stroke-width: 1.5px;
|
|
}
|
|
|
|
.inside_app_domain {
|
|
fill: green;
|
|
stroke: green;
|
|
stroke-width: 1.5px;
|
|
}
|
|
|
|
.outside_app_domain {
|
|
fill: red;
|
|
stroke: red;
|
|
stroke-width: 1.5px;
|
|
}
|
|
|
|
.passes_app_domain {
|
|
stroke: green;
|
|
stroke-width: 1.5px;
|
|
stroke-opacity: 0.6;
|
|
}
|
|
|
|
.fails_app_domain {
|
|
stroke: red;
|
|
stroke-width: 1.5px;
|
|
stroke-opacity: 0.6;
|
|
}
|
|
|
|
|
|
.highlighted {
|
|
stroke: red;
|
|
stroke-width: 3px;
|
|
}
|
|
|
|
.tooltip {
|
|
position: absolute;
|
|
background: lightgrey;
|
|
padding: 5px;
|
|
border-radius: 5px;
|
|
visibility: hidden;
|
|
opacity: 1
|
|
}
|
|
</style>
|
|
<script src="{% static 'js/pw.js' %}"></script>
|
|
|
|
{% block action_modals %}
|
|
{% include "modals/objects/add_pathway_node_modal.html" %}
|
|
{% include "modals/objects/add_pathway_edge_modal.html" %}
|
|
{% include "modals/objects/download_pathway_csv_modal.html" %}
|
|
{% include "modals/objects/download_pathway_image_modal.html" %}
|
|
{% include "modals/objects/generic_copy_object_modal.html" %}
|
|
{% include "modals/objects/edit_pathway_modal.html" %}
|
|
{% include "modals/objects/generic_set_scenario_modal.html" %}
|
|
{% include "modals/objects/delete_pathway_node_modal.html" %}
|
|
{% include "modals/objects/delete_pathway_edge_modal.html" %}
|
|
{% include "modals/objects/generic_delete_modal.html" %}
|
|
{% endblock action_modals %}
|
|
|
|
<p></p>
|
|
<div id="pwcontent">
|
|
<div class="panel-group" id="pwAccordion">
|
|
<div class="panel panel-default">
|
|
<div class="panel-heading" id="headingPanel" style="font-size:2rem;height: 46px">
|
|
{{ pathway.name }}
|
|
</div>
|
|
</div>
|
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
|
<h4 class="panel-title">
|
|
<a id="vizLink" data-toggle="collapse" data-parent="#pwAccordion" href="#viz">
|
|
Graphical Representation
|
|
</a>
|
|
</h4>
|
|
</div>
|
|
<div id="viz" class="panel-collapse collapse in">
|
|
<nav role="navigation" class="navbar navbar-default" style="margin: 0;">
|
|
<div class="navbar-header">
|
|
</div>
|
|
<div id="editbarCollapse" class="collapse navbar-collapse ">
|
|
<ul class="nav navbar-nav">
|
|
<li class="dropdown requiresWritePerm">
|
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
|
aria-haspopup="true" aria-expanded="false">
|
|
<span class="glyphicon glyphicon-edit"></span>
|
|
Edit
|
|
<span class="caret"></span></a>
|
|
<ul id="editingList" class="dropdown-menu">
|
|
{% block actions %}
|
|
{% include "actions/objects/pathway.html" %}
|
|
{% endblock %}
|
|
</ul>
|
|
</li>
|
|
{% if pathway.setting.model.app_domain %}
|
|
<li class="dropdown">
|
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
|
aria-haspopup="true" aria-expanded="false">
|
|
<span class="glyphicon glyphicon-eye-open"></span>
|
|
View
|
|
<span class="caret"></span></a>
|
|
<ul id="editingList" class="dropdown-menu">
|
|
<li>
|
|
<a class="button" id="app-domain-toggle-button">
|
|
<i id="app-domain-toggle-button" class="glyphicon glyphicon-eye-open"></i> App Domain View</a>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
|
|
<ul class="nav navbar-nav navbar-right">
|
|
<li>
|
|
<a role="button" data-toggle="modal" onclick="goFullscreen('vizdiv')">
|
|
<span class="glyphicon glyphicon-fullscreen"></span>
|
|
Fullscreen
|
|
</a>
|
|
</li>
|
|
<li>
|
|
{% if pathway.completed %}
|
|
<button type="button" class="btn btn-default navbar-btn" data-toggle="popover"
|
|
id="status" data-original-title="" title=""
|
|
data-content="Pathway prediction complete.">
|
|
<span class="glyphicon glyphicon-ok"></span>
|
|
</button>
|
|
{% elif pathway.failed %}
|
|
<button type="button" class="btn btn-default navbar-btn" data-toggle="popover"
|
|
id="status" data-original-title="" title=""
|
|
data-content="Pathway prediction failed.">
|
|
<span class="glyphicon glyphicon-remove"></span>
|
|
</button>
|
|
{% else %}
|
|
<button type="button" class="btn btn-default navbar-btn" data-toggle="popover"
|
|
id="status" data-original-title="" title=""
|
|
data-content="Pathway prediction running.">
|
|
<img height="20" src="{% static '/images/wait.gif' %}">
|
|
</button>
|
|
{% endif %}
|
|
|
|
</li>
|
|
</ul>
|
|
|
|
</div>
|
|
</nav>
|
|
<div id="vizdiv" >
|
|
<svg id="pwsvg">
|
|
{% if debug %}
|
|
<rect width="100%" height="100%" fill="aliceblue"/>
|
|
{% endif %}
|
|
<defs>
|
|
<marker id="arrow" viewBox="0 0 10 10" refX="43" refY="5" markerWidth="6" markerHeight="6"
|
|
orient="auto-start-reverse" markerUnits="userSpaceOnUse">
|
|
<path d="M 0 0 L 10 5 L 0 10 z" fill="#999"/>
|
|
</marker>
|
|
<marker id="arrow_passes_app_domain" viewBox="0 0 10 10" refX="43" refY="5" markerWidth="6" markerHeight="6"
|
|
orient="auto-start-reverse" markerUnits="userSpaceOnUse">
|
|
<path d="M 0 0 L 10 5 L 0 10 z" fill="green"/>
|
|
</marker>
|
|
<marker id="arrow_fails_app_domain" viewBox="0 0 10 10" refX="43" refY="5" markerWidth="6" markerHeight="6"
|
|
orient="auto-start-reverse" markerUnits="userSpaceOnUse">
|
|
<path d="M 0 0 L 10 5 L 0 10 z" fill="red"/>
|
|
</marker>
|
|
</defs>
|
|
<g id="zoomable"></g>
|
|
</svg>
|
|
<div id="tooltip" class="tooltip"></div>
|
|
</div>
|
|
</div>
|
|
<!-- Description -->
|
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
|
<h4 class="panel-title">
|
|
<a id="DescriptionLink" data-toggle="collapse" data-parent="#pathwayAccordion"
|
|
href="#Description">Description</a></h4>
|
|
</div>
|
|
<div id="Description" class="panel-collapse collapse in">
|
|
<div class="panel-body list-group-item" id="DescriptionContent">
|
|
{{ pathway.description | safe }}
|
|
</div>
|
|
</div>
|
|
|
|
{% if pathway.scenarios.all %}
|
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
|
<h4 class="panel-title">
|
|
<a id="pathway-scenario-link" data-toggle="collapse" data-parent="#pathway-detail"
|
|
href="#pathway-scenario">Scenarios</a>
|
|
</h4>
|
|
</div>
|
|
<div id="pathway-scenario" class="panel-collapse collapse in">
|
|
<div class="panel-body list-group-item">
|
|
{% for s in pathway.scenarios.all %}
|
|
<a class="list-group-item" href="{{ s.url }}">{{ s.name }} <i>({{ s.package.name }})</i></a>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if pathway.setting %}
|
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
|
<h4 class="panel-title">
|
|
<a id="pathwaySettingLink" data-toggle="collapse" data-parent="#pathwayAccordion"
|
|
href="#pathwaySetting">Setting</a></h4>
|
|
</div>
|
|
<div id="pathwaySetting" class="panel-collapse collapse">
|
|
<div class="panel-body list-group-item" id="pathwaySettingContent">
|
|
<table class="table table-bordered table-hover">
|
|
<tr style="background-color: rgba(0, 0, 0, 0.08);">
|
|
<th scope="col" width="20%">Parameter</th>
|
|
<th scope="col" width="80%">Value</th>
|
|
</tr>
|
|
<tbody>
|
|
{% if pathway.setting.model %}
|
|
<tr>
|
|
<td width="20%">Model</td>
|
|
<td width="80%">
|
|
<table width="100%" class="table table-bordered table-hover">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2">
|
|
<li class="list-group-item">
|
|
<a href="{{ pathway.setting.model.url }}">
|
|
{{ pathway.setting.model.name }}
|
|
</a>
|
|
</li>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th width="20%">Model Parameter</th>
|
|
<th width="80%">Parameter Value</th>
|
|
</tr>
|
|
<tr>
|
|
<td width="20%">
|
|
Threshold
|
|
</td>
|
|
<td width="80%">
|
|
{{ pathway.setting.model_threshold }}
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
{% endif %}
|
|
{% if pathway.setting.rule_packages.all %}
|
|
<tr>
|
|
<td width="20%">Rule Packages</td>
|
|
<td width="80%">
|
|
<table width="100%" class="table table-bordered table-hover">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2">
|
|
{% for p in pathway.setting.rule_packages.all %}
|
|
<li class="list-group-item">
|
|
<a href="{{ p.url }}">
|
|
{{ p.name }}
|
|
</a>
|
|
</li>
|
|
{% endfor %}
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
{% endif %}
|
|
<tr>
|
|
<td>
|
|
<p>Max Nodes</p>
|
|
</td>
|
|
<td>
|
|
<p>{{ pathway.setting.max_nodes }}</p>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<p>Max Depth</p>
|
|
</td>
|
|
<td>
|
|
<p>{{ pathway.setting.max_depth }}</p>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<script>
|
|
// Global switch for app domain view
|
|
var appDomainViewEnabled = false;
|
|
|
|
function goFullscreen(id) {
|
|
var element = document.getElementById(id);
|
|
if (element.mozRequestFullScreen) {
|
|
element.mozRequestFullScreen();
|
|
} else if (element.webkitRequestFullScreen) {
|
|
element.webkitRequestFullScreen();
|
|
}
|
|
}
|
|
|
|
function transformReferences(text) {
|
|
return text.replace(/\[\s*(http[^\]|]+)\s*\|\s*([^\]]+)\s*\]/g, '<a target="parent" href="$1">$2</a>');
|
|
}
|
|
|
|
pathway = {{ pathway.d3_json | safe }};
|
|
|
|
$(function () {
|
|
|
|
$('#status').popover({
|
|
trigger: 'manual',
|
|
placement: 'bottom',
|
|
html: true
|
|
});
|
|
|
|
// If prediction is still running, regularly check status
|
|
if (pathway.status === 'running') {
|
|
let last_modified = pathway.modified;
|
|
|
|
let pollInterval = setInterval(async () => {
|
|
try {
|
|
const response = await fetch("{{ pathway.url }}?status=true", {});
|
|
const data = await response.json();
|
|
|
|
if (data.modified > last_modified) {
|
|
var msg = 'Prediction '
|
|
var btn = '<button type="button" onclick="location.reload()" class="btn btn-primary" id="reloadBtn">Reload page</button>'
|
|
|
|
if (data.status === "running") {
|
|
msg += 'is still running. But the Pathway was updated.<br>' + btn;
|
|
|
|
} else if (data.status === "completed") {
|
|
msg += 'is completed. Reload the page to see the updated Pathway.<br>' + btn;
|
|
} else if (data.status === "failed") {
|
|
msg += 'failed. Reload the page to see the current shape<br>' + btn;
|
|
}
|
|
|
|
$('#status').attr(
|
|
'data-content', msg
|
|
).popover('show');
|
|
}
|
|
|
|
if (data.status === "completed" || data.status === "failed") {
|
|
$('#status img').remove();
|
|
if (data.status === "completed") {
|
|
$('#status').append('<span class="glyphicon glyphicon-ok"></span>')
|
|
} else {
|
|
$('#status').append('<span class="glyphicon glyphicon-remove"></span>')
|
|
}
|
|
clearInterval(pollInterval);
|
|
}
|
|
|
|
} catch (err) {
|
|
console.error("Polling error:", err);
|
|
}
|
|
}, 5000);
|
|
}
|
|
|
|
draw(pathway, 'vizdiv');
|
|
// TODO fix somewhere else...
|
|
var newDesc = transformReferences($('#DescriptionContent')[0].innerText);
|
|
$('#DescriptionContent').html(newDesc);
|
|
|
|
|
|
$('#app-domain-toggle-button').on('click', function () {
|
|
// glyphicon glyphicon-eye-close
|
|
// glyphicon glyphicon-eye-open
|
|
appDomainViewEnabled = !appDomainViewEnabled;
|
|
|
|
if (appDomainViewEnabled) {
|
|
$('#app-domain-toggle-button > i').removeClass('glyphicon-eye-open');
|
|
$('#app-domain-toggle-button > i').addClass('glyphicon-eye-close');
|
|
nodes.forEach((x) => {
|
|
if(x.app_domain) {
|
|
if (x.app_domain.inside_app_domain) {
|
|
d3.select(x.el).select("circle").classed("inside_app_domain", true);
|
|
} else {
|
|
d3.select(x.el).select("circle").classed("outside_app_domain", true);
|
|
}
|
|
}
|
|
});
|
|
links.forEach((x) => {
|
|
if(x.app_domain) {
|
|
if (x.app_domain.passes_app_domain) {
|
|
d3.select(x.el).attr("marker-end", d => d.target.pseudo ? "" : "url(#arrow_passes_app_domain)");
|
|
d3.select(x.el).classed("passes_app_domain", true);
|
|
} else {
|
|
d3.select(x.el).attr("marker-end", d => d.target.pseudo ? "" : "url(#arrow_fails_app_domain)");
|
|
d3.select(x.el).classed("fails_app_domain", true);
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
$('#app-domain-toggle-button > i').removeClass('glyphicon-eye-close');
|
|
$('#app-domain-toggle-button > i').addClass('glyphicon-eye-open');
|
|
nodes.forEach((x) => {
|
|
d3.select(x.el).select("circle").classed("inside_app_domain", false);
|
|
d3.select(x.el).select("circle").classed("outside_app_domain", false);
|
|
});
|
|
links.forEach((x) => {
|
|
d3.select(x.el).attr("marker-end", d => d.target.pseudo ? "" : "url(#arrow)");
|
|
d3.select(x.el).classed("passes_app_domain", false);
|
|
d3.select(x.el).classed("fails_app_domain", false);
|
|
});
|
|
}
|
|
})
|
|
|
|
});
|
|
|
|
</script>
|
|
{% endblock content %}
|