forked from enviPath/enviPy
Initial bayer app Show Pack Classification Adjusted docker compose to bayer specifics Adjusted Dockerfile for Bayer Adding secret flags to group, add secret pools to packages Adjusted View for Package creation Prep configs, added Package Create Modal wip More on PES wip wip Wip minor PW interactions API PES wip Make Select Widget reflect required make required generallay available Update UI if pathway mode is set to build Added ais circle adjustments Initial Zoom, fix AD Creation wip
256 lines
7.8 KiB
HTML
256 lines
7.8 KiB
HTML
{% extends "framework_modern.html" %}
|
|
{% load static %}
|
|
{% block content %}
|
|
<div class="mx-auto w-full p-8">
|
|
<h1 class="h1 mb-4 text-3xl font-bold">
|
|
Predict a Pathway
|
|
|
|
<span class="text-base-content/50 text-xs"
|
|
>in <strong>{{ meta.current_package.name|safe }}</strong>
|
|
</span>
|
|
</h1>
|
|
|
|
<form
|
|
id="predict_form"
|
|
accept-charset="UTF-8"
|
|
action="{{ meta.current_package.url }}/pathway"
|
|
method="post"
|
|
>
|
|
{% csrf_token %}
|
|
<div class="mb-8 flex flex-col gap-8 md:flex-row md:items-end">
|
|
<fieldset class="flex flex-col gap-4 md:flex-3/4">
|
|
<label class="floating-label" for="name">
|
|
<input
|
|
type="text"
|
|
name="name"
|
|
placeholder="Name"
|
|
id="name"
|
|
class="input input-md w-full"
|
|
autofocus
|
|
/>
|
|
<span>Name</span>
|
|
</label>
|
|
|
|
<label class="floating-label" for="description">
|
|
<input
|
|
type="text"
|
|
name="description"
|
|
placeholder="Description"
|
|
id="description"
|
|
class="input input-md w-full"
|
|
/>
|
|
<span>Description</span>
|
|
</label>
|
|
</fieldset>
|
|
<fieldset
|
|
class="fieldset flex shrink-0 flex-row items-start gap-3 md:flex-1/4 md:flex-col"
|
|
>
|
|
<label class="fieldset-label text-base-content/50">Mode</label>
|
|
<label class="label">
|
|
<input
|
|
type="radio"
|
|
name="predict"
|
|
id="radioPredict"
|
|
value="predict"
|
|
checked
|
|
class="radio radio-neutral"
|
|
/>
|
|
Predict
|
|
</label>
|
|
<label class="label">
|
|
<input
|
|
type="radio"
|
|
name="predict"
|
|
id="radioIncremental"
|
|
value="incremental"
|
|
class="radio radio-neutral"
|
|
/>
|
|
Incremental
|
|
</label>
|
|
<label class="label">
|
|
<input
|
|
type="radio"
|
|
name="predict"
|
|
id="radioBuild"
|
|
value="build"
|
|
class="radio radio-neutral"
|
|
/>
|
|
Build
|
|
</label>
|
|
</fieldset>
|
|
</div>
|
|
|
|
<label class="floating-label" for="predict-smiles">
|
|
<input
|
|
type="text"
|
|
name="smiles"
|
|
placeholder="SMILES"
|
|
id="predict-smiles"
|
|
class="input input-md w-full"
|
|
/>
|
|
<span>SMILES</span>
|
|
</label>
|
|
|
|
<div class="divider text-base-content/50">OR</div>
|
|
|
|
<div class="mb-8 w-full">
|
|
<label class="text-base-content/50 mb-4 text-xs font-medium"
|
|
>Draw Structure</label
|
|
>
|
|
<iframe
|
|
id="predict-ketcher"
|
|
src="{% static '/js/ketcher2/ketcher.html' %}"
|
|
width="100%"
|
|
height="510"
|
|
></iframe>
|
|
</div>
|
|
|
|
<label class="select mb-8 w-full" id="prediction-setting-label">
|
|
<span class="label">Predictor</span>
|
|
<select id="prediction-setting" name="prediction-setting">
|
|
<option disabled>Select a Setting</option>
|
|
{% for s in meta.available_settings %}
|
|
<option
|
|
value="{{ s.url }}"
|
|
{% if s.id == meta.user.default_setting.id %}selected{% endif %}
|
|
>
|
|
{{ s.name }}{% if s.id == meta.user.default_setting.id %}
|
|
(User default)
|
|
{% endif %}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</label>
|
|
|
|
<div class="flex h-fit w-full justify-between">
|
|
<a
|
|
href="/batch-predict"
|
|
class="link-hover text-neutral/50 self-end text-sm"
|
|
>More than one compound?</a
|
|
>
|
|
|
|
<div class="flex justify-end gap-2">
|
|
<a
|
|
href="{{ meta.current_package.url }}/pathway"
|
|
class="btn btn-outline"
|
|
>Cancel</a
|
|
>
|
|
<button
|
|
type="submit"
|
|
id="predict-submit-button"
|
|
class="btn btn-primary"
|
|
>
|
|
Predict
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
{# prettier-ignore-start #}
|
|
<script>
|
|
// Hide predictor selection and update button text if mode is "build"
|
|
function radioChange(event) {
|
|
if (event.target.value === "build") {
|
|
document.getElementById("prediction-setting-label").hidden = true;
|
|
document.getElementById("predict-submit-button").innerText = "Build";
|
|
} else {
|
|
document.getElementById("prediction-setting-label").hidden = false;
|
|
document.getElementById("predict-submit-button").innerText = "Predict";
|
|
}
|
|
}
|
|
|
|
const radioButtons = document.querySelectorAll('input[name="predict"]');
|
|
radioButtons.forEach(radio => {
|
|
radio.addEventListener('change', radioChange);
|
|
});
|
|
|
|
// Helper function to safely get Ketcher instance from iframe
|
|
function getKetcherInstance(iframeId) {
|
|
const ketcherFrame = document.getElementById(iframeId);
|
|
if (!ketcherFrame) {
|
|
console.error("Ketcher iframe not found:", iframeId);
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
if ('contentWindow' in ketcherFrame && ketcherFrame.contentWindow.ketcher) {
|
|
return ketcherFrame.contentWindow.ketcher;
|
|
}
|
|
} catch (err) {
|
|
console.error("Cannot access Ketcher iframe - possible CORS issue:", err);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function predictKetcherToTextInput() {
|
|
document.getElementById("predict-smiles").value = this.ketcher.getSmiles();
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
const predictKetcher = document.getElementById("predict-ketcher");
|
|
predictKetcher.addEventListener("load", function () {
|
|
const checkKetcherReady = () => {
|
|
const win = this.contentWindow;
|
|
if (win.ketcher && "editor" in win.ketcher) {
|
|
window.predictKetcher = win.ketcher;
|
|
win.ketcher.editor.event.change.handlers.push({
|
|
once: false,
|
|
priority: 0,
|
|
f: predictKetcherToTextInput,
|
|
ketcher: win.ketcher,
|
|
});
|
|
} else {
|
|
setTimeout(checkKetcherReady, 100);
|
|
}
|
|
};
|
|
|
|
checkKetcherReady();
|
|
});
|
|
|
|
const submitButton = document.getElementById("predict-submit-button");
|
|
submitButton.addEventListener("click", function (e) {
|
|
e.preventDefault();
|
|
const button = this;
|
|
button.disabled = true;
|
|
button.textContent = "Predicting...";
|
|
|
|
// Get SMILES from either input or Ketcher
|
|
const smilesInput = document.getElementById("predict-smiles");
|
|
let smiles = smilesInput.value.trim();
|
|
|
|
// If SMILES input is empty, try to get from Ketcher
|
|
if (!smiles) {
|
|
const ketcher = getKetcherInstance('predict-ketcher');
|
|
if (ketcher && ketcher.getSmiles) {
|
|
try {
|
|
smiles = ketcher.getSmiles().trim();
|
|
if (smiles) {
|
|
smilesInput.value = smiles;
|
|
}
|
|
} catch (err) {
|
|
console.error("Failed to get SMILES from Ketcher:", err);
|
|
alert("Unable to extract structure from the drawing editor. Please enter a SMILES string instead.");
|
|
button.disabled = false;
|
|
button.textContent = "Predict";
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Basic validation
|
|
if (!smiles) {
|
|
alert("Please enter a SMILES string or draw a structure.");
|
|
button.disabled = false;
|
|
button.textContent = "Predict";
|
|
return;
|
|
}
|
|
|
|
// Submit form
|
|
document.getElementById("predict_form").submit();
|
|
});
|
|
});
|
|
</script>
|
|
{# prettier-ignore-end #}
|
|
{% endblock content %}
|