[Feature] Modern UI roll out (#236)

This PR moves all the collection pages into the new UI in a rough push.
I did not put the same amount of care into these as into search, index, and predict.

## Major changes

- All modals are now migrated to a state based alpine.js implementation.
- jQuery is no longer present in the base layout; ajax is replace by native fetch api
- most of the pps.js is now obsolte (as I understand it; the code is not referenced any more @jebus  please double check)
- in-memory pagination for large result lists (set to 50; we can make that configurable later; performance degrades at around 1k) stukk a bit rough tracked in #235

## Minor things

- Sarch and index also use alpine now
- The loading spinner is now CSS animated (not sure if it currently gets correctly called)

## Not done

- Ihave not even cheked the admin pages. Not sure If these need migrations
- The temporary migration pages still use the old template. Not sure what is supposed to happen with those? @jebus

## What I did to test

- opend all pages in browse, and user ; plus all pages reachable from there.
- Interacted and tested the functionality of each modal superfically with exception of the API key modal (no functional test).

---
This PR is massive sorry for that; just did not want to push half-brokenn state.
@jebus @liambrydon I would be glad if you could click around and try to break it :)

Finally closes #133

Co-authored-by: Tim Lorsbach <tim@lorsba.ch>
Reviewed-on: enviPath/enviPy#236
Co-authored-by: Tobias O <tobias.olenyi@envipath.com>
Co-committed-by: Tobias O <tobias.olenyi@envipath.com>
This commit is contained in:
2025-11-26 23:16:44 +13:00
committed by jebus
parent 7f6f209b4a
commit 1a2c9bb543
110 changed files with 10784 additions and 9465 deletions

View File

@ -1,48 +0,0 @@
<div
class="modal fade bs-modal-lg"
id="citemodal"
tabindex="-1"
role="dialog"
aria-labelledby="myLargeModalLabel"
aria-hidden="true"
>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h3>How to cite enviPath</h3>
</div>
<div class="modal-body">
<ol class="list-group list-group-numbered">
<li class="list-group-item">
Hafner, J., Lorsbach, T., Schmidt, S. <em>et al.</em>
<cite
>Advancements in biotransformation pathway prediction:
enhancements, datasets, and novel functionalities in
enviPath.</cite
>
<a href="https://doi.org/10.1186/s13321-024-00881-6" target="_blank"
>J Cheminform 16, 93 (2024)</a
>
</li>
<li class="list-group-item">
Wicker, J., Lorsbach, T., Gütlein, M., Schmid, E., Latino, D.,
Kramer, S., Fenner, K.
<cite
>enviPath - The environmental contaminant biotransformation
pathway resource</cite
>
<a href="https://doi.org/10.1093/nar/gkv1229" target="_blank">
Nucleic Acids Research, Volume 44, Issue D1, 4 January 2016, Pages
D502-D508
</a>
</li>
</ol>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
Close
</button>
</div>
</div>
</div>
</div>

View File

@ -1,70 +1,85 @@
<div
class="modal fade"
tabindex="-1"
<dialog
id="import_legacy_package_modal"
role="dialog"
aria-labelledby="import_legacy_package_modal"
aria-hidden="true"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title">Import Package from legacy System</h4>
</div>
<div class="modal-body">
<p>Create a Package based on the JSON Export of the legacy system.</p>
<form
id="import-legacy-package-modal-form"
accept-charset="UTF-8"
data-remote="true"
method="post"
enctype="multipart/form-data"
>
{% csrf_token %}
<p>
<label class="btn btn-primary" for="legacyJsonFile">
<input
id="legacyJsonFile"
name="file"
type="file"
style="display:none;"
onchange="$('#upload-legacy-file-info').html(this.files[0].name)"
/>
Choose JSON File
</label>
<span class="label label-info" id="upload-legacy-file-info"></span>
<input
type="hidden"
value="import-legacy-package-json"
name="hidden"
readonly=""
/>
</p>
</form>
</div>
<div class="modal-footer">
<a
id="import-legacy-package-modal-form-submit"
class="btn btn-primary"
href="#"
>Submit</a
>
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
</div>
<div class="modal-box">
<!-- Header -->
<h3 class="text-lg font-bold">Import Package from Legacy System</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p class="mb-4">
Create a Package based on the JSON Export of the legacy system.
</p>
<form
id="import-legacy-package-modal-form"
accept-charset="UTF-8"
method="post"
enctype="multipart/form-data"
>
{% csrf_token %}
<div class="form-control">
<label class="label">
<span class="label-text">Legacy JSON File</span>
</label>
<input
type="file"
id="legacyJsonFile"
name="file"
class="file-input file-input-bordered w-full"
accept=".json"
required
/>
</div>
<input
type="hidden"
value="import-legacy-package-json"
name="hidden"
readonly
/>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Cancel
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('import-legacy-package-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Importing...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#import-legacy-package-modal-form-submit").on("click", function (e) {
e.preventDefault();
$("#import-legacy-package-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,70 +1,83 @@
<div
class="modal fade"
tabindex="-1"
<dialog
id="import_package_modal"
role="dialog"
aria-labelledby="import_package_modal"
aria-hidden="true"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title">Import Package</h4>
</div>
<div class="modal-body">
<p>Create a Package based on a JSON Export.</p>
<form
id="import-package-modal-form"
accept-charset="UTF-8"
data-remote="true"
method="post"
enctype="multipart/form-data"
>
{% csrf_token %}
<p>
<label class="btn btn-primary" for="jsonFile">
<input
id="jsonFile"
name="file"
type="file"
style="display:none;"
onchange="$('#upload-file-info').html(this.files[0].name)"
/>
Choose JSON File
</label>
<span class="label label-info" id="upload-file-info"></span>
<input
type="hidden"
value="import-package-json"
name="hidden"
readonly=""
/>
</p>
</form>
</div>
<div class="modal-footer">
<a
id="import-package-modal-form-submit"
class="btn btn-primary"
href="#"
>Submit</a
>
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
</div>
<div class="modal-box">
<!-- Header -->
<h3 class="text-lg font-bold">Import Package</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p class="mb-4">Create a Package based on a JSON Export.</p>
<form
id="import-package-modal-form"
accept-charset="UTF-8"
method="post"
enctype="multipart/form-data"
>
{% csrf_token %}
<div class="form-control">
<label class="label">
<span class="label-text">JSON File</span>
</label>
<input
type="file"
id="jsonFile"
name="file"
class="file-input file-input-bordered w-full"
accept=".json"
required
/>
</div>
<input
type="hidden"
value="import-package-json"
name="hidden"
readonly
/>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Cancel
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('import-package-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Importing...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#import-package-modal-form-submit").on("click", function (e) {
e.preventDefault();
$("#import-package-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,119 +1,137 @@
{% load static %}
<div
class="modal fade bs-modal-lg"
<dialog
id="new_compound_modal"
tabindex="-1"
aria-labelledby="new_compound_modal"
aria-modal="true"
role="dialog"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Create a new Compound</h4>
</div>
<div class="modal-body">
<form
id="new_compound_modal_form"
accept-charset="UTF-8"
action="{% url 'package compound list' meta.current_package.uuid %}"
data-remote="true"
method="post"
>
{% csrf_token %}
<label for="compound-name">Name</label>
<div class="modal-box max-w-3xl">
<!-- Header -->
<h3 class="text-lg font-bold">Create a new Compound</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="new-compound-modal-form"
accept-charset="UTF-8"
action="{% url 'package compound list' meta.current_package.uuid %}"
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="compound-name">
<span class="label-text">Name</span>
</label>
<input
id="compound-name"
class="form-control"
class="input input-bordered w-full"
name="compound-name"
placeholder="Name"
required
/>
<label for="compound-description">Description</label>
</div>
<div class="form-control mb-3">
<label class="label" for="compound-description">
<span class="label-text">Description</span>
</label>
<input
id="compound-description"
class="form-control"
class="input input-bordered w-full"
name="compound-description"
placeholder="Description"
/>
<label for="compound-smiles">SMILES</label>
</div>
<div class="form-control mb-3">
<label class="label" for="compound-smiles">
<span class="label-text">SMILES</span>
</label>
<input
type="text"
class="form-control"
class="input input-bordered w-full"
name="compound-smiles"
placeholder="SMILES"
id="compound-smiles"
/>
<p></p>
<div>
<iframe
id="new_compound_ketcher"
src="{% static '/js/ketcher2/ketcher.html' %}"
width="100%"
height="510"
></iframe>
</div>
<p></p>
</form>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary pull-left"
data-dismiss="modal"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
id="new_compound_modal_form_submit"
>
Submit
</button>
</div>
</div>
<div class="mb-3">
<iframe
id="new_compound_ketcher"
src="{% static '/js/ketcher2/ketcher.html' %}"
width="100%"
height="510"
></iframe>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('new-compound-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Creating...</span>
</button>
</div>
</div>
</div>
<script>
function newCompoundModalketcherToNewCompoundModalTextInput() {
$("#compound-smiles").val(this.ketcher.getSmiles());
}
$(function () {
$("#new_compound_ketcher").on("load", function () {
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>
<script>
document
.getElementById("new_compound_ketcher")
.addEventListener("load", function () {
const iframe = this;
const checkKetcherReady = () => {
win = this.contentWindow;
const win = iframe.contentWindow;
if (win.ketcher && "editor" in win.ketcher) {
win.ketcher.editor.event.change.handlers.push({
once: false,
priority: 0,
f: newCompoundModalketcherToNewCompoundModalTextInput,
f: function () {
document.getElementById("compound-smiles").value =
this.ketcher.getSmiles();
},
ketcher: win.ketcher,
});
} else {
setTimeout(checkKetcherReady, 100);
}
};
checkKetcherReady();
});
$(function () {
$("#new_compound_modal_form_submit").on("click", function (e) {
e.preventDefault();
$(this).prop("disabled", true);
// submit form
$("#new_compound_modal_form").submit();
});
});
});
</script>

View File

@ -1,70 +1,96 @@
<div
class="modal fade"
tabindex="-1"
{% load static %}
<dialog
id="new_group_modal"
role="dialog"
aria-labelledby="new_group_modal"
aria-hidden="true"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title">New Group</h4>
</div>
<div class="modal-body">
<p>
Create new Group. You can assign users to the group once it is
created. Description can be changed after creation.
</p>
<form
id="new_group_modal_form"
accept-charset="UTF-8"
action="{{ SERVER_BASE }}/group"
data-remote="true"
method="post"
>
{% csrf_token %}
<p>
<label for="name">Name</label>
<input
id="name"
type="text"
name="group-name"
class="form-control"
placeholder="Name"
/>
</p>
<p>
<label for="description">Description</label>
<input
id="description"
type="text"
class="form-control"
placeholder="Description..."
name="group-description"
/>
</p>
</form>
</div>
<div class="modal-footer">
<a id="new_group_modal_form_submit" class="btn btn-primary" href="#"
>Submit</a
>
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
</div>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">New Group</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p class="mb-4">
Create new Group. You can assign users to the group once it is created.
Description can be changed after creation.
</p>
<form
id="new-group-modal-form"
accept-charset="UTF-8"
action="{{ SERVER_BASE }}/group"
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="group-name">
<span class="label-text">Name</span>
</label>
<input
id="group-name"
class="input input-bordered w-full"
name="group-name"
placeholder="Name"
required
/>
</div>
<div class="form-control mb-3">
<label class="label" for="group-description">
<span class="label-text">Description</span>
</label>
<input
id="group-description"
type="text"
class="input input-bordered w-full"
placeholder="Description..."
name="group-description"
/>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Cancel
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('new-group-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Creating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#new_group_modal_form_submit").on("click", function () {
$("#new_group_modal_form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,30 +1,66 @@
<div
class="modal fade"
tabindex="-1"
<dialog
id="new_model_modal"
role="dialog"
aria-labelledby="new_model_modal"
aria-hidden="true"
class="modal"
x-data="{
isSubmitting: false,
modelType: '',
buildAppDomain: false,
reset() {
this.isSubmitting = false;
this.modelType = '';
this.buildAppDomain = false;
},
get showMlrr() {
return this.modelType === 'mlrr';
},
get showRbrr() {
return this.modelType === 'rbrr';
},
get showEnviformer() {
return this.modelType === 'enviformer';
},
submit(formId) {
const form = document.getElementById(formId);
if (form && form.checkValidity()) {
this.isSubmitting = true;
form.submit();
} else if (form) {
form.reportValidity();
}
}
}"
@close="reset()"
>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title">New Model</h4>
</div>
<div class="modal-body">
<form
id="new_model_form"
accept-charset="UTF-8"
action="{{ meta.current_package.url }}/model"
data-remote="true"
method="post"
>
{% csrf_token %}
<div class="jumbotron">
<div class="modal-box max-w-3xl">
<!-- Header -->
<h3 class="text-lg font-bold">New Model</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="new_model_form"
accept-charset="UTF-8"
action="{{ meta.current_package.url }}/model"
method="post"
>
{% csrf_token %}
<div class="alert alert-info mb-4">
<span>
Create a new Model to limit the number of degradation products in
the prediction. You just need to set a name and the packages you
want the object to be based on. There are multiple types of models
@ -32,239 +68,270 @@
<a
target="_blank"
href="https://wiki.envipath.org/index.php/relative-reasoning"
role="button"
class="link"
>wiki &gt;&gt;</a
>
</div>
<!-- Name -->
<label for="model-name">Name</label>
</span>
</div>
<!-- Name -->
<div class="form-control mb-3">
<label class="label" for="model-name">
<span class="label-text">Name</span>
</label>
<input
id="model-name"
name="model-name"
class="form-control"
class="input input-bordered w-full"
placeholder="Name"
required
/>
</div>
<!-- Description -->
<label for="model-description">Description</label>
<!-- Description -->
<div class="form-control mb-3">
<label class="label" for="model-description">
<span class="label-text">Description</span>
</label>
<input
id="model-description"
name="model-description"
class="form-control"
class="input input-bordered w-full"
placeholder="Description"
/>
</div>
<!-- Model Type -->
<label for="model-type">Model Type</label>
<!-- Model Type -->
<div class="form-control mb-3">
<label class="label" for="model-type">
<span class="label-text">Model Type</span>
</label>
<select
id="model-type"
name="model-type"
class="form-control"
data-width="100%"
class="select select-bordered w-full"
x-model="modelType"
required
>
<option disabled selected>Select Model Type</option>
<option value="" disabled selected>Select Model Type</option>
{% for k, v in model_types.items %}
<option value="{{ v }}">{{ k }}</option>
{% endfor %}
</select>
</div>
<!-- Rule Packages -->
<div id="rule-packages" class="ep-model-param mlrr rbrr">
<label for="model-rule-packages">Rule Packages</label>
<select
id="model-rule-packages"
name="model-rule-packages"
data-actions-box="true"
class="form-control"
multiple
data-width="100%"
>
<option disabled>Reviewed Packages</option>
<!-- Rule Packages (MLRR, RBRR) -->
<div class="form-control mb-3" x-show="showMlrr || showRbrr" x-cloak>
<label class="label" for="model-rule-packages">
<span class="label-text">Rule Packages</span>
</label>
<select
id="model-rule-packages"
name="model-rule-packages"
class="select select-bordered w-full h-32"
multiple
>
<optgroup label="Reviewed Packages">
{% for obj in meta.readable_packages %}
{% if obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %}
{% endfor %}
<option disabled>Unreviewed Packages</option>
</optgroup>
<optgroup label="Unreviewed Packages">
{% for obj in meta.readable_packages %}
{% if not obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %}
{% endfor %}
</select>
</div>
</optgroup>
</select>
<label class="label">
<span class="label-text-alt">Hold Ctrl/Cmd to select multiple</span>
</label>
</div>
<!-- Data Packages -->
<div id="data-packages" class="ep-model-param mlrr rbrr enviformer">
<label for="model-data-packages">Data Packages</label>
<select
id="model-data-packages"
name="model-data-packages"
data-actions-box="true"
class="form-control"
multiple
data-width="100%"
>
<option disabled>Reviewed Packages</option>
<!-- Data Packages (MLRR, RBRR, Enviformer) -->
<div
class="form-control mb-3"
x-show="showMlrr || showRbrr || showEnviformer"
x-cloak
>
<label class="label" for="model-data-packages">
<span class="label-text">Data Packages</span>
</label>
<select
id="model-data-packages"
name="model-data-packages"
class="select select-bordered w-full h-32"
multiple
>
<optgroup label="Reviewed Packages">
{% for obj in meta.readable_packages %}
{% if obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %}
{% endfor %}
<option disabled>Unreviewed Packages</option>
</optgroup>
<optgroup label="Unreviewed Packages">
{% for obj in meta.readable_packages %}
{% if not obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %}
{% endfor %}
</select>
</div>
</optgroup>
</select>
<label class="label">
<span class="label-text-alt">Hold Ctrl/Cmd to select multiple</span>
</label>
</div>
<!-- Fingerprinter -->
<div id="fingerprinter" class="ep-model-param mlrr">
<label for="model-fingerprinter">Fingerprinter</label>
<select
id="model-fingerprinter"
name="model-fingerprinter"
data-actions-box="true"
class="form-control"
multiple
data-width="100%"
>
<option value="MACCS" selected>MACCS Fingerprinter</option>
{% if meta.enabled_features.PLUGINS and additional_descriptors %}
<option disabled selected>
Select Additional Fingerprinter / Descriptor
</option>
<!-- Fingerprinter (MLRR) -->
<div class="form-control mb-3" x-show="showMlrr" x-cloak>
<label class="label" for="model-fingerprinter">
<span class="label-text">Fingerprinter</span>
</label>
<select
id="model-fingerprinter"
name="model-fingerprinter"
class="select select-bordered w-full h-32"
multiple
>
<option value="MACCS" selected>MACCS Fingerprinter</option>
{% if meta.enabled_features.PLUGINS and additional_descriptors %}
<optgroup label="Additional Fingerprinter / Descriptor">
{% for k, v in additional_descriptors.items %}
<option value="{{ v }}">{{ k }}</option>
{% endfor %}
{% endif %}
</select>
</div>
</optgroup>
{% endif %}
</select>
<label class="label">
<span class="label-text-alt">Hold Ctrl/Cmd to select multiple</span>
</label>
</div>
<!-- Threshold -->
<div id="threshold" class="ep-model-param mlrr enviformer">
<label for="model-threshold">Threshold</label>
<input
type="number"
min="0"
max="1"
step="0.05"
value="0.5"
id="model-threshold"
name="model-threshold"
class="form-control"
/>
</div>
<!-- Threshold (MLRR, Enviformer) -->
<div
class="form-control mb-3"
x-show="showMlrr || showEnviformer"
x-cloak
>
<label class="label" for="model-threshold">
<span class="label-text">Threshold</span>
</label>
<input
type="number"
min="0"
max="1"
step="0.05"
value="0.5"
id="model-threshold"
name="model-threshold"
class="input input-bordered w-full"
/>
</div>
<div id="appdomain" class="ep-model-param mlrr">
{% if meta.enabled_features.APPLICABILITY_DOMAIN %}
<!-- Build AD? -->
<div class="checkbox">
<label>
<input
type="checkbox"
id="build-app-domain"
name="build-app-domain"
/>Also build an Applicability Domain?
<!-- Applicability Domain (MLRR) -->
{% if meta.enabled_features.APPLICABILITY_DOMAIN %}
<div x-show="showMlrr" x-cloak>
<div class="form-control mb-3">
<label class="label cursor-pointer justify-start gap-3">
<input
type="checkbox"
id="build-app-domain"
name="build-app-domain"
class="checkbox"
x-model="buildAppDomain"
/>
<span class="label-text"
>Also build an Applicability Domain?</span
>
</label>
</div>
<div x-show="buildAppDomain" x-cloak class="ml-4 space-y-3">
<div class="form-control">
<label class="label" for="num-neighbors">
<span class="label-text">Number of Neighbors</span>
</label>
</div>
<div id="ad-params" style="display:none">
<!-- Num Neighbors -->
<label for="num-neighbors">Number of Neighbors</label>
<input
id="num-neighbors"
name="num-neighbors"
type="number"
class="form-control"
class="input input-bordered w-full"
value="5"
step="1"
min="0"
max="10"
/>
<!-- Local Compatibility -->
<label for="local-compatibility-threshold"
>Local Compatibility Threshold</label
>
</div>
<div class="form-control">
<label class="label" for="local-compatibility-threshold">
<span class="label-text">Local Compatibility Threshold</span>
</label>
<input
id="local-compatibility-threshold"
name="local-compatibility-threshold"
type="number"
class="form-control"
value="0.5"
step="0.01"
min="0"
max="1"
/>
<!-- Reliability -->
<label for="reliability-threshold">Reliability Threshold</label>
<input
id="reliability-threshold"
name="reliability-threshold"
type="number"
class="form-control"
class="input input-bordered w-full"
value="0.5"
step="0.01"
min="0"
max="1"
/>
</div>
{% endif %}
<div class="form-control">
<label class="label" for="reliability-threshold">
<span class="label-text">Reliability Threshold</span>
</label>
<input
id="reliability-threshold"
name="reliability-threshold"
type="number"
class="input input-bordered w-full"
value="0.5"
step="0.01"
min="0"
max="1"
/>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<a id="new_model_modal_form_submit" class="btn btn-primary" href="#"
>Submit</a
>
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
</div>
{% endif %}
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Cancel
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('new_model_form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Creating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
// Built in Model Types
var nativeModelTypes = ["mlrr", "rbrr", "enviformer"];
// Initially hide all "specific" forms
$(".ep-model-param").each(function () {
$(this).hide();
});
$("#model-type").selectpicker();
$("#model-fingerprinter").selectpicker();
$("#model-rule-packages").selectpicker();
$("#model-data-packages").selectpicker();
$("#build-app-domain").change(function () {
if ($(this).is(":checked")) {
$("#ad-params").show();
} else {
$("#ad-params").hide();
}
});
// On change hide all and show only selected
$("#model-type").change(function () {
$(".ep-model-param").hide();
var modelType = $("#model-type").val();
if (nativeModelTypes.indexOf(modelType) !== -1) {
$("." + modelType).show();
} else {
// do nothing
}
});
$("#new_model_modal_form_submit").on("click", function (e) {
e.preventDefault();
$("#new_model_form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,68 +1,93 @@
<div
class="modal fade"
tabindex="-1"
{% load static %}
<dialog
id="new_package_modal"
role="dialog"
aria-labelledby="new_package_modal"
aria-hidden="true"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title">New Package</h4>
</div>
<div class="modal-body">
<p>Create new package. Description can be changed later.</p>
<form
id="new_package_modal_form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<p>
<label for="name">Name</label>
<input
id="name"
class="form-control"
name="package-name"
placeholder="Name"
/>
</p>
<p>
<label for="description">Description</label>
<input
id="description"
type="text"
rows="3"
class="form-control"
placeholder="Description..."
name="package-description"
/>
</p>
</form>
</div>
<div class="modal-footer">
<a id="new_package_modal_form_submit" class="btn btn-primary" href="#"
>Submit</a
>
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
</div>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">New Package</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p class="mb-4">Create new package. Description can be changed later.</p>
<form
id="new-package-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="package-name">
<span class="label-text">Name</span>
</label>
<input
id="package-name"
class="input input-bordered w-full"
name="package-name"
placeholder="Name"
required
/>
</div>
<div class="form-control mb-3">
<label class="label" for="package-description">
<span class="label-text">Description</span>
</label>
<input
id="package-description"
type="text"
class="input input-bordered w-full"
placeholder="Description..."
name="package-description"
/>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Cancel
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('new-package-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Creating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#new_package_modal_form_submit").on("click", function (e) {
e.preventDefault();
$("#new_package_modal_form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,376 +0,0 @@
{% load static %}
<div
class="modal fade"
tabindex="-1"
id="new_pathway_modal"
role="dialog"
aria-labelledby="new_pathway_modal"
aria-hidden="true"
style="overflow-y: auto;"
>
<!-- FIXME: make width dynamic-->
<div class="modal-dialog" id="new_pathway_modal_dialog" style="width:900px">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span>
</button>
<h4 class="js-title-step"></h4>
</div>
<div class="modal-body hide" data-step="1" data-title="New Pathway">
<div class="jumbotron">
Create a new pathway by entering the root compound and a name. Then
select if you want to use the prediction engine to generate a
predicted pathway or create an empty pathway that you fill in by
yourself. If you choose to predict a pathway, you can modify the
settings for the prediction, or use the default settings and just
click Submit.
</div>
<div class="modal-body">
{% if current_user.name == 'anonymous' %}
<div class="alert alert-warning">
You are currently logged in as Anonymous. Please note: Pathways
entered or predicted as anonymous user will be deleted after 30
days. Please log in to save your results.
</div>
{% endif %}
</div>
<div class="row">
<div class="col-md-6">
<label for="name">Name</label>
<input
id="name"
class="form-control"
name="name"
placeholder="Name"
/>
<label for="description">Description</label>
<input
id="description"
class="form-control"
name="description"
placeholder="no description"
/>
</div>
<div class="col-md-6">
<label for="predict">Predict pathway or build yourself?</label>
<div class="radio" id="predict">
<p>
<label>
<input
type="radio"
name="predict"
id="radioPredict"
value="predict"
checked
/>Predict pathway
</label>
</p>
<p>
<label>
<input
type="radio"
name="predict"
id="radioIncremental"
value="incremental"
/>Incremental prediction
</label>
</p>
<p>
<label>
<input
type="radio"
name="predict"
id="radioBuild"
value="build"
/>Build pathway
</label>
</p>
</div>
</div>
</div>
<label for="smilesinput">SMILES</label>
<table style="width: 100%">
<colgroup>
<col span="1" style="width: 90%;" />
<col span="1" style="width: 10%;" />
</colgroup>
<tr>
<td>
<input
id="smilesinput"
class="form-control"
name="smilesinput"
placeholder="C1CCCCC1"
autocapitalize="none"
/>
</td>
<td>
<button type="button" class="btn btn-default" id="render-button">
Render
</button>
</td>
</tr>
</table>
<p id="ketcher_container"></p>
<div>
<iframe
id="ifKetcher"
src="{% static '/js/ketcher/ketcher.html' %}"
width="850"
height="510"
></iframe>
</div>
</div>
<div
class="modal-body hide"
data-step="2"
data-title="New Pathway - Advanced Settings"
>
<div class="jumbotron">
Choose if you want to use an existing setting, or create a new one for
this pathway prediction. Then click Submit to use the specified
setting, or click next to set the parameters.
</div>
<div id="settings">
<div class="radio" id="settingRadio">
<p>
<label>
<input
type="radio"
name="existing"
id="radioDefault"
value="exisiting"
checked
/>
Use Default
</label>
</p>
<p>
<label>
<input
type="radio"
name="existing"
id="radioExists"
value="exisiting"
/>
Select Existing
</label>
</p>
<p>
<label>
<input
type="radio"
name="existing"
id="radioNew"
value="temporary"
/>
Create New
</label>
</p>
</div>
<select id="settingSelect" name="settingSelect" class="form-control">
{% for setting in available_settings %}
<option value="{{ setting.id }}">{{ setting.name|safe }}</option>
{% endfor %}
</select>
<p></p>
</div>
</div>
{% with step_offset=1 %}
{% include "templates/modals/collections/new_setting_modal_body.html" %}
{% endwith %}
<div class="modal-footer">
<button
type="button"
class="btn btn-default js-btn-step pull-left"
data-orientation="cancel"
onclick="reset()"
data-dismiss="modal"
></button>
<button
type="button"
class="btn btn-default js-btn-step"
data-orientation="previous"
id="backbutton"
></button>
<button
type="button"
class="btn btn-default js-btn-step"
data-orientation="next"
id="nextbutton"
></button>
<a id="modal-form-submit" class="btn btn-primary" href="#">Submit</a>
</div>
</div>
</div>
</div>
<script>
s = new Setting(
"settingName",
"package_multi_select",
"modelSelect",
"cutoff",
"evalType",
"availableTS",
"forms",
"truncatorTable",
"summaryTable",
);
$(function () {
// hide all forms
$("#forms").children().hide();
$("#render-button").on("click", function () {
syncKetcherAndTextInput("text", "ifKetcher", "smilesinput");
});
// If theres a change in the in '#smilesinput' sync the value to ketcher
$("#smilesinput").on("input", function () {
syncKetcherAndTextInput("text", "ifKetcher", "smilesinput");
});
// If theres an update in ketcher sync it to textinput
setInterval(function () {
syncKetcherAndTextInput("ketcher", "ifKetcher", "smilesinput");
}, 250);
$("#smilesinput").on("blur", function () {
syncKetcherAndTextInput("text", "ifKetcher", "smilesinput");
});
$("#smilesinput").on("keypress", function (event) {
if (event.keyCode == 13) {
syncKetcherAndTextInput("text", "ifKetcher", "smilesinput");
}
});
// Show forms depending on the selected TS
$("#availableTS").on("change", function (e) {
e.preventDefault();
var type = $(this).val();
// hide current content
$("#forms").children().hide();
if (type === "") {
return;
}
$("#" + type + "_form").show();
});
$("#modelSelect").on("change", function () {
setCutoff = function (thresh) {
$("#cutoff").val(thresh);
};
var modelUri = $("#modelSelect :selected").val();
fillPRCurve(modelUri, setCutoff);
});
// Add a TS to the setting
$("#add-ts-button").on("click", function (e) {
e.preventDefault();
s.addTruncator();
});
$("input[type=radio][name=predict]").change(function () {
if (this.id == "radioBuild") {
$("#nextbutton").prop("disabled", true);
} else {
$("#nextbutton").prop("disabled", false);
}
});
$("input[type=radio][name=existing]").change(function () {
if (this.id == "radioDefault" || this.id == "radioExists") {
if (this.id == "radioDefault") {
$("#settingSelect").prop("disabled", true);
} else {
$("#settingSelect").prop("disabled", false);
}
$("#nextbutton").prop("disabled", true);
} else {
// build...
$("#settingSelect").prop("disabled", true);
$("#nextbutton").prop("disabled", false);
}
});
var pwStep1 = function () {
console.log("pw step 1");
// Make "Next" to "Advanced"
$("#nextbutton").val("Advanced");
};
var pwStep2 = function () {
console.log("pw step 2");
// Make "Advanced" to "Next"
$("#nextbutton").val("Next");
// As "Use default is preselected" disable "Next" button
$("#nextbutton").prop("disabled", true);
// Disable setting dropdown as long as the correspndonding radio isnt checked
$("#settingSelect").prop("disabled", true);
// Show submit button
$("#modal-form-submit").show();
};
var settingStep1 = function () {
// First step sets name and packages
s.extractName();
s.extractSelectedPackages();
};
var settingStep2 = function () {
// Seconds step gathers relative reasoning params
s.extractRelativeReasoning();
s.extractCutoff();
s.extractEvaluationType();
};
var settingStep3 = function () {
s.updateTable();
s.updateSummaryTable();
// hide duplicate submit...
$("#nextbutton").hide();
};
var postPathway = function () {
console.log("Complete!");
console.log(s.tsParams);
console.log("Getting SMILES");
};
function dummy() {
console.log("dummy");
}
$("#new_pathway_modal").modalSteps({
btnCancelHtml: "Cancel",
btnPreviousHtml: "Back",
btnNextHtml: "Next",
btnLastStepHtml: "Submit",
disableNextButton: false,
completeCallback: postPathway,
callbacks: {
1: pwStep1,
2: pwStep2,
3: dummy,
4: settingStep1,
5: settingStep2,
6: settingStep3,
},
});
$("#modal-form-submit").on("click", function () {
e.preventDefault();
postPathway();
});
});
</script>

View File

@ -1,185 +1,260 @@
{% load static %}
<div id="new_prediction_setting_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Create a Prediction Setting</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>
To create a Prediction Setting fill the form below and click "Create"
</p>
<form
id="new-prediction-setting-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<dialog
id="new_prediction_setting_modal"
class="modal"
x-data="{
isSubmitting: false,
tpMethod: '',
<label for="prediction-setting-name">Name</label>
reset() {
this.isSubmitting = false;
this.tpMethod = '';
},
async submit() {
const form = document.getElementById('new-prediction-setting-modal-form');
if (!form.checkValidity()) {
form.reportValidity();
return;
}
this.isSubmitting = true;
const formData = new FormData(form);
try {
const response = await fetch('/setting', {
method: 'POST',
body: new URLSearchParams(formData)
});
if (response.ok) {
location.reload();
}
} catch (error) {
console.error('Error creating setting:', error);
} finally {
this.isSubmitting = false;
}
}
}"
@close="reset()"
>
<div class="modal-box max-w-2xl">
<!-- Header -->
<h3 class="text-lg font-bold">Create a Prediction Setting</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p class="mb-4">
To create a Prediction Setting fill the form below and click "Create"
</p>
<form
id="new-prediction-setting-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="prediction-setting-name">
<span class="label-text">Name</span>
</label>
<input
id="prediction-setting-name"
name="prediction-setting-name"
class="form-control"
class="input input-bordered w-full"
placeholder="Name"
required
/>
<label for="prediction-setting-description">Description</label>
</div>
<div class="form-control mb-3">
<label class="label" for="prediction-setting-description">
<span class="label-text">Description</span>
</label>
<input
id="prediction-setting-description"
name="prediction-setting-description"
class="form-control"
class="input input-bordered w-full"
placeholder="Description"
/>
</div>
<label for="prediction-setting-max-nodes">Max #Nodes</label>
<div class="form-control mb-3">
<label class="label" for="prediction-setting-max-nodes">
<span class="label-text">Max #Nodes</span>
</label>
<input
id="prediction-setting-max-nodes"
type="number"
class="form-control"
class="input input-bordered w-full"
name="prediction-setting-max-nodes"
value="30"
min="1"
max="50"
step="1"
/>
<label for="prediction-setting-max-depth">Max Depth</label>
</div>
<div class="form-control mb-3">
<label class="label" for="prediction-setting-max-depth">
<span class="label-text">Max Depth</span>
</label>
<input
id="prediction-setting-max-depth"
type="number"
class="form-control"
class="input input-bordered w-full"
name="prediction-setting-max-depth"
value="5"
min="1"
max="8"
step="1"
/>
</div>
<label for="tp-generation-method">TP Generation Method</label>
<div class="form-control mb-3">
<label class="label" for="tp-generation-method">
<span class="label-text">TP Generation Method</span>
</label>
<select
id="tp-generation-method"
name="tp-generation-method"
class="form-control"
data-width="100%"
class="select select-bordered w-full"
x-model="tpMethod"
required
>
<option disabled selected>Select how TPs are generated</option>
<option value="" disabled selected>
Select how TPs are generated
</option>
<option value="rule-based-prediction-setting">Rule Based</option>
<option value="model-based-prediction-setting">Model Based</option>
</select>
<div id="rule-based-prediction-setting-specific-form">
<!-- Rule Packages -->
<label>Rule Packages</label><br />
</div>
<!-- Rule Based Settings -->
<div x-show="tpMethod === 'rule-based-prediction-setting'" x-cloak>
<div class="form-control mb-3">
<label class="label">
<span class="label-text">Rule Packages</span>
</label>
<select
id="rule-based-prediction-setting-packages"
name="rule-based-prediction-setting-packages"
data-actions-box="true"
class="form-control"
class="select select-bordered w-full h-32"
multiple
data-width="100%"
>
<option disabled>Reviewed Packages</option>
{% for obj in meta.readable_packages %}
{% if obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %}
{% endfor %}
<option disabled>Unreviewed Packages</option>
{% for obj in meta.readable_packages %}
{% if not obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %}
{% endfor %}
<optgroup label="Reviewed Packages">
{% for obj in meta.readable_packages %}
{% if obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %}
{% endfor %}
</optgroup>
<optgroup label="Unreviewed Packages">
{% for obj in meta.readable_packages %}
{% if not obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %}
{% endfor %}
</optgroup>
</select>
<label class="label">
<span class="label-text-alt"
>Hold Ctrl/Cmd to select multiple</span
>
</label>
</div>
<div id="model-based-prediction-setting-specific-form">
<label>Select Model</label><br />
</div>
<!-- Model Based Settings -->
<div x-show="tpMethod === 'model-based-prediction-setting'" x-cloak>
<div class="form-control mb-3">
<label class="label" for="model-based-prediction-setting-model">
<span class="label-text">Select Model</span>
</label>
<select
id="model-based-prediction-setting-model"
name="model-based-prediction-setting-model"
class="form-control"
data-width="100%"
class="select select-bordered w-full"
>
<option disabled selected>Select the model</option>
<option value="" disabled selected>Select the model</option>
{% for m in models %}
<option value="{{ m.url }}">{{ m.name|safe }}</option>
{% endfor %}
</select>
<label for="model-based-prediction-setting-threshold"
>Threshold</label
>
</div>
<div class="form-control mb-3">
<label class="label" for="model-based-prediction-setting-threshold">
<span class="label-text">Threshold</span>
</label>
<input
id="model-based-prediction-setting-threshold"
name="model-based-prediction-setting-threshold"
class="form-control"
class="input input-bordered w-full"
placeholder="0.25"
type="number"
min="0"
max="1"
step="0.05"
/>
</div>
</div>
<input
class="form-check-input"
type="checkbox"
value="on"
id="prediction-setting-new-default"
name="prediction-setting-new-default"
/>
<label class="form-check-label" for="prediction-setting-new-default"
>Set this setting as new default</label
>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="new-prediction-setting-modal-submit"
>
Create
</button>
</div>
<div class="form-control">
<label class="label cursor-pointer justify-start gap-3">
<input
type="checkbox"
class="checkbox"
value="on"
id="prediction-setting-new-default"
name="prediction-setting-new-default"
/>
<span class="label-text">Set this setting as new default</span>
</label>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit()"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Create</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Creating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
// Initially hide all "specific" forms
$("div[id$='-specific-form']").each(function () {
$(this).hide();
});
$("#rule-based-prediction-setting-packages").selectpicker();
// On change hide all and show only selected
$("#tp-generation-method").change(function () {
$("div[id$='-specific-form']").each(function () {
$(this).hide();
});
val = $("option:selected", this).val();
$("#" + val + "-specific-form").show();
});
$("#new-prediction-setting-modal-submit").click(function (e) {
e.preventDefault();
// $('#new-prediction-setting-modal-form').submit();
const formData = $("#new-prediction-setting-modal-form").serialize();
$.post("/setting", formData, function (response) {
location.reload();
});
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,91 +1,105 @@
{% load static %}
<div
class="modal fade bs-modal-lg"
<dialog
id="new_reaction_modal"
tabindex="-1"
aria-labelledby="new_reaction_modal"
aria-modal="true"
role="dialog"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Create a new Reaction</h4>
</div>
<div class="modal-body">
<form
id="new_reaction_modal_form"
accept-charset="UTF-8"
action="{% url 'package reaction list' meta.current_package.uuid %}"
data-remote="true"
method="post"
>
{% csrf_token %}
<label for="reaction-name">Name</label>
<div class="modal-box max-w-3xl">
<!-- Header -->
<h3 class="font-bold text-lg">Create a new Reaction</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="new-reaction-modal-form"
accept-charset="UTF-8"
action="{% url 'package reaction list' meta.current_package.uuid %}"
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="reaction-name">
<span class="label-text">Name</span>
</label>
<input
id="reaction-name"
class="form-control"
class="input input-bordered w-full"
name="reaction-name"
placeholder="Name"
required
/>
<label for="reaction-description">Description</label>
</div>
<div class="form-control mb-3">
<label class="label" for="reaction-description">
<span class="label-text">Description</span>
</label>
<input
id="reaction-description"
class="form-control"
class="input input-bordered w-full"
name="reaction-description"
placeholder="Description"
/>
<p></p>
<div>
<iframe
id="new_reaction_ketcher"
src="{% static '/js/ketcher2/ketcher.html' %}"
width="100%"
height="510"
></iframe>
</div>
<input type="hidden" name="reaction-smirks" id="reaction-smirks" />
<p></p>
</form>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary pull-left"
data-dismiss="modal"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
id="new_reaction_modal_form_submit"
>
Submit
</button>
</div>
</div>
<div class="mb-3">
<iframe
id="new_reaction_ketcher"
src="{% static '/js/ketcher2/ketcher.html' %}"
width="100%"
height="510"
></iframe>
</div>
<input type="hidden" name="reaction-smirks" id="reaction-smirks" />
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="
const k = getKetcher('new_reaction_ketcher');
document.getElementById('reaction-smirks').value = k.getSmiles();
submit('new-reaction-modal-form');
"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Creating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#new_reaction_modal_form_submit").on("click", function (e) {
e.preventDefault();
$(this).prop("disabled", true);
k = getKetcher("new_reaction_ketcher");
$("#reaction-smirks").val(k.getSmiles());
// submit form
$("#new_reaction_modal_form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,120 +1,140 @@
{% load static %}
<div
class="modal fade bs-modal-lg"
<dialog
id="new_rule_modal"
tabindex="-1"
aria-labelledby="new_rule_modal"
aria-modal="true"
role="dialog"
class="modal"
x-data="{
...modalForm(),
smirksVizHtml: '',
updateSmirksViz() {
const smirks = document.getElementById('rule-smirks').value;
if (!smirks) {
this.smirksVizHtml = '';
return;
}
const img = new Image();
img.src = '{% url 'depict' %}?is_query_smirks=true&smirks=' + encodeURIComponent(smirks);
img.style.width = '100%';
img.style.height = '100%';
img.style.objectFit = 'cover';
img.onload = () => {
this.smirksVizHtml = img.outerHTML;
};
img.onerror = () => {
this.smirksVizHtml = `
<div class='alert alert-error' role='alert'>
<h4 class='alert-heading'>Could not render SMIRKS!</h4>
<p>Could not render SMIRKS - Have you entered a valid SMIRKS?</p>
</div>`;
};
}
}"
@close="reset(); smirksVizHtml = ''"
>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Create a new Rule</h4>
</div>
<div class="modal-body">
<form
id="new_rule_modal_form"
accept-charset="UTF-8"
action="{% url 'package rule list' meta.current_package.uuid %}"
data-remote="true"
method="post"
>
{% csrf_token %}
<label for="rule-name">Name</label>
<div class="modal-box max-w-3xl">
<!-- Header -->
<h3 class="font-bold text-lg">Create a new Rule</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="new-rule-modal-form"
accept-charset="UTF-8"
action="{% url 'package rule list' meta.current_package.uuid %}"
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="rule-name">
<span class="label-text">Name</span>
</label>
<input
id="rule-name"
class="form-control"
class="input input-bordered w-full"
name="rule-name"
placeholder="Name"
required
/>
<label for="rule-description">Description</label>
</div>
<div class="form-control mb-3">
<label class="label" for="rule-description">
<span class="label-text">Description</span>
</label>
<input
id="rule-description"
class="form-control"
class="input input-bordered w-full"
name="rule-description"
placeholder="Description"
/>
<label for="rule-smirks">SMIRKS</label>
</div>
<div class="form-control mb-3">
<label class="label" for="rule-smirks">
<span class="label-text">SMIRKS</span>
</label>
<input
id="rule-smirks"
class="form-control"
class="input input-bordered w-full"
name="rule-smirks"
placeholder="SMIRKS"
@input="updateSmirksViz()"
/>
<p></p>
<div id="rule-smirks-viz"></div>
<input
type="hidden"
name="rule-type"
id="rule-type"
value="SimpleAmbitRule"
/>
<p></p>
</form>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary pull-left"
data-dismiss="modal"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
id="new_rule_modal_form_submit"
>
Submit
</button>
</div>
</div>
<div id="rule-smirks-viz" class="mb-3" x-html="smirksVizHtml"></div>
<input
type="hidden"
name="rule-type"
id="rule-type"
value="SimpleAmbitRule"
/>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('new-rule-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Creating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#rule-smirks").on("input", function (e) {
$("#rule-smirks-viz").empty();
smirks = $("#rule-smirks").val();
const img = new Image();
img.src =
"{% url 'depict' %}?is_query_smirks=true&smirks=" +
encodeURIComponent(smirks);
img.style.width = "100%";
img.style.height = "100%";
img.style.objectFit = "cover";
img.onload = function () {
$("#rule-smirks-viz").append(img);
};
img.onerror = function () {
error_tpl = `
<div class="alert alert-error" role="alert">
<h4 class="alert-heading">Could not render SMIRKS!</h4>
<p>Could not render SMIRKS - Have you entered a valid SMIRKS?</a>
</p>
</div>`;
$("#rule-smirks-viz").append(error_tpl);
};
});
$("#new_rule_modal_form_submit").on("click", function (e) {
e.preventDefault();
$(this).prop("disabled", true);
// submit form
$("#new_rule_modal_form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,30 +1,45 @@
<div
class="modal fade"
tabindex="-1"
{% load static %}
<dialog
id="new_scenario_modal"
role="dialog"
aria-labelledby="new_scenario_modal"
aria-hidden="true"
class="modal"
x-data="{
...modalForm(),
scenarioType: 'empty',
validateYear(el) {
if (el.value && el.value.length < 4) {
el.value = new Date().getFullYear();
}
}
}"
@close="reset()"
>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title">New Scenario</h4>
</div>
<div class="modal-body">
<form
id="new_scenario_form"
accept-charset="UTF-8"
action="{{ meta.current_package.url }}/scenario"
data-remote="true"
method="post"
>
{% csrf_token %}
<div class="jumbotron">
<div class="modal-box max-w-3xl">
<!-- Header -->
<h3 class="font-bold text-lg">New Scenario</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="new-scenario-modal-form"
accept-charset="UTF-8"
action="{{ meta.current_package.url }}/scenario"
method="post"
>
{% csrf_token %}
<div class="alert alert-info mb-4">
<span>
Please enter name, description, and date of scenario. Date should be
associated to the data, not the current date. For example, this
could reflect the publishing date of a study. You can leave all
@ -32,122 +47,131 @@
<a
target="_blank"
href="https://wiki.envipath.org/index.php/scenario"
role="button"
class="link"
>wiki &gt;&gt;</a
>
</div>
<label for="scenario-name">Name</label>
</span>
</div>
<div class="form-control mb-3">
<label class="label" for="scenario-name">
<span class="label-text">Name</span>
</label>
<input
id="scenario-name"
name="scenario-name"
class="form-control"
class="input input-bordered w-full"
placeholder="Name"
required
/>
<label for="scenario-description">Description</label>
</div>
<div class="form-control mb-3">
<label class="label" for="scenario-description">
<span class="label-text">Description</span>
</label>
<input
id="scenario-description"
name="scenario-description"
class="form-control"
class="input input-bordered w-full"
placeholder="Description"
/>
<label id="dateField" for="dateYear">Date</label>
<table>
<tr>
<th>
<input
type="number"
id="dateYear"
name="scenario-date-year"
class="form-control"
placeholder="YYYY"
max="{% now "Y" %}"
/>
</th>
<th>
<input
type="number"
id="dateMonth"
name="scenario-date-month"
min="1"
max="12"
class="form-control"
placeholder="MM"
/>
</th>
<th>
<input
type="number"
id="dateDay"
name="scenario-date-day"
min="1"
max="31"
class="form-control"
placeholder="DD"
/>
</th>
</tr>
</table>
<label for="scenario-type">Scenario Type</label>
</div>
<div class="form-control mb-3">
<label class="label">
<span class="label-text">Date</span>
</label>
<div class="flex gap-2">
<input
type="number"
id="dateYear"
name="scenario-date-year"
class="input input-bordered w-24"
placeholder="YYYY"
max="{% now 'Y' %}"
@blur="validateYear($el)"
/>
<input
type="number"
id="dateMonth"
name="scenario-date-month"
min="1"
max="12"
class="input input-bordered w-20"
placeholder="MM"
/>
<input
type="number"
id="dateDay"
name="scenario-date-day"
min="1"
max="31"
class="input input-bordered w-20"
placeholder="DD"
/>
</div>
</div>
<div class="form-control mb-3">
<label class="label" for="scenario-type">
<span class="label-text">Scenario Type</span>
</label>
<select
id="scenario-type"
name="scenario-type"
class="form-control"
data-width="100%"
class="select select-bordered w-full"
x-model="scenarioType"
>
<option value="empty" selected>Empty Scenario</option>
{% for k, v in scenario_types.items %}
<option value="{{ v.name }}">{{ k }}</option>
{% endfor %}
</select>
</div>
{% for type in scenario_types.values %}
<div id="{{ type.name }}-specific-inputs">
{% for widget in type.widgets %}
{{ widget|safe }}
{% endfor %}
</div>
{% endfor %}
</form>
</div>
<div class="modal-footer">
<a id="new_scenario_modal_form_submit" class="btn btn-primary" href="#"
>Submit</a
>
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
</div>
{% for type in scenario_types.values %}
<div
id="{{ type.name }}-specific-inputs"
x-show="scenarioType === '{{ type.name }}'"
x-cloak
>
{% for widget in type.widgets %}
{{ widget|safe }}
{% endfor %}
</div>
{% endfor %}
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Cancel
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('new-scenario-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Creating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
// Initially hide all "specific" forms
$("div[id$='-specific-inputs']").each(function () {
$(this).hide();
});
// On change hide all and show only selected
$("#scenario-type").change(function () {
$("div[id$='-specific-inputs']").each(function () {
$(this).hide();
});
val = $("option:selected", this).val();
$("#" + val + "-specific-inputs").show();
});
$("#new_scenario_modal_form_submit").on("click", function (e) {
e.preventDefault();
$("#new_scenario_form").submit();
});
var dateYear = document.getElementById("dateYear");
dateYear.addEventListener("change", () => {
console.log("Final value after editing:", dateYear.value);
if (dateYear.value.length < 4) {
dateYear.value = new Date().getFullYear();
}
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,92 +1,117 @@
{% load static %}
<!-- Add Additional Information-->
<div id="add_additional_information_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
<h3 class="modal-title">Add Additional Information</h3>
</div>
<div class="modal-body">
<!-- Add Additional Information -->
<dialog
id="add_additional_information_modal"
class="modal"
x-data="{
isSubmitting: false,
selectedType: '',
reset() {
this.isSubmitting = false;
this.selectedType = '';
},
submit() {
if (!this.selectedType) return;
const form = document.getElementById('add_' + this.selectedType + '_add-additional-information-modal-form');
if (form && form.checkValidity()) {
this.isSubmitting = true;
form.submit();
} else if (form) {
form.reportValidity();
}
}
}"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="text-lg font-bold">Add Additional Information</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<div class="form-control">
<label class="label" for="select-additional-information-type">
<span class="label-text">Select the type to add</span>
</label>
<select
id="select-additional-information-type"
data-actions-box="true"
class="form-control"
data-width="100%"
class="select select-bordered w-full"
x-model="selectedType"
>
<option selected disabled>Select the type to add</option>
<option value="" selected disabled>Select the type to add</option>
{% for add_inf in available_additional_information %}
<option value="{{ add_inf.name }}">
{{ add_inf.display_name }}
</option>
{% endfor %}
</select>
{% for add_inf in available_additional_information %}
<div class="aiform {{ add_inf.name }}" style="display: none;">
<form
id="add_{{ add_inf.name }}_add-additional-information-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
{{ add_inf.widget|safe }}
<input
type="hidden"
name="hidden"
value="add-additional-information"
/>
</form>
</div>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="add-additional-information-modal-submit"
{% for add_inf in available_additional_information %}
<div
class="mt-4"
x-show="selectedType === '{{ add_inf.name }}'"
x-cloak
>
Add
</button>
</div>
<form
id="add_{{ add_inf.name }}_add-additional-information-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
{{ add_inf.widget|safe }}
<input
type="hidden"
name="hidden"
value="add-additional-information"
/>
</form>
</div>
{% endfor %}
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit()"
:disabled="isSubmitting || !selectedType"
>
<span x-show="!isSubmitting">Add</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Adding...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#select-additional-information-type").change(function (e) {
var selectedType = $(
"#select-additional-information-type :selected",
).val();
$(".aiform").hide();
$("." + selectedType).show();
});
$("#add-additional-information-modal-submit").click(function (e) {
e.preventDefault();
var selectedType = $(
"#select-additional-information-type :selected",
).val();
console.log(selectedType);
if (
selectedType !== null &&
selectedType !== undefined &&
selectedType !== ""
) {
$("." + selectedType + " >form").submit();
}
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,67 +1,107 @@
{% load static %}
<div
class="modal fade bs-modal-lg"
<dialog
id="add_pathway_edge_modal"
tabindex="-1"
aria-labelledby="add_pathway_edge_modal"
aria-modal="true"
role="dialog"
class="modal"
x-data="{
isSubmitting: false,
reactionImageUrl: '',
reset() {
this.isSubmitting = false;
this.reactionImageUrl = '';
},
updateReactionImage() {
const substratesSelect = document.getElementById('add_pathway_edge_substrates');
const productsSelect = document.getElementById('add_pathway_edge_products');
const substrates = [];
for (const option of substratesSelect.selectedOptions) {
substrates.push(option.dataset.smiles);
}
const products = [];
for (const option of productsSelect.selectedOptions) {
products.push(option.dataset.smiles);
}
if (substrates.length > 0 && products.length > 0) {
const reaction = substrates.join('.') + '>>' + products.join('.');
this.reactionImageUrl = '{% url "depict" %}?smirks=' + encodeURIComponent(reaction);
} else {
this.reactionImageUrl = '';
}
},
submit() {
this.isSubmitting = true;
document.getElementById('add_pathway_edge_modal_form').submit();
}
}"
@close="reset()"
>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">Add a Reaction</h4>
</div>
<div class="modal-body">
<form
id="add_pathway_edge_modal_form"
accept-charset="UTF-8"
action="{% url 'package pathway edge list' meta.current_package.uuid pathway.uuid %}"
data-remote="true"
method="post"
>
{% csrf_token %}
<label for="edge-name">Name</label>
<div class="modal-box max-w-4xl">
<!-- Header -->
<h3 class="text-lg font-bold">Add a Reaction</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="add_pathway_edge_modal_form"
accept-charset="UTF-8"
action="{% url 'package pathway edge list' meta.current_package.uuid pathway.uuid %}"
data-remote="true"
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="edge-name">
<span class="label-text">Name</span>
</label>
<input
id="edge-name"
class="form-control"
type="text"
class="input input-bordered w-full"
name="edge-name"
placeholder="Name"
/>
<label for="edge-description">Description</label>
</div>
<div class="form-control mb-3">
<label class="label" for="edge-description">
<span class="label-text">Description</span>
</label>
<input
id="edge-description"
class="form-control"
type="text"
class="input input-bordered w-full"
name="edge-description"
placeholder="Description"
/>
<p></p>
<div class="row">
<div class="col-xs-5">
<legend>Substrate(s)</legend>
</div>
<div class="col-xs-2"></div>
<div class="col-xs-5">
<legend>Product(s)</legend>
</div>
</div>
<div class="row">
<div class="col-xs-5">
</div>
<div class="mb-3 grid grid-cols-11 gap-2">
<div class="col-span-5">
<div class="form-control">
<label class="label">
<span class="label-text font-semibold">Substrate(s)</span>
</label>
<select
id="add_pathway_edge_substrates"
name="edge-substrates"
data-actions-box="true"
class="form-control"
class="select select-bordered h-32 w-full"
multiple
data-width="100%"
@change="updateReactionImage()"
>
{% for n in pathway.nodes %}
<option
@ -73,20 +113,21 @@
{% endfor %}
</select>
</div>
<div
class="col-xs-2"
style="display: flex; justify-content: center; align-items: center;"
>
<i class="glyphicon glyphicon-arrow-right"></i>
</div>
<div class="col-xs-5">
</div>
<div class="col-span-1 flex items-center justify-center">
<span class="text-2xl"></span>
</div>
<div class="col-span-5">
<div class="form-control">
<label class="label">
<span class="label-text font-semibold">Product(s)</span>
</label>
<select
id="add_pathway_edge_products"
name="edge-products"
data-actions-box="true"
class="form-control"
class="select select-bordered h-32 w-full"
multiple
data-width="100%"
@change="updateReactionImage()"
>
{% for n in pathway.nodes %}
<option
@ -99,76 +140,42 @@
</select>
</div>
</div>
<div class="row">
<p></p>
<div class="col-xs-12" id="reaction_image"></div>
</div>
</form>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary pull-left"
data-dismiss="modal"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
id="add_pathway_edge_modal_form_submit"
>
Submit
</button>
</div>
</div>
<div class="mb-3" x-show="reactionImageUrl" x-cloak>
<img :src="reactionImageUrl" class="w-full" alt="Reaction preview" />
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit()"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Submitting...</span>
</button>
</div>
</div>
</div>
<script>
function reactionImage() {
var substrates = [];
$("#add_pathway_edge_substrates option:selected").each(function () {
var smiles = $(this).data("smiles"); // read data-smiles attribute
substrates.push(smiles);
});
var products = [];
$("#add_pathway_edge_products option:selected").each(function () {
var smiles = $(this).data("smiles"); // read data-smiles attribute
products.push(smiles);
});
if (substrates.length > 0 && products.length > 0) {
reaction = substrates.join(".") + ">>" + products.join(".");
$("#reaction_image").empty();
$("#reaction_image").append(
"<img width='100%' src='{% url 'depict' %}?smirks=" +
encodeURIComponent(reaction) +
"'>",
);
}
}
$(function () {
$("#add_pathway_edge_substrates").selectpicker();
$("#add_pathway_edge_products").selectpicker();
$("#add_pathway_edge_substrates").on("change", function (e) {
reactionImage();
});
$("#add_pathway_edge_products").on("change", function (e) {
reactionImage();
});
$(function () {
$("#add_pathway_edge_modal_form_submit").on("click", function (e) {
e.preventDefault();
$(this).prop("disabled", true);
// submit form
$("#add_pathway_edge_modal_form").submit();
});
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,119 +1,137 @@
{% load static %}
<div
class="modal fade bs-modal-lg"
<dialog
id="add_pathway_node_modal"
tabindex="-1"
aria-labelledby="add_pathway_node_modal"
aria-modal="true"
role="dialog"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">Add a Node</h4>
</div>
<div class="modal-body">
<form
id="add_pathway_node_modal_form"
accept-charset="UTF-8"
action="{% url 'package pathway node list' meta.current_package.uuid pathway.uuid %}"
data-remote="true"
method="post"
>
{% csrf_token %}
<label for="node-name">Name</label>
<div class="modal-box max-w-4xl">
<!-- Header -->
<h3 class="text-lg font-bold">Add a Node</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="add_pathway_node_modal_form"
accept-charset="UTF-8"
action="{% url 'package pathway node list' meta.current_package.uuid pathway.uuid %}"
data-remote="true"
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="node-name">
<span class="label-text">Name</span>
</label>
<input
id="node-name"
class="form-control"
type="text"
class="input input-bordered w-full"
name="node-name"
placeholder="Name"
/>
<label for="node-description">Description</label>
</div>
<div class="form-control mb-3">
<label class="label" for="node-description">
<span class="label-text">Description</span>
</label>
<input
id="node-description"
class="form-control"
type="text"
class="input input-bordered w-full"
name="node-description"
placeholder="Description"
/>
<label for="node-smiles">SMILES</label>
</div>
<div class="form-control mb-3">
<label class="label" for="node-smiles">
<span class="label-text">SMILES</span>
</label>
<input
type="text"
class="form-control"
class="input input-bordered w-full"
name="node-smiles"
placeholder="SMILES"
id="node-smiles"
/>
<p></p>
<div>
<iframe
id="add_node_ketcher"
src="{% static '/js/ketcher2/ketcher.html' %}"
width="100%"
height="510"
></iframe>
</div>
<p></p>
</form>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary pull-left"
data-dismiss="modal"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
id="add_pathway_node_modal_form_submit"
>
Submit
</button>
</div>
</div>
<div class="mb-3">
<iframe
id="add_node_ketcher"
src="{% static '/js/ketcher2/ketcher.html' %}"
width="100%"
height="510"
></iframe>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('add_pathway_node_modal_form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Submitting...</span>
</button>
</div>
</div>
</div>
<script>
function newStructureModalketcherToNewStructureModalTextInput() {
$("#node-smiles").val(this.ketcher.getSmiles());
}
$(function () {
$("#add_node_ketcher").on("load", function () {
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>
<script>
document
.getElementById("add_node_ketcher")
.addEventListener("load", function () {
const iframe = this;
const checkKetcherReady = () => {
win = this.contentWindow;
const win = iframe.contentWindow;
if (win.ketcher && "editor" in win.ketcher) {
win.ketcher.editor.event.change.handlers.push({
once: false,
priority: 0,
f: newStructureModalketcherToNewStructureModalTextInput,
f: function () {
document.getElementById("node-smiles").value =
this.ketcher.getSmiles();
},
ketcher: win.ketcher,
});
} else {
setTimeout(checkKetcherReady, 100);
}
};
checkKetcherReady();
});
$(function () {
$("#add_pathway_node_modal_form_submit").on("click", function (e) {
e.preventDefault();
$(this).prop("disabled", true);
// submit form
$("#add_pathway_node_modal_form").submit();
});
});
});
</script>

View File

@ -1,119 +1,137 @@
{% load static %}
<div
class="modal fade bs-modal-lg"
<dialog
id="add_structure_modal"
tabindex="-1"
aria-labelledby="add_structure_modal"
aria-modal="true"
role="dialog"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Create a new Structure</h4>
</div>
<div class="modal-body">
<form
id="add_structure_modal_form"
accept-charset="UTF-8"
action="{% url 'package compound structure list' meta.current_package.uuid compound.uuid %}"
data-remote="true"
method="post"
>
{% csrf_token %}
<label for="structure-name">Name</label>
<div class="modal-box max-w-4xl">
<!-- Header -->
<h3 class="text-lg font-bold">Create a new Structure</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="add_structure_modal_form"
accept-charset="UTF-8"
action="{% url 'package compound structure list' meta.current_package.uuid compound.uuid %}"
data-remote="true"
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="structure-name">
<span class="label-text">Name</span>
</label>
<input
id="structure-name"
class="form-control"
type="text"
class="input input-bordered w-full"
name="structure-name"
placeholder="Name"
/>
<label for="structure-description">Description</label>
</div>
<div class="form-control mb-3">
<label class="label" for="structure-description">
<span class="label-text">Description</span>
</label>
<input
id="structure-description"
class="form-control"
type="text"
class="input input-bordered w-full"
name="structure-description"
placeholder="Description"
/>
<label for="structure-smiles">SMILES</label>
</div>
<div class="form-control mb-3">
<label class="label" for="structure-smiles">
<span class="label-text">SMILES</span>
</label>
<input
type="text"
class="form-control"
class="input input-bordered w-full"
name="structure-smiles"
placeholder="SMILES"
id="structure-smiles"
/>
<p></p>
<div>
<iframe
id="add_structure_ketcher"
src="{% static '/js/ketcher2/ketcher.html' %}"
width="100%"
height="510"
></iframe>
</div>
<p></p>
</form>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary pull-left"
data-dismiss="modal"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
id="add_structure_modal_form_submit"
>
Submit
</button>
</div>
</div>
<div class="mb-3">
<iframe
id="add_structure_ketcher"
src="{% static '/js/ketcher2/ketcher.html' %}"
width="100%"
height="510"
></iframe>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('add_structure_modal_form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Submitting...</span>
</button>
</div>
</div>
</div>
<script>
function newStructureModalketcherToNewStructureModalTextInput() {
$("#structure-smiles").val(this.ketcher.getSmiles());
}
$(function () {
$("#add_structure_ketcher").on("load", function () {
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>
<script>
document
.getElementById("add_structure_ketcher")
.addEventListener("load", function () {
const iframe = this;
const checkKetcherReady = () => {
win = this.contentWindow;
const win = iframe.contentWindow;
if (win.ketcher && "editor" in win.ketcher) {
win.ketcher.editor.event.change.handlers.push({
once: false,
priority: 0,
f: newStructureModalketcherToNewStructureModalTextInput,
f: function () {
document.getElementById("structure-smiles").value =
this.ketcher.getSmiles();
},
ketcher: win.ketcher,
});
} else {
setTimeout(checkKetcherReady, 100);
}
};
checkKetcherReady();
});
$(function () {
$("#add_structure_modal_form_submit").on("click", function (e) {
e.preventDefault();
$(this).prop("disabled", true);
// submit form
$("#add_structure_modal_form").submit();
});
});
});
</script>

View File

@ -1,36 +1,48 @@
{% load static %}
<!-- Delete Edge -->
<div id="delete_pathway_edge_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Delete Edge</h3>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<dialog
id="delete_pathway_edge_modal"
class="modal"
x-data="modalForm({ state: { selectedEdge: '', imageUrl: '' } })"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="text-lg font-bold">Delete Edge</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p class="mb-4">
Deletes the Edge. Nodes referenced by this edge will remain.
<p></p>
<form
id="delete-pathway-edge-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
</p>
<form
id="delete-pathway-edge-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<div class="form-control">
<label class="label" for="delete_pathway_edge_edges">
<span class="label-text">Select Reaction to delete</span>
</label>
<select
id="delete_pathway_edge_edges"
name="edge-url"
data-actions-box="true"
class="form-control"
data-width="100%"
class="select select-bordered w-full"
x-model="selectedEdge"
@change="imageUrl = selectedEdge ? selectedEdge + '?image=svg' : ''"
required
>
<option value="" disabled selected>
Select Reaction to delete
@ -39,51 +51,44 @@
<option value="{{ e.url }}">{{ e.edge_label.name|safe }}</option>
{% endfor %}
</select>
<input type="hidden" id="hidden" name="hidden" value="delete" />
</form>
<p></p>
<div id="delete_pathway_edge_image"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="delete-pathway-edge-modal-submit"
>
Delete
</button>
</div>
<input type="hidden" id="hidden" name="hidden" value="delete" />
</form>
<!-- Image Preview -->
<div class="mt-4" x-show="imageUrl" x-cloak>
<img :src="imageUrl" class="w-full" alt="Edge preview" />
</div>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-error"
@click="setFormAction('delete-pathway-edge-modal-form', selectedEdge); submit('delete-pathway-edge-modal-form')"
:disabled="isSubmitting || !selectedEdge"
>
<span x-show="!isSubmitting">Delete</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Deleting...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#delete_pathway_edge_edges").selectpicker();
$("#delete_pathway_edge_edges").on("change", function (e) {
edge_url = $("#delete_pathway_edge_edges option:selected").val();
if (edge_url !== "") {
$("#delete_pathway_edge_image").empty();
$("#delete_pathway_edge_image").append(
"<img width='100%' src='" + edge_url + "?image=svg'>",
);
}
});
$("#delete-pathway-edge-modal-submit").click(function (e) {
e.preventDefault();
edge_url = $("#delete_pathway_edge_edges option:selected").val();
if (edge_url === "") {
return;
}
$("#delete-pathway-edge-modal-form").attr("action", edge_url);
$("#delete-pathway-edge-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,38 +1,49 @@
{% load static %}
<!-- Delete Node -->
<div id="delete_pathway_node_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Delete Node</h3>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<dialog
id="delete_pathway_node_modal"
class="modal"
x-data="modalForm({ state: { selectedNode: '', imageUrl: '' } })"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="text-lg font-bold">Delete Node</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p class="mb-4">
Deletes the Node. Edges having this Node as Substrate or Product will be
removed as well.
<p></p>
<form
id="delete-pathway-node-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
</p>
<form
id="delete-pathway-node-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<div class="form-control">
<label class="label" for="delete_pathway_node_nodes">
<span class="label-text">Select Compound to delete</span>
</label>
<select
id="delete_pathway_node_nodes"
name="node-url"
data-actions-box="true"
class="form-control"
data-width="100%"
class="select select-bordered w-full"
x-model="selectedNode"
@change="imageUrl = selectedNode ? selectedNode + '?image=svg' : ''"
required
>
<option value="" disabled selected>
Select Compound to delete
@ -43,51 +54,44 @@
</option>
{% endfor %}
</select>
<input type="hidden" id="hidden" name="hidden" value="delete" />
</form>
<p></p>
<div id="delete_pathway_node_image"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="delete-pathway-node-modal-submit"
>
Delete
</button>
</div>
<input type="hidden" id="hidden" name="hidden" value="delete" />
</form>
<!-- Image Preview -->
<div class="mt-4" x-show="imageUrl" x-cloak>
<img :src="imageUrl" class="w-full" alt="Node preview" />
</div>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-error"
@click="setFormAction('delete-pathway-node-modal-form', selectedNode); submit('delete-pathway-node-modal-form')"
:disabled="isSubmitting || !selectedNode"
>
<span x-show="!isSubmitting">Delete</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Deleting...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#delete_pathway_node_nodes").selectpicker();
$("#delete_pathway_node_nodes").on("change", function (e) {
node_url = $("#delete_pathway_node_nodes option:selected").val();
if (node_url !== "") {
$("#delete_pathway_node_image").empty();
$("#delete_pathway_node_image").append(
"<img width='100%' src='" + node_url + "?image=svg'>",
);
}
});
$("#delete-pathway-node-modal-submit").click(function (e) {
e.preventDefault();
node_url = $("#delete_pathway_node_nodes option:selected").val();
if (node_url === "") {
return;
}
$("#delete-pathway-node-modal-form").attr("action", node_url);
$("#delete-pathway-node-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,53 +1,69 @@
{% load static %}
<!-- Download Pathway -->
<div id="download_pathway_csv_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Download Pathway as CSV</h3>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<dialog
id="download_pathway_csv_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">Download Pathway as CSV</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p>
By clicking on Download the Pathway will be converted into a CSV and
directly downloaded.
<form
id="download-pathway-csv-modal-form"
accept-charset="UTF-8"
action="{{ pathway.url }}"
data-remote="true"
method="GET"
>
<input type="hidden" name="download" value="true" />
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="download-pathway-csv-modal-submit"
>
Download
</button>
</div>
</p>
<form
id="download-pathway-csv-modal-form"
accept-charset="UTF-8"
action="{{ pathway.url }}"
method="GET"
>
<input type="hidden" name="download" value="true" />
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('download-pathway-csv-modal-form'); $el.closest('dialog').close();"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Download</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#download-pathway-csv-modal-submit").click(function (e) {
e.preventDefault();
$("#download-pathway-csv-modal-form").submit();
$("#download_pathway_csv_modal").modal("hide");
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,43 +1,57 @@
{% load static %}
<!-- Download Pathway -->
<div id="download_pathway_image_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Download Pathway as Image</h3>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
By clicking on Download the Pathway will be saved as SVG.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="download-pathway-image-modal-submit"
>
Download
</button>
</div>
<dialog
id="download_pathway_image_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">Download Pathway as Image</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p>By clicking on Download the Pathway will be saved as SVG.</p>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="isSubmitting = true; downloadSVG(document.getElementById('pwsvg'), '{{ pathway.name.split|join:'_' }}.svg'); $el.closest('dialog').close();"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Download</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#download-pathway-image-modal-submit").click(function (e) {
e.preventDefault();
downloadSVG($("#pwsvg")[0], '{{ pathway.name.split|join:"_" }}.svg');
$("#download_pathway_image_modal").modal("hide");
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,70 +1,91 @@
{% load static %}
<!-- Edit Compound -->
<div id="edit_compound_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit Compound</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Edit Compound.</p>
<form
id="edit-compound-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<p>
<label for="compound-name">Name</label>
<input
id="compound-name"
class="form-control"
name="compound-name"
value="{{ compound.name|safe }}"
/>
</p>
<p>
<label for="compound-description">Description</label>
<input
id="compound-description"
type="text"
class="form-control"
value="{{ compound.description|safe }}"
name="compound-description"
/>
</p>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="edit-compound-modal-submit"
>
Update
</button>
</div>
<dialog
id="edit_compound_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">Edit Compound</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="edit-compound-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="compound-name">
<span class="label-text">Name</span>
</label>
<input
id="compound-name"
class="input input-bordered w-full"
name="compound-name"
value="{{ compound.name|safe }}"
required
/>
</div>
<div class="form-control mb-3">
<label class="label" for="compound-description">
<span class="label-text">Description</span>
</label>
<input
id="compound-description"
type="text"
class="input input-bordered w-full"
value="{{ compound.description|safe }}"
name="compound-description"
/>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('edit-compound-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Update</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Updating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#edit-compound-modal-submit").click(function (e) {
e.preventDefault();
$("#edit-compound-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,70 +1,91 @@
{% load static %}
<!-- Edit Compound -->
<div id="edit_compound_structure_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Create a Compound</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Edit a Compound Structure.</p>
<form
id="edit-compound-structure-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<p>
<label for="compound-structure-name">Name</label>
<input
id="compound-structure-name"
class="form-control"
name="compound-structure-name"
value="{{ compound_structure.name|safe }}"
/>
</p>
<p>
<label for="compound-structure-description">Description</label>
<input
id="compound-structure-description"
type="text"
class="form-control"
value="{{ compound_structure.description|safe }}"
name="compound-structure-description"
/>
</p>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="edit-compound-structure-modal-submit"
>
Create
</button>
</div>
<dialog
id="edit_compound_structure_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">Edit Compound Structure</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="edit-compound-structure-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="compound-structure-name">
<span class="label-text">Name</span>
</label>
<input
id="compound-structure-name"
class="input input-bordered w-full"
name="compound-structure-name"
value="{{ compound_structure.name|safe }}"
required
/>
</div>
<div class="form-control mb-3">
<label class="label" for="compound-structure-description">
<span class="label-text">Description</span>
</label>
<input
id="compound-structure-description"
type="text"
class="input input-bordered w-full"
value="{{ compound_structure.description|safe }}"
name="compound-structure-description"
/>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('edit-compound-structure-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Update</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Updating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#edit-compound-structure-modal-submit").click(function (e) {
e.preventDefault();
$("#edit-compound-structure-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,151 +1,150 @@
{% load static %}
<!-- Edit Package Permission -->
<div id="edit_group_member_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Add or Remove Group Member</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>
To add member (either User or entire Groups) to this group select the
entity you want to add below and click the check mark.
<br />
To remove member simply click the <code>X</code> next to the member.
</p>
<!-- Edit Group Member -->
<dialog
id="edit_group_member_modal"
class="modal"
x-data="{
isSubmitting: false,
<div class="row">
<div class="col-xs-8">
<legend>User or Group</legend>
</div>
<div class="col-xs-4">
<legend>Add/Remove</legend>
</div>
</div>
reset() {
this.isSubmitting = false;
},
<div class="row">
<form
id="modal-form-group-member"
class="form-inline"
role="form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<div class="col-xs-8">
<select
id="select_member"
name="member"
data-actions-box="true"
class="selPackages"
data-width="100%"
>
<option disabled selected>User</option>
submitForm(form) {
if (form && form.checkValidity()) {
form.submit();
} else if (form) {
form.reportValidity();
}
}
}"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="text-lg font-bold">Add or Remove Group Member</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p class="mb-4">
To add member (either User or entire Groups) to this group select the
entity you want to add below and click the check mark.
<br />
To remove member simply click the X button next to the member.
</p>
<!-- Add Member Form -->
<form
id="modal-form-group-member"
accept-charset="UTF-8"
action=""
method="post"
class="mb-4"
>
{% csrf_token %}
<div class="flex gap-2 items-end">
<div class="form-control flex-1">
<label class="label">
<span class="label-text">User or Group</span>
</label>
<select
id="select_member"
name="member"
class="select select-bordered w-full"
required
>
<optgroup label="Users">
{% for u in users %}
<option value="{{ u.url }}">{{ u.username }}</option>
{% endfor %}
<option disabled>Groups</option>
</optgroup>
<optgroup label="Groups">
{% for g in groups %}
<option value="{{ g.url }}">{{ g.name|safe }}</option>
{% endfor %}
</select>
<input type="hidden" name="action" value="add" />
</div>
<div class="col-xs-2"></div>
<div class="col-xs-2">
<button type="submit" style="width:60%;" class="btn col-xs-2">
<span class="glyphicon glyphicon-ok"></span>
</button>
</div>
</form>
</optgroup>
</select>
<input type="hidden" name="action" value="add" />
</div>
<button type="submit" class="btn btn-primary">Add</button>
</div>
<p></p>
{% for u in group.user_member.all %}
<div class="row">
</form>
<!-- User Members -->
{% if group.user_member.all %}
<div class="divider">User Members</div>
<div class="space-y-2">
{% for u in group.user_member.all %}
<form
id="modal-form-group-member_{{ u.uuid }}"
class="form-inline"
role="form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<div class="col-xs-8">
{{ u.username }}
<div class="flex items-center gap-2">
<span class="flex-1">{{ u.username }}</span>
<input type="hidden" name="member" value="{{ u.url }}" />
<input type="hidden" name="action" value="remove" />
</div>
<div class="col-xs-2"></div>
<div class="col-xs-2">
<button type="submit" style="width:60%;" class="btn col-xs-2">
<span class="glyphicon glyphicon-trash"></span>
<button type="submit" class="btn btn-error btn-sm">
Remove
</button>
</div>
</form>
</div>
{% endfor %}
<p></p>
{% for g in group.group_member.all %}
<div class="row">
{% endfor %}
</div>
{% endif %}
<!-- Group Members -->
{% if group.group_member.all %}
<div class="divider">Group Members</div>
<div class="space-y-2">
{% for g in group.group_member.all %}
<form
id="modal-form-group-member_{{ g.uuid }}"
class="form-inline"
role="form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<div class="col-xs-8">
{{ g.name|safe }}
<div class="flex items-center gap-2">
<span class="flex-1">{{ g.name|safe }}</span>
<input type="hidden" name="member" value="{{ g.url }}" />
<input type="hidden" name="action" value="remove" />
</div>
<div class="col-xs-2"></div>
<div class="col-xs-2">
<button type="submit" style="width:60%;" class="btn col-xs-2">
<span class="glyphicon glyphicon-trash"></span>
<button type="submit" class="btn btn-error btn-sm">
Remove
</button>
</div>
</form>
</div>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="edit-package-modal-submit"
>
Update
</button>
</div>
{% endfor %}
</div>
{% endif %}
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
>
Close
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#edit-package-modal-submit").click(function (e) {
e.preventDefault();
$("#edit-package-modal-form").submit();
});
$("#select_member").selectpicker();
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button>close</button>
</form>
</dialog>

View File

@ -1,71 +1,94 @@
{% load static %}
<!-- Edit Model -->
<div id="edit_model_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
<h3 class="modal-title">Update Model</h3>
</div>
<div class="modal-body">
<p>Alter Name and Description of the Model.</p>
<form
id="edit-model-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<p>
<label for="model-name">Name</label>
<input
id="model-name"
type="text"
class="form-control"
name="model-name"
value="{{ model.name|safe }}"
/>
</p>
<p>
<label for="model-description">Description</label>
<input
id="model-description"
type="text"
class="form-control"
name="model-description"
value="{{ model.description|safe }}"
/>
</p>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="edit-model-modal-submit"
>
Update
</button>
</div>
<dialog
id="edit_model_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">Update Model</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p class="mb-4">Alter Name and Description of the Model.</p>
<form
id="edit-model-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="model-name">
<span class="label-text">Name</span>
</label>
<input
id="model-name"
type="text"
class="input input-bordered w-full"
name="model-name"
value="{{ model.name|safe }}"
required
/>
</div>
<div class="form-control mb-3">
<label class="label" for="model-description">
<span class="label-text">Description</span>
</label>
<input
id="model-description"
type="text"
class="input input-bordered w-full"
name="model-description"
value="{{ model.description|safe }}"
/>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('edit-model-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Update</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Updating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#edit-model-modal-submit").click(function (e) {
e.preventDefault();
$("#edit-model-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,70 +1,91 @@
{% load static %}
<!-- Edit Node -->
<div id="edit_node_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit Node</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Edit Node.</p>
<form
id="edit-node-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<p>
<label for="node-name">Name</label>
<input
id="node-name"
class="form-control"
name="node-name"
value="{{ node.name|safe }}"
/>
</p>
<p>
<label for="node-description">Description</label>
<input
id="node-description"
type="text"
class="form-control"
value="{{ node.description|safe }}"
name="node-description"
/>
</p>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="edit-node-modal-submit"
>
Create
</button>
</div>
<dialog
id="edit_node_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">Edit Node</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="edit-node-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="node-name">
<span class="label-text">Name</span>
</label>
<input
id="node-name"
class="input input-bordered w-full"
name="node-name"
value="{{ node.name|safe }}"
required
/>
</div>
<div class="form-control mb-3">
<label class="label" for="node-description">
<span class="label-text">Description</span>
</label>
<input
id="node-description"
type="text"
class="input input-bordered w-full"
value="{{ node.description|safe }}"
name="node-description"
/>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('edit-node-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Update</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Updating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#edit-node-modal-submit").click(function (e) {
e.preventDefault();
$("#edit-node-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,70 +1,91 @@
{% load static %}
<!-- Edit Package -->
<div id="edit_package_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Update Package</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Edit a Package.</p>
<form
id="edit-package-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<p>
<label for="package-name">Name</label>
<input
id="package-name"
class="form-control"
name="package-name"
value="{{ package.name|safe }}"
/>
</p>
<p>
<label for="package-description">Description</label>
<input
id="package-description"
type="text"
class="form-control"
value="{{ package.description|safe }}"
name="package-description"
/>
</p>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="edit-package-modal-submit"
>
Update
</button>
</div>
<dialog
id="edit_package_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">Update Package</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="edit-package-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="package-name">
<span class="label-text">Name</span>
</label>
<input
id="package-name"
class="input input-bordered w-full"
name="package-name"
value="{{ package.name|safe }}"
required
/>
</div>
<div class="form-control mb-3">
<label class="label" for="package-description">
<span class="label-text">Description</span>
</label>
<input
id="package-description"
type="text"
class="input input-bordered w-full"
value="{{ package.description|safe }}"
name="package-description"
/>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('edit-package-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Update</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Updating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#edit-package-modal-submit").click(function (e) {
e.preventDefault();
$("#edit-package-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,264 +1,271 @@
{% load static %}
<!-- Edit Package Permission -->
<div id="edit_package_permissions_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Grant or Revoke Permissions</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>
Modify permissions for this package. Note that if you give
<code>write</code> permissions to a user or group,
<code>read</code> permissions will be granted automatically.
<br />
To allow users to perform destructive actions, such as deleting the
package, <code>owner</code>
permissions must be granted.
</p>
<!-- Edit Package Permissions -->
<dialog
id="edit_package_permissions_modal"
class="modal"
x-data="{
updatePermissions(checkbox) {
const parts = checkbox.id.split('_');
const perm = parts[0];
const id = parts[1];
<div class="row">
<div class="col-xs-4">
<legend>User or Group</legend>
</div>
<div class="col-xs-2">
<legend>Read</legend>
</div>
<div class="col-xs-2">
<legend>Write</legend>
</div>
<div class="col-xs-2">
<legend>Owner</legend>
</div>
</div>
const readBox = document.getElementById('read_' + id);
const writeBox = document.getElementById('write_' + id);
const ownerBox = document.getElementById('owner_' + id);
<div class="row">
<form
id="modal-form-permissions"
class="form-inline"
role="form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<div class="col-xs-4">
<select
id="select_grantee"
name="grantee"
data-actions-box="true"
class="selPackages"
data-width="100%"
>
<option disabled selected>User</option>
if (perm === 'read' && !readBox.checked) {
writeBox.checked = false;
ownerBox.checked = false;
}
if (perm === 'write') {
if (writeBox.checked) {
readBox.checked = true;
} else {
ownerBox.checked = false;
}
}
if (perm === 'owner' && ownerBox.checked) {
readBox.checked = true;
writeBox.checked = true;
}
}
}"
>
<div class="modal-box max-w-2xl">
<!-- Header -->
<h3 class="text-lg font-bold">Grant or Revoke Permissions</h3>
<!-- Close button (X) -->
<form method="dialog">
<button class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2">
</button>
</form>
<!-- Body -->
<div class="py-4">
<p class="mb-4">
Modify permissions for this package. Note that if you give
<code class="badge badge-ghost">write</code> permissions to a user or
group, <code class="badge badge-ghost">read</code> permissions will be
granted automatically.
<br />
To allow users to perform destructive actions, such as deleting the
package, <code class="badge badge-ghost">owner</code> permissions must
be granted.
</p>
<!-- Add New Permission -->
<form
id="modal-form-permissions"
accept-charset="UTF-8"
action=""
method="post"
class="mb-4"
>
{% csrf_token %}
<div class="grid grid-cols-12 gap-2 items-end">
<div class="col-span-5">
<label class="label">
<span class="label-text">User or Group</span>
</label>
<select
id="select_grantee"
name="grantee"
class="select select-bordered w-full select-sm"
required
>
<optgroup label="Users">
{% for u in users %}
<option value="{{ u.url }}">{{ u.username }}</option>
{% endfor %}
<option disabled>Groups</option>
</optgroup>
<optgroup label="Groups">
{% for g in groups %}
<option value="{{ g.url }}">{{ g.name|safe }}</option>
{% endfor %}
</select>
</div>
<div class="col-xs-2">
<input type="checkbox" name="read" id="read_new" />
</div>
<div class="col-xs-2">
<input type="checkbox" name="write" id="write_new" />
</div>
<div class="col-xs-2">
<input type="checkbox" name="owner" id="owner_new" />
</div>
<div class="col-xs-2">
<button
type="submit"
style="width:60%;"
class="btn col-xs-2 modify-perm-button"
>
<span class="glyphicon glyphicon-plus"></span>
</button>
</div>
</form>
</optgroup>
</select>
</div>
<div class="col-span-2 text-center">
<label class="label justify-center">
<span class="label-text">Read</span>
</label>
<input
type="checkbox"
name="read"
id="read_new"
class="checkbox"
@click="updatePermissions($el)"
/>
</div>
<div class="col-span-2 text-center">
<label class="label justify-center">
<span class="label-text">Write</span>
</label>
<input
type="checkbox"
name="write"
id="write_new"
class="checkbox"
@click="updatePermissions($el)"
/>
</div>
<div class="col-span-2 text-center">
<label class="label justify-center">
<span class="label-text">Owner</span>
</label>
<input
type="checkbox"
name="owner"
id="owner_new"
class="checkbox"
@click="updatePermissions($el)"
/>
</div>
<div class="col-span-1">
<button type="submit" class="btn btn-primary btn-sm">+</button>
</div>
</div>
<p></p>
{% for up in user_permissions %}
<div class="row">
</form>
<!-- User Permissions -->
{% if user_permissions %}
<div class="divider">User Permissions</div>
<div class="space-y-2">
{% for up in user_permissions %}
<form
id="modal-form-permissions_{{ up.user.uuid }}"
class="form-inline"
role="form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<div class="col-xs-4">
{{ up.user.username }}
<input type="hidden" name="grantee" value="{{ up.user.url }}" />
</div>
<div class="col-xs-2">
<input
type="checkbox"
name="read"
id="read_{{ up.user.uuid }}"
{% if up.has_read %}checked{% endif %}
/>
</div>
<div class="col-xs-2">
<input
type="checkbox"
name="write"
id="write_{{ up.user.uuid }}"
{% if up.has_write %}checked{% endif %}
/>
</div>
<div class="col-xs-2">
<input
type="checkbox"
name="owner"
id="owner_{{ up.user.uuid }}"
{% if up.has_all %}checked{% endif %}
/>
</div>
<div class="col-xs-2">
<button
type="submit"
style="width:60%;"
class="btn col-xs-2 modify-perm-button"
>
<span class="glyphicon glyphicon-ok"></span>
</button>
<div class="grid grid-cols-12 gap-2 items-center">
<div class="col-span-5 truncate">
{{ up.user.username }}
<input
type="hidden"
name="grantee"
value="{{ up.user.url }}"
/>
</div>
<div class="col-span-2 text-center">
<input
type="checkbox"
name="read"
id="read_{{ up.user.uuid }}"
class="checkbox"
{% if up.has_read %}checked{% endif %}
@click="updatePermissions($el)"
/>
</div>
<div class="col-span-2 text-center">
<input
type="checkbox"
name="write"
id="write_{{ up.user.uuid }}"
class="checkbox"
{% if up.has_write %}checked{% endif %}
@click="updatePermissions($el)"
/>
</div>
<div class="col-span-2 text-center">
<input
type="checkbox"
name="owner"
id="owner_{{ up.user.uuid }}"
class="checkbox"
{% if up.has_all %}checked{% endif %}
@click="updatePermissions($el)"
/>
</div>
<div class="col-span-1">
<button type="submit" class="btn btn-sm btn-ghost"></button>
</div>
</div>
</form>
</div>
{% endfor %}
<p></p>
{% for gp in group_permissions %}
<div class="row">
{% endfor %}
</div>
{% endif %}
<!-- Group Permissions -->
{% if group_permissions %}
<div class="divider">Group Permissions</div>
<div class="space-y-2">
{% for gp in group_permissions %}
<form
id="modal-form-permissions_{{ gp.user.uuid }}"
class="form-inline"
role="form"
id="modal-form-permissions_{{ gp.group.uuid }}"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<div class="col-xs-4">
{{ gp.group.name|safe }}
<input
type="hidden"
name="grantee"
value="{{ gp.group.url }}"
/>
</div>
<div class="col-xs-2">
<input
type="checkbox"
name="read"
id="read_{{ gp.group.uuid }}"
{% if gp.has_read %}checked{% endif %}
/>
</div>
<div class="col-xs-2">
<input
type="checkbox"
name="write"
id="write_{{ gp.group.uuid }}"
{% if gp.has_write %}checked{% endif %}
/>
</div>
<div class="col-xs-2">
<input
type="checkbox"
name="owner"
id="owner_{{ gp.group.uuid }}"
{% if gp.has_all %}checked{% endif %}
/>
</div>
<div class="col-xs-2">
<button
type="submit"
style="width:60%;"
class="btn col-xs-2 modify-perm-button"
>
<span class="glyphicon glyphicon-ok"></span>
</button>
<div class="grid grid-cols-12 gap-2 items-center">
<div class="col-span-5 truncate">
{{ gp.group.name|safe }}
<input
type="hidden"
name="grantee"
value="{{ gp.group.url }}"
/>
</div>
<div class="col-span-2 text-center">
<input
type="checkbox"
name="read"
id="read_{{ gp.group.uuid }}"
class="checkbox"
{% if gp.has_read %}checked{% endif %}
@click="updatePermissions($el)"
/>
</div>
<div class="col-span-2 text-center">
<input
type="checkbox"
name="write"
id="write_{{ gp.group.uuid }}"
class="checkbox"
{% if gp.has_write %}checked{% endif %}
@click="updatePermissions($el)"
/>
</div>
<div class="col-span-2 text-center">
<input
type="checkbox"
name="owner"
id="owner_{{ gp.group.uuid }}"
class="checkbox"
{% if gp.has_all %}checked{% endif %}
@click="updatePermissions($el)"
/>
</div>
<div class="col-span-1">
<button type="submit" class="btn btn-sm btn-ghost"></button>
</div>
</div>
</form>
</div>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="edit-package-modal-submit"
>
Update
</button>
</div>
{% endfor %}
</div>
{% endif %}
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
>
Close
</button>
</div>
</div>
</div>
<script>
function checkboxClick() {
// id looks like read_3cadef24-220e-4587-9fa5-0e9a17aca2da
parts = this.id.split("_");
perm = parts[0];
id = parts[1];
readbox = "#read_" + id;
writebox = "#write_" + id;
ownerbox = "#owner_" + id;
if (perm == "read" && !$(readbox).prop("checked")) {
$(writebox).prop("checked", false);
$(ownerbox).prop("checked", false);
}
if (perm == "write") {
if ($(writebox).prop("checked")) {
$(readbox).prop("checked", true);
}
if (!$(writebox).prop("checked")) {
$(ownerbox).prop("checked", false);
}
}
if (perm == "owner") {
if ($(ownerbox).prop("checked")) {
$(readbox).prop("checked", true);
$(writebox).prop("checked", true);
}
}
}
$(function () {
$("#edit-package-modal-submit").click(function (e) {
e.preventDefault();
$("#edit-package-modal-form").submit();
});
$("#select_grantee").selectpicker();
// Add click functions to permission checkboxes
$('[id^="read_"]').on("click", checkboxClick);
$('[id^="write_"]').on("click", checkboxClick);
$('[id^="owner_"]').on("click", checkboxClick);
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button>close</button>
</form>
</dialog>

View File

@ -1,82 +1,119 @@
{% load static %}
<!-- Edit Package -->
<div id="edit_password_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Update your Password</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>To change your password please fill out the following inputs</p>
<form
id="edit-password-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<p>
<label for="old-password">Old Password</label>
<input
id="old-password"
class="form-control"
name="old-password"
type="password"
autocomplete="current-password"
/>
</p>
<p>
<label for="new-password">New Password</label>
<input
id="new-password"
class="form-control"
name="new-password"
type="password"
,
autocomplete="new-password"
/>
</p>
<p>
<label for="new-password-repeat">Repeat New Password</label>
<input
id="new-password-repeat"
class="form-control"
name="new-password-repeat"
type="password"
autocomplete="new-password"
/>
</p>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="edit-password-modal-submit"
>
Update
</button>
</div>
<dialog
id="edit_password_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">Update your Password</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p class="mb-4">
To change your password please fill out the following inputs
</p>
<form
id="edit-password-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<input type="hidden" name="hidden" value="update-password" />
<div class="form-control mb-3">
<label class="label" for="old-password">
<span class="label-text">Old Password</span>
</label>
<input
id="old-password"
class="input input-bordered w-full"
name="old-password"
type="password"
autocomplete="current-password"
required
/>
</div>
<div class="form-control mb-3">
<label class="label" for="new-password">
<span class="label-text">New Password</span>
</label>
<input
id="new-password"
class="input input-bordered w-full"
name="new-password"
type="password"
autocomplete="new-password"
required
/>
</div>
<div class="form-control mb-3">
<label class="label" for="new-password-repeat">
<span class="label-text">Repeat New Password</span>
</label>
<input
id="new-password-repeat"
class="input input-bordered w-full"
name="new-password-repeat"
type="password"
autocomplete="new-password"
required
@input="validatePasswordMatch('new-password', 'new-password-repeat')"
/>
<label class="label" x-show="errors['new-password-repeat']">
<span
class="label-text-alt text-error"
x-text="errors['new-password-repeat']"
></span>
</label>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="if (validatePasswordMatch('new-password', 'new-password-repeat')) submit('edit-password-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Update</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Updating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#edit-password-modal-submit").click(function (e) {
e.preventDefault();
$("#edit-password-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,72 +1,92 @@
{% load static %}
<!-- Edit Pathway -->
<div id="edit_pathway_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit Pathway</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Edit Pathway.</p>
<form
id="edit-pathway-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<p>
<label for="pathway-name">Name</label>
<input
id="pathway-name"
class="form-control"
name="pathway-name"
value="{{ pathway.name|safe }}"
/>
</p>
<p>
<label for="pathway-description">Description</label>
<textarea
id="pathway-description"
type="text"
class="form-control"
name="pathway-description"
rows="10"
>
<dialog
id="edit_pathway_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">Edit Pathway</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="edit-pathway-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="pathway-name">
<span class="label-text">Name</span>
</label>
<input
id="pathway-name"
class="input input-bordered w-full"
name="pathway-name"
value="{{ pathway.name|safe }}"
required
/>
</div>
<div class="form-control mb-3">
<label class="label" for="pathway-description">
<span class="label-text">Description</span>
</label>
<textarea
id="pathway-description"
class="textarea textarea-bordered w-full"
name="pathway-description"
rows="10"
>
{{ pathway.description|safe }}</textarea
>
</p>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="edit-pathway-modal-submit"
>
Update
</button>
</div>
>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('edit-pathway-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Update</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Updating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#edit-pathway-modal-submit").click(function (e) {
e.preventDefault();
$("#edit-pathway-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,163 +1,156 @@
{% load static %}
<!-- Edit Package -->
<div id="update_prediction_settings_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Update Prediction Setting</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>
To update your prediction setting modify parameters in the form below
und click "Update"
</p>
<form
id="edit-prediction-setting-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<div id="prediction-setting" class="panel-collapse in collapse">
<div class="panel-body list-group-item">
<table class="table-bordered table-hover table">
<tr style="background-color: rgba(0, 0, 0, 0.08);">
<th scope="col" width="20%">Parameter</th>
<th scope="col" width="80%">Value</th>
<!-- Edit Prediction Setting -->
<dialog
id="update_prediction_settings_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box max-w-3xl">
<!-- Header -->
<h3 class="text-lg font-bold">Update Prediction Setting</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p class="mb-4">
To update your prediction setting modify parameters in the form below
and click "Update"
</p>
<form
id="edit-prediction-setting-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<div class="overflow-x-auto">
<table class="table table-zebra w-full">
<thead>
<tr>
<th class="w-1/5">Parameter</th>
<th class="w-4/5">Value</th>
</tr>
</thead>
<tbody>
{% if 'model' in user.prediction_settings %}
<tr>
<td>Model</td>
<td>
<div class="form-control">
<select
id="model"
name="model"
class="select select-bordered w-full"
>
{% for m in models %}
<option
value="{{ m.id }}"
{% if user.prediction_settings.model.url == m.url %}selected{% endif %}
>
{{ m.name|safe }}
</option>
{% endfor %}
</select>
</div>
{% for k, v in user.prediction_settings.model_parameters.items %}
{% if k == 'threshold' %}
<div class="form-control mt-2">
<label class="label">
<span class="label-text">Threshold</span>
</label>
<input
type="number"
class="input input-bordered w-full"
name="{{ k }}"
value="{{ v }}"
min="0"
max="1"
step="0.05"
/>
</div>
{% endif %}
{% endfor %}
</td>
</tr>
<tbody>
{% if 'model' in user.prediction_settings %}
<tr>
<td width="20%">Model</td>
<td width="80%">
<table
width="100%"
class="table-bordered table-hover table"
>
<tbody>
<tr>
<td colspan="2">
<select
id="model"
name="model"
class="form-control"
data-width="100%"
>
{% for m in models %}
<option
value="{{ m.id }}"
{% if user.prediction_settings.model.url == m.url %}selected{% endif %}
>
{{ m.name|safe }}
</option>
{% endfor %}
</select>
</td>
</tr>
{% for k, v in user.prediction_settings.model_parameters.items %}
<tr>
<th width="20%">Model Parameter</th>
<th width="80%">Parameter Value</th>
</tr>
<tr>
<td width="20%">
{% if k == 'threshold' %}
Threshold
{% endif %}
</td>
<td width="80%">
{% if k == 'threshold' %}
<input
type="number"
class="form-control"
name="{{ k }}"
value="{{ v }}"
min="0"
max="1"
step="0.05"
/>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</td>
</tr>
{% endif %}
{% for k, v in user.prediction_settings.truncator.items %}
<tr>
<td>
<p>
{% if k == 'max_nodes' %}
Max Nodes
{% elif k == 'max_depth' %}
Max Depth
{% endif %}
</p>
</td>
<td>
<p>
{% if k == 'max_nodes' %}
<input
type="number"
class="form-control"
name="{{ k }}"
value="{{ v }}"
min="1"
max="50"
step="1"
/>
{% elif k == 'max_depth' %}
<input
type="number"
class="form-control"
name="{{ k }}"
value="{{ v }}"
min="1"
max="8"
step="1"
/>
{% endif %}
</p>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="edit-prediction-setting-modal-submit"
>
Update
</button>
</div>
{% endif %}
{% for k, v in user.prediction_settings.truncator.items %}
<tr>
<td>
{% if k == 'max_nodes' %}
Max Nodes
{% elif k == 'max_depth' %}
Max Depth
{% endif %}
</td>
<td>
{% if k == 'max_nodes' %}
<input
type="number"
class="input input-bordered w-full"
name="{{ k }}"
value="{{ v }}"
min="1"
max="50"
step="1"
/>
{% elif k == 'max_depth' %}
<input
type="number"
class="input input-bordered w-full"
name="{{ k }}"
value="{{ v }}"
min="1"
max="8"
step="1"
/>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('edit-prediction-setting-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Update</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Updating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#edit-prediction-setting-modal-submit").click(function (e) {
e.preventDefault();
$("#edit-prediction-setting-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,69 +1,91 @@
{% load static %}
<!-- Edit Reaction -->
<div id="edit_reaction_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
<h3 class="modal-title">Update Reaction</h3>
</div>
<div class="modal-body">
<form
id="edit-reaction-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<p>
<label for="reaction-name">Name</label>
<input
id="reaction-name"
class="form-control"
name="reaction-name"
value="{{ reaction.name|safe }}"
/>
</p>
<p>
<label for="reaction-description">Description</label>
<input
id="reaction-description"
type="text"
class="form-control"
value="{{ reaction.description|safe }}"
name="reaction-description"
/>
</p>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="edit-reaction-modal-submit"
>
Update
</button>
</div>
<dialog
id="edit_reaction_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">Update Reaction</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="edit-reaction-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="reaction-name">
<span class="label-text">Name</span>
</label>
<input
id="reaction-name"
class="input input-bordered w-full"
name="reaction-name"
value="{{ reaction.name|safe }}"
required
/>
</div>
<div class="form-control mb-3">
<label class="label" for="reaction-description">
<span class="label-text">Description</span>
</label>
<input
id="reaction-description"
type="text"
class="input input-bordered w-full"
value="{{ reaction.description|safe }}"
name="reaction-description"
/>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('edit-reaction-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Update</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Updating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#edit-reaction-modal-submit").click(function (e) {
e.preventDefault();
$("#edit-reaction-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,69 +1,91 @@
{% load static %}
<!-- Edit Rule -->
<div id="edit_rule_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
<h3 class="modal-title">Update Rule</h3>
</div>
<div class="modal-body">
<form
id="edit-rule-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<p>
<label for="rule-name">Name</label>
<input
id="rule-name"
class="form-control"
name="rule-name"
value="{{ rule.name|safe }}"
/>
</p>
<p>
<label for="rule-description">Description</label>
<input
id="rule-description"
type="text"
class="form-control"
value="{{ rule.description|safe }}"
name="rule-description"
/>
</p>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="edit-rule-modal-submit"
>
Update
</button>
</div>
<dialog
id="edit_rule_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">Update Rule</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="edit-rule-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="rule-name">
<span class="label-text">Name</span>
</label>
<input
id="rule-name"
class="input input-bordered w-full"
name="rule-name"
value="{{ rule.name|safe }}"
required
/>
</div>
<div class="form-control mb-3">
<label class="label" for="rule-description">
<span class="label-text">Description</span>
</label>
<input
id="rule-description"
type="text"
class="input input-bordered w-full"
value="{{ rule.description|safe }}"
name="rule-description"
/>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('edit-rule-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Update</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Updating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#edit-rule-modal-submit").click(function (e) {
e.preventDefault();
$("#edit-rule-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,110 +1,128 @@
{% load static %}
<!-- Edit User -->
<div id="edit_user_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Update User Defaults</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Edit User Defaults.</p>
<form
id="edit-user-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<p>
<label for="default-package">Default Package</label>
<select
id="default-package"
name="default-package"
class="form-control"
data-width="100%"
>
<option disabled>Select a Package</option>
{% for p in meta.writeable_packages %}
<option
value="{{ p.url }}"
{% if p.id == meta.user.default_package.id %}selected{% endif %}
>
{{ p.name|safe }}
</option>
{% endfor %}
</select>
</p>
<p>
<label for="default-group">Default Group</label>
<select
id="default-group"
name="default-group"
class="form-control"
data-width="100%"
>
<option disabled>Select a Group</option>
{% for g in meta.available_groups %}
<option
value="{{ g.url }}"
{% if g.id == meta.user.default_group.id %}selected{% endif %}
>
{{ g.name|safe }}
</option>
{% endfor %}
</select>
</p>
<p>
<label for="default-prediction-setting"
>Default Prediction Setting</label
>
<select
id="default-prediction-setting"
name="default-prediction-setting"
class="form-control"
data-width="100%"
>
<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|safe }}
</option>
{% endfor %}
</select>
</p>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="edit-user-modal-submit"
>
Update
</button>
</div>
<dialog
id="edit_user_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">Update User Defaults</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="edit-user-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="default-package">
<span class="label-text">Default Package</span>
</label>
<select
id="default-package"
name="default-package"
class="select select-bordered w-full"
>
<option disabled>Select a Package</option>
{% for p in meta.writeable_packages %}
<option
value="{{ p.url }}"
{% if p.id == meta.user.default_package.id %}selected{% endif %}
>
{{ p.name|safe }}
</option>
{% endfor %}
</select>
</div>
<div class="form-control mb-3">
<label class="label" for="default-group">
<span class="label-text">Default Group</span>
</label>
<select
id="default-group"
name="default-group"
class="select select-bordered w-full"
>
<option disabled>Select a Group</option>
{% for g in meta.available_groups %}
<option
value="{{ g.url }}"
{% if g.id == meta.user.default_group.id %}selected{% endif %}
>
{{ g.name|safe }}
</option>
{% endfor %}
</select>
</div>
<div class="form-control mb-3">
<label class="label" for="default-prediction-setting">
<span class="label-text">Default Prediction Setting</span>
</label>
<select
id="default-prediction-setting"
name="default-prediction-setting"
class="select select-bordered w-full"
>
<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|safe }}
</option>
{% endfor %}
</select>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('edit-user-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Update</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Updating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#edit-user-modal-submit").click(function (e) {
e.preventDefault();
$("#edit-user-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,93 +1,123 @@
<div
class="modal fade"
tabindex="-1"
<dialog
id="evaluate_model_modal"
role="dialog"
aria-labelledby="evaluate_model_modal"
aria-hidden="true"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title">Evaluate Model</h4>
</div>
<div class="modal-body">
<form
id="evaluate_model_form"
accept-charset="UTF-8"
action="{{ current_object.url }}"
data-remote="true"
method="post"
>
{% csrf_token %}
<div class="jumbotron">
<div class="modal-box max-w-3xl">
<!-- Header -->
<h3 class="text-lg font-bold">Evaluate Model</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="evaluate_model_form"
accept-charset="UTF-8"
action="{{ current_object.url }}"
method="post"
>
{% csrf_token %}
<div class="alert alert-info mb-4">
<span>
For evaluation, you need to select the packages you want to use.
While the model is evaluating, you can use the model for
predictions.
</div>
<!-- Evaluation Packages -->
<label for="model-evaluation-packages">Evaluation Packages</label>
</span>
</div>
<!-- Evaluation Packages -->
<div class="form-control">
<label class="label" for="model-evaluation-packages">
<span class="label-text">Evaluation Packages</span>
</label>
<select
id="model-evaluation-packages"
name="model-evaluation-packages"
data-actions-box="true"
class="form-control"
class="select select-bordered w-full h-48"
multiple
data-width="100%"
required
>
<option disabled>Reviewed Packages</option>
{% for obj in meta.readable_packages %}
{% if obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %}
{% endfor %}
<option disabled>Unreviewed Packages</option>
{% for obj in meta.readable_packages %}
{% if not obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %}
{% endfor %}
<optgroup label="Reviewed Packages">
{% for obj in meta.readable_packages %}
{% if obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %}
{% endfor %}
</optgroup>
<optgroup label="Unreviewed Packages">
{% for obj in meta.readable_packages %}
{% if not obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name|safe }}</option>
{% endif %}
{% endfor %}
</optgroup>
</select>
<label class="label">
<span class="label-text-alt"
>Hold Ctrl/Cmd to select multiple packages</span
>
</label>
</div>
<!-- Eval Type -->
<label for="model-evaluation-type">Evaluation Type</label>
<!-- Eval Type -->
<div class="form-control mt-4">
<label class="label" for="model-evaluation-type">
<span class="label-text">Evaluation Type</span>
</label>
<select
id="model-evaluation-type"
name="model-evaluation-type"
class="form-control"
class="select select-bordered w-full"
required
>
<option disabled selected>Select evaluation type</option>
<option value="" disabled selected>Select evaluation type</option>
<option value="sg">Single Generation</option>
<option value="mg">Multiple Generations</option>
</select>
</div>
<input type="hidden" name="hidden" value="evaluate" />
</form>
</div>
<div class="modal-footer">
<a id="evaluate_model_form_submit" class="btn btn-primary" href="#"
>Evaluate</a
>
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
</div>
<input type="hidden" name="hidden" value="evaluate" />
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Cancel
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('evaluate_model_form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Evaluate</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Evaluating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#model-evaluation-packages").selectpicker();
$("#evaluate_model_form_submit").on("click", function (e) {
e.preventDefault();
$("#evaluate_model_form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,53 +1,56 @@
{% load static %}
<!-- Export Package -->
<div id="export_package_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Export Package as JSON</h3>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<dialog
id="export_package_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">Export Package as JSON</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p>
By clicking on Export the Package will be serialized into a JSON and
directly downloaded.
<form
id="export-package-modal-form"
accept-charset="UTF-8"
action="{{ package.url }}"
data-remote="true"
method="GET"
>
<input type="hidden" name="export" value="true" />
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="export-package-modal-form-submit"
>
Export
</button>
</div>
opened in a new tab.
</p>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="window.open('{{ package.url }}?export=true', '_blank'); $el.closest('dialog').close();"
:disabled="isSubmitting"
>
Export
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#export-package-modal-form-submit").click(function (e) {
e.preventDefault();
$("#export-package-modal-form").submit();
$("#export_package_modal").modal("hide");
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,109 +1,142 @@
{% load static %}
<!-- Copy Object -->
<div id="generic_copy_object_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Copy {{ object_type|capfirst }}</h3>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form
id="generic-copy-object-modal-form"
accept-charset="UTF-8"
data-remote="true"
method="post"
>
{% csrf_token %}
<label for="target-package"
>Select the Target Package you want to copy this {{ object_type }}
into</label
>
<dialog
id="generic_copy_object_modal"
class="modal"
x-data="{
isSubmitting: false,
errorMessage: '',
targetPackage: '',
reset() {
this.isSubmitting = false;
this.errorMessage = '';
this.targetPackage = '';
},
async submit() {
if (!this.targetPackage) return;
this.isSubmitting = true;
this.errorMessage = '';
try {
const response = await fetch(this.targetPackage, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
},
body: new URLSearchParams({
hidden: 'copy',
object_to_copy: '{{ current_object.url }}'
})
});
const data = await response.json();
if (response.ok) {
window.location.href = data.success;
} else {
if (data.error && data.error.indexOf('to the same package') > -1) {
this.errorMessage = 'The target Package is the same as the source Package. Please select another target!';
} else {
this.errorMessage = data.error || 'An error occurred';
}
}
} catch (error) {
this.errorMessage = 'An error occurred while copying';
} finally {
this.isSubmitting = false;
}
}
}"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="text-lg font-bold">Copy {{ object_type|capfirst }}</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="generic-copy-object-modal-form"
accept-charset="UTF-8"
method="post"
>
{% csrf_token %}
<div class="form-control">
<label class="label" for="target-package">
<span class="label-text">
Select the Target Package you want to copy this {{ object_type }}
into
</span>
</label>
<select
id="target-package"
name="target-package"
data-actions-box="true"
class="form-control"
data-width="100%"
class="select select-bordered w-full"
x-model="targetPackage"
required
>
<option disabled selected>Select Target Package</option>
<option value="" disabled selected>Select Target Package</option>
{% for p in meta.writeable_packages %}
<option value="{{ p.url }}">{{ p.name|safe }}</option>
`
{% endfor %}
</select>
<input type="hidden" name="hidden" value="copy" />
</form>
<div
id="copy-object-error-message"
class="alert alert-danger"
role="alert"
style="display: none"
></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="generic-copy-object-modal-form-submit"
>
Copy
</button>
</div>
<input type="hidden" name="hidden" value="copy" />
</form>
<!-- Error Message -->
<div
x-show="errorMessage"
x-cloak
class="alert alert-error mt-4"
role="alert"
>
<span x-text="errorMessage"></span>
</div>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit()"
:disabled="isSubmitting || !targetPackage"
>
<span x-show="!isSubmitting">Copy</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Copying...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#generic-copy-object-modal-form-submit").click(function (e) {
e.preventDefault();
$("#copy-object-error-message").hide();
const packageUrl = $("#target-package").find(":selected").val();
if (
packageUrl === "Select Target Package" ||
packageUrl === "" ||
packageUrl === null ||
packageUrl === undefined
) {
return;
}
const formData = {
hidden: "copy",
object_to_copy: "{{ current_object.url }}",
};
$.ajax({
type: "post",
data: formData,
url: packageUrl,
success: function (data, textStatus) {
window.location.href = data.success;
},
error: function (jqXHR, textStatus, errorThrown) {
if (jqXHR.responseJSON.error.indexOf("to the same package") > -1) {
$("#copy-object-error-message").append(
"<p>The target Package is the same as the source Package. Please select another target!</p>",
);
} else {
$("#copy-object-error-message").append(
"<p>" + jqXHR.responseJSON.error + "</p>",
);
}
$("#copy-object-error-message").show();
},
});
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,58 +1,99 @@
{% load static %}
<!-- Delete Object -->
<div id="generic_delete_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Delete {{ object_type|capfirst }}</h3>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
<!--
Generic Delete Modal - Delete object with confirmation
Migrated from Bootstrap + jQuery to DaisyUI + Alpine.js
Uses native <dialog> element with .showModal() API
-->
<dialog
id="generic_delete_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">Delete {{ object_type|capfirst }}</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<!-- Warning message -->
<div class="alert alert-warning">
<svg
xmlns="http://www.w3.org/2000/svg"
class="stroke-current shrink-0 h-6 w-6"
fill="none"
viewBox="0 0 24 24"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
{% if object_type == 'user' %}
Clicking "Delete" will <strong>permanently</strong> delete the User
and associated data. This action can't be undone!
{% else %}
Deletes the {{ object_type|capfirst }}. Related objects that depend on
this {{ object_type|capfirst }} will be deleted as well.
{% endif %}
<form
id="generic-delete-modal-form"
accept-charset="UTF-8"
action="{{ current_object.url }}"
data-remote="true"
method="post"
>
{% csrf_token %}
<input type="hidden" id="hidden" name="hidden" value="delete" />
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="generic-delete-modal-form-submit"
>
Delete
</button>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
/>
</svg>
<span>
{% if object_type == 'user' %}
Clicking "Delete" will <strong>permanently</strong> delete the User
and associated data. This action can't be undone!
{% else %}
Deletes the {{ object_type|capfirst }}. Related objects that depend
on this {{ object_type|capfirst }} will be deleted as well.
{% endif %}
</span>
</div>
<!-- Hidden form -->
<form
id="generic-delete-modal-form"
accept-charset="UTF-8"
action="{{ current_object.url }}"
method="post"
>
{% csrf_token %}
<input type="hidden" name="hidden" value="delete" />
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Cancel
</button>
<button
type="button"
class="btn btn-error"
@click="submit('generic-delete-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Delete</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Deleting...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#generic-delete-modal-form-submit").click(function (e) {
e.preventDefault();
$("#generic-delete-modal-form").submit();
});
});
</script>
<!-- Backdrop (click to close) -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,213 +1,173 @@
{% load static %}
<style>
.alias-container {
display: flex;
flex-wrap: wrap;
align-items: center;
border: 1px solid #ccc;
border-radius: 4px;
padding: 4px 6px;
cursor: text;
min-height: 38px;
background-color: #fff;
}
.alias {
display: inline-flex;
align-items: center;
background-color: #5bc0de;
color: white;
padding: 4px 8px;
margin: 3px 3px;
border-radius: 4px;
font-size: 13px;
line-height: 1.4;
}
.alias .remove {
margin-left: 6px;
cursor: pointer;
font-weight: bold;
line-height: 1;
}
.alias-input {
flex: 1;
min-width: 120px;
border: none;
outline: none;
margin: 3px 3px;
font-size: 14px;
}
.form-control.alias-container {
height: auto;
box-shadow: none;
}
</style>
<div
class="modal fade bs-modal-lg"
<dialog
id="set_aliases_modal"
tabindex="-1"
aria-labelledby="set_aliases_modal"
aria-modal="true"
role="dialog"
>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">
Set Aliases for {{ current_object.name|safe }}
</h4>
</div>
<div class="modal-body">
<form
id="set_aliases_modal_form"
accept-charset="UTF-8"
action="{{ current_object.url }}"
data-remote="true"
method="post"
>
{% csrf_token %}
<label for="alias-input">Aliases:</label>
<div class="form-control alias-container" id="alias-box">
{% for alias in current_object.aliases %}
<span class="alias"
>{{ alias|escape }}<span class="remove">&times;</span></span
>
{% endfor %}
<input
type="text"
id="alias-input"
class="alias-input"
placeholder="Add Alias..."
/>
</div>
</form>
<div
id="add-alias-error-message"
class="alert alert-danger"
role="alert"
style="display: none"
></div>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary pull-left"
data-dismiss="modal"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
id="set_aliases_modal_form_submit"
>
Submit
</button>
</div>
</div>
</div>
</div>
<script>
$(function () {
function addAlias(aliasText) {
aliasText = aliasText.trim();
if (aliasText === "") return;
class="modal"
x-data="{
isSubmitting: false,
aliases: [{% for alias in current_object.aliases %}'{{ alias|escapejs }}'{% if not forloop.last %},{% endif %}{% endfor %}],
newAlias: '',
errorMessage: '',
// Avoid duplicate aliass
var exists = false;
$("#alias-box .alias").each(function () {
if (
$(this).text().replace("×", "").trim().toLowerCase() ===
aliasText.toLowerCase()
) {
exists = true;
return false;
}
});
reset() {
this.isSubmitting = false;
this.errorMessage = '';
},
addAlias() {
const aliasText = this.newAlias.trim();
if (aliasText === '') return;
// Check for duplicates (case-insensitive)
const exists = this.aliases.some(
a => a.toLowerCase() === aliasText.toLowerCase()
);
if (!exists) {
var aliasHtml =
'<span class="alias">' +
$("<div>").text(aliasText).html() +
'<span class="remove">&times;</span></span>';
$(aliasHtml).insertBefore("#alias-input");
this.aliases.push(aliasText);
}
$("#alias-input").val("");
}
this.newAlias = '';
},
// Add alias when Enter is pressed
$("#alias-input").on("keypress", function (e) {
if (e.which === 13) {
removeAlias(index) {
this.aliases.splice(index, 1);
},
handleKeypress(e) {
if (e.key === 'Enter') {
e.preventDefault();
addAlias($(this).val());
this.addAlias();
}
});
},
// Add alias when input loses focus
$("#alias-input").on("blur", function () {
var val = $(this).val();
if (val.trim() !== "") {
addAlias(val);
handleBlur() {
if (this.newAlias.trim() !== '') {
this.addAlias();
}
});
},
// Remove alias when clicking ×
$("#alias-box").on("click", ".remove", function () {
$(this).closest(".alias").remove();
});
async submit() {
this.isSubmitting = true;
this.errorMessage = '';
// Focus input when clicking the container
$("#alias-box").on("click", function () {
$("#alias-input").focus();
});
$("#set_aliases_modal_form_submit").on("click", function (e) {
e.preventDefault();
let aliases = [];
$("#alias-box .alias").each(function () {
aliases.push($(this).text().replace("×", "").trim());
});
if (aliases.length === 0) {
// Set empty string for deletion of all aliases
// If empty list is sent, its gets removed entirely from post data
aliases = [""];
const formData = new URLSearchParams();
if (this.aliases.length === 0) {
formData.append('aliases', '');
} else {
this.aliases.forEach(alias => {
formData.append('aliases', alias);
});
}
formData = {
aliases: aliases,
};
try {
const response = await fetch('{{ current_object.url }}', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: formData
});
$.ajax({
type: "post",
data: formData,
url: "{{ current_object.url }}",
traditional: true,
success: function (data, textStatus) {
if (response.ok) {
const data = await response.json();
window.location.href = data.success;
},
error: function (jqXHR, textStatus, errorThrown) {
$("#add-alias-error-message").append(
"<p>Setting aliases failed!</p>",
);
$("#add-alias-error-message").show();
},
});
});
});
</script>
} else {
this.errorMessage = 'Setting aliases failed!';
}
} catch (error) {
this.errorMessage = 'Setting aliases failed!';
} finally {
this.isSubmitting = false;
}
}
}"
@close="reset()"
>
<div class="modal-box max-w-4xl">
<!-- Header -->
<h3 class="text-lg font-bold">
Set Aliases for {{ current_object.name|safe }}
</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<div class="form-control">
<label class="label">
<span class="label-text">Aliases:</span>
</label>
<div
class="flex flex-wrap items-center gap-1 p-2 border border-base-300 rounded-lg bg-base-100 min-h-[38px] cursor-text"
@click="$refs.aliasInput.focus()"
>
<template x-for="(alias, index) in aliases" :key="index">
<span class="badge badge-info gap-1 py-3">
<span x-text="alias"></span>
<button
type="button"
class="btn btn-ghost btn-xs p-0 h-auto min-h-0"
@click.stop="removeAlias(index)"
>
</button>
</span>
</template>
<input
type="text"
x-ref="aliasInput"
x-model="newAlias"
class="flex-1 min-w-[120px] border-none outline-none bg-transparent text-sm"
placeholder="Add Alias..."
@keypress="handleKeypress($event)"
@blur="handleBlur()"
/>
</div>
</div>
<!-- Error Message -->
<div x-show="errorMessage" x-cloak class="alert alert-error mt-4">
<span x-text="errorMessage"></span>
</div>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit()"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Submitting...</span>
</button>
</div>
</div>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,97 +1,137 @@
{% load static %}
<!-- Delete Object -->
<div id="generic_set_external_reference_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Add External References</h3>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form
id="generic-set-external-reference-modal-form"
accept-charset="UTF-8"
action="{{ current_object.url }}"
data-remote="true"
method="post"
>
{% csrf_token %}
<label for="database-select"
>Select the Database you want to attach an External Reference
for</label
>
<!-- Set External Reference -->
<dialog
id="generic_set_external_reference_modal"
class="modal"
x-data="{
isSubmitting: false,
selectedDatabase: '',
placeholder: '',
reset() {
this.isSubmitting = false;
this.selectedDatabase = '';
this.placeholder = '';
},
updatePlaceholder() {
if (this.selectedDatabase) {
const option = document.querySelector('#database-select option[value=\'' + this.selectedDatabase + '\']');
if (option) {
this.placeholder = option.dataset.inputPlaceholder || '';
}
}
},
submit(formId) {
const form = document.getElementById(formId);
if (form && form.checkValidity()) {
this.isSubmitting = true;
form.submit();
} else if (form) {
form.reportValidity();
}
}
}"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="text-lg font-bold">Add External References</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="generic-set-external-reference-modal-form"
accept-charset="UTF-8"
action="{{ current_object.url }}"
method="post"
>
{% csrf_token %}
<div class="form-control">
<label class="label" for="database-select">
<span class="label-text">
Select the Database you want to attach an External Reference for
</span>
</label>
<select
id="database-select"
name="selected-database"
data-actions-box="true"
class="form-control"
data-width="100%"
class="select select-bordered w-full"
x-model="selectedDatabase"
@change="updatePlaceholder()"
required
>
<option disabled selected>Select Database</option>
<option value="" disabled selected>Select Database</option>
{% for entity, databases in meta.external_databases.items %}
{% if entity == object_type %}
{% for db in databases %}
<option
id="db-select-{{ db.database.pk }}"
data-input-placeholder="{{ db.placeholder }}"
value="{{ db.database.id }}"
data-input-placeholder="{{ db.placeholder }}"
>
{{ db.database.name|safe }}
</option>
`
{% endfor %}
{% endif %}
{% endfor %}
</select>
<p></p>
<div id="input-div" style="display: none">
<label for="identifier">The reference</label>
<input
type="text"
id="identifier"
name="identifier"
class="form-control"
placeholder=""
/>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="generic-set-external-reference-modal-form-submit"
>
Submit
</button>
</div>
</div>
<div class="form-control mt-4" x-show="selectedDatabase" x-cloak>
<label class="label" for="identifier">
<span class="label-text">The reference</span>
</label>
<input
type="text"
id="identifier"
name="identifier"
class="input input-bordered w-full"
:placeholder="placeholder"
required
/>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('generic-set-external-reference-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Submitting...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#database-select").on("change", function () {
let selected = $(this).val();
$("#identifier").attr(
"placeholder",
$("#db-select-" + selected).data("input-placeholder"),
);
$("#input-div").show();
});
$("#generic-set-external-reference-modal-form-submit").click(function (e) {
e.preventDefault();
$("#generic-set-external-reference-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,112 +1,142 @@
{% load static %}
<div
class="modal fade bs-modal-lg"
<dialog
id="set_scenario_modal"
tabindex="-1"
aria-labelledby="set_scenario_modal"
aria-modal="true"
role="dialog"
class="modal"
x-data="{
isSubmitting: false,
isLoading: false,
loaded: false,
scenarios: [],
attachedScenarios: [{% for scen in current_object.scenarios.all %}'{{ scen.url }}'{% if not forloop.last %},{% endif %}{% endfor %}],
reset() {
this.isSubmitting = false;
},
async loadScenarios() {
if (this.loaded) return;
this.isLoading = true;
try {
const response = await fetch('{% url "package scenario list" meta.current_package.uuid %}');
const data = await response.json();
this.scenarios = data;
this.loaded = true;
} catch (error) {
console.error('Error loading scenarios:', error);
} finally {
this.isLoading = false;
}
},
isSelected(url) {
return this.attachedScenarios.includes(url);
},
submit() {
this.isSubmitting = true;
const select = document.getElementById('scenario-select');
if (select.selectedOptions.length === 0) {
// Add hidden empty option to indicate clearing all scenarios
const emptyOption = document.createElement('option');
emptyOption.value = '';
emptyOption.selected = true;
select.appendChild(emptyOption);
}
document.getElementById('set_scenario_modal_form').submit();
}
}"
@close="reset()"
x-init="$watch('$el.open', value => { if (value) loadScenarios(); })"
>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">
Set Scenarios for {{ current_object.name|safe }}
</h4>
<div class="modal-box max-w-4xl">
<!-- Header -->
<h3 class="text-lg font-bold">
Set Scenarios for {{ current_object.name|safe }}
</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<!-- Loading indicator -->
<div x-show="isLoading" x-cloak class="mb-4 text-center">
<span class="loading loading-spinner loading-lg"></span>
<div class="alert alert-info mt-2">Loading Scenarios...</div>
</div>
<div class="modal-body">
<div id="loading_scenario_div" class="text-center"></div>
<form
id="set_scenario_modal_form"
accept-charset="UTF-8"
action="{{ current_object.url }}"
data-remote="true"
method="post"
>
{% csrf_token %}
<label for="scenario-select">Scenarios</label>
<form
id="set_scenario_modal_form"
accept-charset="UTF-8"
action="{{ current_object.url }}"
data-remote="true"
method="post"
x-show="!isLoading"
>
{% csrf_token %}
<div class="form-control">
<label class="label" for="scenario-select">
<span class="label-text">Scenarios</span>
</label>
<select
id="scenario-select"
name="selected-scenarios"
data-actions-box="true"
class="form-control"
class="select select-bordered h-48 w-full"
multiple
data-width="100%"
>
<option disabled>Select Scenarios</option>
<option value="" hidden></option>
<template x-for="scenario in scenarios" :key="scenario.url">
<option
:value="scenario.url"
:selected="isSelected(scenario.url)"
x-text="scenario.name"
></option>
</template>
</select>
</form>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary pull-left"
data-dismiss="modal"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
id="set_scenario_modal_form_submit"
>
Submit
</button>
</div>
<label class="label">
<span class="label-text-alt"
>Hold Ctrl/Cmd to select multiple scenarios</span
>
</label>
</div>
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit()"
:disabled="isSubmitting || isLoading"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Submitting...</span>
</button>
</div>
</div>
</div>
{# prettier-ignore-start #}
<script>
$(function () {
var loaded = false;
var attachedScenarios = []
{% if current_object.scenarios.all %}
{% for scen in current_object.scenarios.all %}
attachedScenarios.push('{{ scen.url }}')
{% endfor %}
{% endif %}
$('#scenario-select').selectpicker();
$('#set_scenario_modal').on('shown.bs.modal', function () {
if (!loaded) {
makeLoadingGif("#loading_scenario_div", "{% static '/images/wait.gif' %}");
$('#loading_scenario_div').append("<p></p><div class='alert alert-info'>Loading Scenarios...</div>");
$.getJSON("{% url 'package scenario list' meta.current_package.uuid %}").then(function (data) {
for(s in data) {
scenario = data[s]
var selected = attachedScenarios.includes(scenario.url);
$('#scenario-select').append(`<option value="${scenario.url}" ${selected ? 'selected' : ''}>${scenario.name}</option>`);
}
$('#scenario-select').selectpicker('refresh');
$("#loading_scenario_div").empty();
});
loaded = true;
}
$('#set_scenario_modal_form_submit').on('click', function (e) {
e.preventDefault();
if ($('#scenario-select').val().length == 0) {
$('#scenario-select').val("")
}
$('#set_scenario_modal_form').submit();
});
});
});
</script>
{# prettier-ignore-end #}
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,75 +1,89 @@
{% load static %}
<!-- Identify Missing Rules -->
<div id="identify_missing_rules_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Identify Missing Rules</h3>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<dialog
id="identify_missing_rules_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="text-lg font-bold">Identify Missing Rules</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p class="mb-4">
By clicking on Download we'll search the Pathway for Reactions that are
not backed by a Rule or which can be assembled by chaining two rules.
<form
id="identify-missing-rules-modal-form"
accept-charset="UTF-8"
action="{{ pathway.url }}"
data-remote="true"
method="GET"
>
<label for="rule-package">Select the Rule Package</label>
</p>
<form
id="identify-missing-rules-modal-form"
accept-charset="UTF-8"
action="{{ pathway.url }}"
method="GET"
>
<div class="form-control">
<label class="label" for="rule-package">
<span class="label-text">Select the Rule Package</span>
</label>
<select
id="rule-package"
name="rule-package"
data-actions-box="true"
class="form-control"
data-width="100%"
class="select select-bordered w-full"
required
>
<option disabled>Reviewed Packages</option>
{% for obj in meta.readable_packages %}
{% if obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name }}</option>
{% endif %}
{% endfor %}
<option disabled>Unreviewed Packages</option>
{% for obj in meta.readable_packages %}
{% if not obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name }}</option>
{% endif %}
{% endfor %}
<optgroup label="Reviewed Packages">
{% for obj in meta.readable_packages %}
{% if obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name }}</option>
{% endif %}
{% endfor %}
</optgroup>
<optgroup label="Unreviewed Packages">
{% for obj in meta.readable_packages %}
{% if not obj.reviewed %}
<option value="{{ obj.url }}">{{ obj.name }}</option>
{% endif %}
{% endfor %}
</optgroup>
</select>
<input type="hidden" name="identify-missing-rules" value="true" />
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="identify-missing-rules-modal-submit"
>
Download
</button>
</div>
</div>
<input type="hidden" name="identify-missing-rules" value="true" />
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="document.getElementById('identify-missing-rules-modal-form').submit(); $el.closest('dialog').close()"
>
Download
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#identify-missing-rules-modal-submit").click(function (e) {
e.preventDefault();
$("#identify-missing-rules-modal-form").submit();
$("#identify_missing_rules_modal").modal("hide");
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,118 +1,174 @@
<div
class="modal fade"
tabindex="-1"
<dialog
id="manage_api_token_modal"
role="dialog"
aria-labelledby="manage_api_token_modal"
aria-hidden="true"
class="modal"
x-data="{
isSubmitting: false,
newToken: '',
tokens: [],
reset() {
this.isSubmitting = false;
this.newToken = '';
},
async requestToken() {
this.isSubmitting = true;
const form = document.getElementById('request_api_token_form');
const formData = new FormData(form);
try {
const response = await fetch('{{ meta.user.url }}', {
method: 'POST',
body: new URLSearchParams(formData)
});
const data = await response.json();
this.newToken = data.raw_token;
} catch (error) {
console.error('Error requesting token:', error);
} finally {
this.isSubmitting = false;
}
},
async deleteToken(form) {
const formData = new FormData(form);
try {
await fetch(form.action, {
method: 'POST',
body: new URLSearchParams(formData)
});
form.closest('.token-item').remove();
} catch (error) {
console.error('Error deleting token:', error);
}
}
}"
@close="reset()"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span>
</button>
<h3 class="modal-title">Manage API Token</h3>
</div>
<div class="modal-body">
<p>
Requesting a Token will invalidate all potential existing tokens. The
new token will only be shown once, so ensure to store it in secure
place
</p>
<form
id="request_api_token_form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<p>
<label for="token-name">Name</label>
<input
type="text"
id="token-name"
class="form-control"
name="name"
placeholder="Generic Token for {{ meta.user.username }}"
/>
<label for="valid-for">Valid for (in days)</label>
<input
type="number"
id="valid-for"
class="form-control"
name="valid-for"
value="90"
/>
<input type="hidden" name="hidden" value="request-api-token" />
</p>
</form>
<div id="new-token">
<pre id="new-token-pre"></pre>
<div class="modal-box">
<!-- Header -->
<h3 class="text-lg font-bold">Manage API Token</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<p class="mb-4">
Requesting a Token will invalidate all potential existing tokens. The
new token will only be shown once, so ensure to store it in a secure
place.
</p>
<form id="request_api_token_form" accept-charset="UTF-8" method="post">
{% csrf_token %}
<div class="form-control mb-3">
<label class="label" for="token-name">
<span class="label-text">Name</span>
</label>
<input
type="text"
id="token-name"
class="input input-bordered w-full"
name="name"
placeholder="Generic Token for {{ meta.user.username }}"
/>
</div>
<div id="existing-tokens">
{% for t in tokens %}
<div class="form-control mb-3">
<label class="label" for="valid-for">
<span class="label-text">Valid for (in days)</span>
</label>
<input
type="number"
id="valid-for"
class="input input-bordered w-full"
name="valid-for"
value="90"
/>
</div>
<input type="hidden" name="hidden" value="request-api-token" />
</form>
<!-- New Token Display -->
<div x-show="newToken" x-cloak class="alert alert-success mb-4">
<div class="w-full">
<span class="font-bold">New Token:</span>
<pre
class="mt-2 p-2 bg-base-200 rounded overflow-x-auto"
x-text="newToken"
></pre>
</div>
</div>
<!-- Existing Tokens -->
<div class="space-y-2">
{% for t in tokens %}
<div class="token-item">
<form
id="delete-token-{{ forloop.counter0 }}"
accept-charset="UTF-8"
action="{{ meta.user.url }}"
data-remote="true"
method="post"
>
{% csrf_token %}
<div class="input-group">
<div class="join w-full">
<input type="hidden" name="hidden" value="delete" />
<input type="hidden" name="token-id" value="{{ t.pk }}" />
<input
type="text"
class="form-control"
class="input input-bordered join-item w-full"
value="{{ t.name|safe }}"
disabled
/>
<span class="input-group-btn">
<button type="submit" class="btn btn-danger">Delete</button>
</span>
<button
type="button"
class="btn btn-error join-item"
@click="deleteToken($el.closest('form'))"
>
Delete
</button>
</div>
</form>
{% endfor %}
</div>
</div>
<div class="modal-footer">
<a id="manage_api_token_form_submit" class="btn btn-primary" href="#"
>Submit</a
>
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
</div>
{% endfor %}
</div>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Cancel
</button>
<button
type="button"
class="btn btn-primary"
@click="requestToken()"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Request Token</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Requesting...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#new-token").hide();
$("#manage_api_token_form_submit").on("click", function (e) {
e.preventDefault();
const formData = $("#request_api_token_form").serialize();
$.post("", formData, function (response) {
$("#new-token-pre").text(response.raw_token);
$("#new-token").show();
});
});
// Select all elements that start with 'delete-token-'
$("[id^='delete-token-']").on("submit", function (e) {
e.preventDefault();
const formData = $(this).serialize();
const form = $(this);
$.post(this.action, formData, function (response) {
console.log(this);
form.remove();
});
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,52 +1,85 @@
{% load static %}
<!-- Publish a Package -->
<div id="publish_package_modal" class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Publish Package</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
<dialog
id="publish_package_modal"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-box">
<!-- Header -->
<h3 class="font-bold text-lg">Publish Package</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<div class="alert alert-info">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
class="h-6 w-6 shrink-0 stroke-current"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Clicking on Publish will make this Package publicly available!</p>
<form
id="publish-package-modal-form"
accept-charset="UTF-8"
action="{{ current_package.url }}"
data-remote="true"
method="post"
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path>
</svg>
<span
>Clicking on Publish will make this Package publicly available!</span
>
{% csrf_token %}
<input type="hidden" name="hidden" value="publish-package" />
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="publish-package-modal-form-submit"
>
Publish
</button>
</div>
<form
id="publish-package-modal-form"
accept-charset="UTF-8"
action="{{ current_package.url }}"
method="post"
>
{% csrf_token %}
<input type="hidden" name="hidden" value="publish-package" />
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('publish-package-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Publish</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Publishing...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#publish-package-modal-form-submit").click(function (e) {
e.preventDefault();
$("#publish-package-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,55 +1,72 @@
<div
class="modal fade"
tabindex="-1"
<dialog
id="retrain_model_modal"
role="dialog"
aria-labelledby="retrain_model_modal"
aria-hidden="true"
class="modal"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title">Retrain Model</h4>
</div>
<div class="modal-body">
<form
id="retrain_model_form"
accept-charset="UTF-8"
action="{{ meta.current_object.url }}"
data-remote="true"
method="post"
>
<div class="jumbotron">
<div class="modal-box max-w-3xl">
<!-- Header -->
<h3 class="text-lg font-bold">Retrain Model</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="retrain_model_form"
accept-charset="UTF-8"
action="{{ meta.current_object.url }}"
method="post"
>
{% csrf_token %}
<div class="alert alert-info mb-4">
<span>
To reflect changes in the rule or data packages, you can use the
"Retrain" button, to let the model reflect the changes without
creating a new model. While the model is retraining, it will be
unavailable for prediction.
</div>
{% csrf_token %}
<input type="hidden" name="hidden" value="retrain" />
</form>
</div>
<div class="modal-footer">
<a id="retrain_model_form_submit" class="btn btn-primary" href="#"
>Retrain</a
>
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
</div>
</span>
</div>
<input type="hidden" name="hidden" value="retrain" />
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Cancel
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('retrain_model_form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Retrain</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Retraining...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#retrain_model_form_submit").on("click", function (e) {
e.preventDefault();
$("#retrain_model_form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,198 +1,193 @@
<div
class="modal fade"
tabindex="-1"
<dialog
id="set_license_modal"
role="dialog"
aria-labelledby="set_license_modal"
aria-hidden="true"
class="modal"
x-data="{
isSubmitting: false,
licenseType: '',
ccRemix: false,
ccNoCom: false,
ccAlike: false,
reset() {
this.isSubmitting = false;
this.licenseType = '';
this.ccRemix = false;
this.ccNoCom = false;
this.ccAlike = false;
},
get licenseString() {
if (this.licenseType !== 'cc') return 'no-license';
let str = 'by';
if (this.ccNoCom) str += '-nc';
if (!this.ccRemix) {
str += '-nd';
} else if (this.ccAlike) {
str += '-sa';
}
return str;
},
get licenseUrl() {
if (this.licenseType !== 'cc') return '';
return 'https://creativecommons.org/licenses/' + this.licenseString + '/4.0/';
},
get licenseImageUrl() {
if (this.licenseType !== 'cc') return '';
return 'https://licensebuttons.net/l/' + this.licenseString + '/4.0/88x31.png';
},
submit(formId) {
const form = document.getElementById(formId);
document.getElementById('license').value = this.licenseString;
if (form && form.checkValidity()) {
this.isSubmitting = true;
form.submit();
} else if (form) {
form.reportValidity();
}
}
}"
@close="reset()"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span>
<span class="sr-only">Close</span>
</button>
<h3 class="modal-title">Set License</h3>
<div class="modal-box">
<!-- Header -->
<h3 class="text-lg font-bold">Set License</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<div class="flex gap-4 mb-4">
<div class="flex-1">
<p>
Set the license for all data in this package:
<br /><br />
(For more information please visit our
<a
target="_blank"
href="https://wiki.envipath.org/index.php/License"
class="link link-primary"
>wiki</a
>.)
</p>
</div>
<div class="flex-none" x-show="licenseType === 'cc'" x-cloak>
<a :href="licenseUrl" target="_blank">
<img :src="licenseImageUrl" alt="CC License" />
</a>
</div>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-9">
<p>
Set the license for all data in this package:
<br />
<br />
(For more information please visit our
<a target="#" href="https://wiki.envipath.org/index.php/License"
>wiki</a
>.)
</p>
<form
id="set_license_form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
<div class="form-control">
<label class="label cursor-pointer justify-start gap-3">
<input
type="radio"
name="optlicense"
class="radio"
value="cc"
x-model="licenseType"
/>
<span class="label-text">Creative commons license</span>
</label>
</div>
<div class="ml-8 space-y-2" x-show="licenseType === 'cc'" x-cloak>
<div class="form-control">
<label class="label cursor-pointer justify-start gap-3">
<input type="checkbox" class="checkbox" x-model="ccRemix" />
<span class="label-text"
>Allow adaptations of your work to be shared</span
>
</label>
</div>
<div class="col-md-3">
<div id="ccfig"></div>
<div class="form-control">
<label class="label cursor-pointer justify-start gap-3">
<input type="checkbox" class="checkbox" x-model="ccNoCom" />
<span class="label-text">Prohibit commercial use</span>
</label>
</div>
<div class="form-control">
<label class="label cursor-pointer justify-start gap-3">
<input
type="checkbox"
class="checkbox"
x-model="ccAlike"
:disabled="!ccRemix"
/>
<span class="label-text">Share only if others share alike</span>
</label>
</div>
</div>
<form
id="set_license_form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
<div class="input-group">
<div class="radio">
<label
><input
type="radio"
name="optlicense"
onclick="cc()"
id="ccradio"
/>Creative commons license</label
>
</div>
<div>
<div class="checkbox">
<label
><input
type="checkbox"
value=""
onclick="cc()"
id="ccremix"
disabled
/>Allow adaptations of your work to be shared</label
>
</div>
<div class="checkbox">
<label
><input
type="checkbox"
value=""
onclick="cc()"
id="ccnocom"
disabled
/>Prohibit commercial use</label
>
</div>
<div class="checkbox">
<label
><input
type="checkbox"
value=""
onclick="cc()"
id="ccalike"
disabled
/>Share only if others share alike</label
>
</div>
</div>
<div class="radio">
<label
><input
type="radio"
name="optlicense"
onclick="cc()"
id="noccradio"
/>No creative commons license, contact package owner for license
information</label
>
</div>
</div>
<input type="hidden" id="license" name="license" />
</form>
</div>
<div class="modal-footer">
<button id="set_license_form_submit" class="btn btn-primary">
Submit
</button>
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
</div>
<div class="form-control mt-2">
<label class="label cursor-pointer justify-start gap-3">
<input
type="radio"
name="optlicense"
class="radio"
value="nocc"
x-model="licenseType"
/>
<span class="label-text"
>No creative commons license, contact package owner for license
information</span
>
</label>
</div>
<input type="hidden" id="license" name="license" />
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Cancel
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('set_license_form')"
:disabled="isSubmitting || !licenseType"
>
<span x-show="!isSubmitting">Submit</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Submitting...</span>
</button>
</div>
</div>
</div>
<script>
function ccstring(ccremix, ccnocom, ccalike) {
var ccstring = "by";
if (ccnocom) {
ccstring += "-nc";
}
if (!ccremix) {
ccstring += "-nd";
} else {
if (ccalike) {
ccstring += "-sa";
}
}
return ccstring;
}
function cc() {
var nocc = $("#noccradio").prop("checked");
var iscc = $("#ccradio").prop("checked");
if (nocc) {
$("#ccradio").prop("checked", false);
$("#ccremix").prop("checked", false);
$("#ccnocom").prop("checked", false);
$("#ccalike").prop("checked", false);
$("#ccremix").prop("disabled", true);
$("#ccnocom").prop("disabled", true);
$("#ccalike").prop("disabled", true);
} else if (iscc) {
$("#ccremix").prop("disabled", false);
$("#ccnocom").prop("disabled", false);
if ($("#ccremix").prop("checked")) {
$("#ccalike").prop("disabled", false);
} else {
$("#ccalike").prop("disabled", true);
}
}
var remix = $("#ccremix").prop("checked");
var nocom = $("#ccnocom").prop("checked");
var alike = $("#ccalike").prop("checked");
if (nocc) {
$("#set_license_form_submit").prop("disabled", false);
$("#ccfig").empty();
$("#license").val("no-license");
} else if (iscc) {
$("#set_license_form_submit").prop("disabled", false);
$("#ccfig").empty();
var ccstr = ccstring(remix, nocom, alike);
var link = `https://creativecommons.org/licenses/${ccstr}/4.0/`;
var imageLink = `https://licensebuttons.net/l/${ccstr}/4.0/88x31.png`;
var img_tpl = `<a href='${link}' target="_blank">
<img src='${imageLink}'>
</a>`;
$("#ccfig").append(img_tpl);
$("#license").val(ccstr);
} else {
$("#ccfig").empty();
$("#set_license_form_submit").prop("disabled", true);
$("#license").val("no-license");
}
}
$(function () {
// Disable by default as nothing is selected
cc();
$("#set_license_form_submit").prop("disabled", true);
$("#set_license_form_submit").on("click", function (e) {
e.preventDefault();
$("#set_license_form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,62 +1,69 @@
{% load static %}
<!-- Update Scenario Additional Information-->
<div
<dialog
id="update_scenario_additional_information_modal"
class="modal"
tabindex="-1"
x-data="modalForm()"
@close="reset()"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
<h3 class="modal-title">Update Additional Information</h3>
</div>
<div class="modal-body">
<form
id="edit-scenario-additional-information-modal-form"
accept-charset="UTF-8"
action=""
data-remote="true"
method="post"
>
{% csrf_token %}
{% for widget in update_widgets %}
{{ widget|safe }}
{% endfor %}
<input
type="hidden"
name="hidden"
value="set-additional-information"
/>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button
type="button"
class="btn btn-primary"
id="edit-scenario-additional-information-modal-submit"
>
Update
</button>
</div>
<div class="modal-box">
<!-- Header -->
<h3 class="text-lg font-bold">Update Additional Information</h3>
<!-- Close button (X) -->
<form method="dialog">
<button
class="btn btn-sm btn-circle btn-ghost absolute top-2 right-2"
:disabled="isSubmitting"
>
</button>
</form>
<!-- Body -->
<div class="py-4">
<form
id="edit-scenario-additional-information-modal-form"
accept-charset="UTF-8"
action=""
method="post"
>
{% csrf_token %}
{% for widget in update_widgets %}
{{ widget|safe }}
{% endfor %}
<input type="hidden" name="hidden" value="set-additional-information" />
</form>
</div>
<!-- Footer -->
<div class="modal-action">
<button
type="button"
class="btn"
onclick="this.closest('dialog').close()"
:disabled="isSubmitting"
>
Close
</button>
<button
type="button"
class="btn btn-primary"
@click="submit('edit-scenario-additional-information-modal-form')"
:disabled="isSubmitting"
>
<span x-show="!isSubmitting">Update</span>
<span
x-show="isSubmitting"
class="loading loading-spinner loading-sm"
></span>
<span x-show="isSubmitting">Updating...</span>
</button>
</div>
</div>
</div>
<script>
$(function () {
$("#edit-scenario-additional-information-modal-submit").click(function (e) {
e.preventDefault();
$("#edit-scenario-additional-information-modal-form").submit();
});
});
</script>
<!-- Backdrop -->
<form method="dialog" class="modal-backdrop">
<button :disabled="isSubmitting">close</button>
</form>
</dialog>

View File

@ -1,178 +0,0 @@
{% load static %}
<div
class="modal fade bs-modal-lg"
id="predict_modal"
tabindex="-1"
aria-labelledby="predict_modal"
aria-modal="true"
role="dialog"
>
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Predict a Pathway</h4>
</div>
<div class="modal-body">
<form
id="predict_modal_form"
accept-charset="UTF-8"
action="{{ meta.current_package.url }}/pathway"
data-remote="true"
method="post"
>
{% csrf_token %}
<div class="row">
<div class="col-md-6">
<label for="name">Name</label>
<input
id="name"
class="form-control"
name="name"
placeholder="Name"
/>
<label for="description">Description</label>
<input
id="description"
class="form-control"
name="description"
placeholder="Description"
/>
</div>
<div class="col-md-6">
<label for="predict">Predict pathway or build yourself?</label>
<div class="radio" id="predict">
<p>
<label>
<input
type="radio"
name="predict"
id="radioPredict"
value="predict"
checked
/>Predict pathway
</label>
</p>
<p>
<label>
<input
type="radio"
name="predict"
id="radioIncremental"
value="incremental"
/>Incremental prediction
</label>
</p>
<p>
<label>
<input
type="radio"
name="predict"
id="radioBuild"
value="build"
/>Build pathway
</label>
</p>
</div>
</div>
</div>
<label for="predict-modal-smiles">SMILES</label>
<input
type="text"
class="form-control"
name="smiles"
placeholder="SMILES"
id="predict-modal-smiles"
/>
<p id="ketcher_container"></p>
<div>
<iframe
id="predict-modal-ketcher"
src="{% static '/js/ketcher2/ketcher.html' %}"
width="100%"
height="510"
></iframe>
</div>
<label for="prediction-setting">Default Prediction Setting</label>
<select
id="prediction-setting"
name="prediction-setting"
class="form-control"
data-width="100%"
>
<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|safe }}{% if s.id == meta.user.default_setting.id %}
<i>(User default)</i>
{% endif %}
</option>
{% endfor %}
</select>
</form>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary pull-left"
data-dismiss="modal"
>
Close
</button>
<button type="button" class="btn btn-primary" id="predictButton">
Predict
</button>
</div>
</div>
</div>
</div>
<script>
function predictModalketcherToPredictModalTextInput() {
$("#predict-modal-smiles").val(this.ketcher.getSmiles());
}
$(function () {
$("#predict-modal-ketcher").on("load", function () {
const checkKetcherReady = () => {
win = this.contentWindow;
if (win.ketcher && "editor" in win.ketcher) {
win.ketcher.editor.event.change.handlers.push({
once: false,
priority: 0,
f: predictModalketcherToPredictModalTextInput,
ketcher: win.ketcher,
});
} else {
setTimeout(checkKetcherReady, 100);
}
};
checkKetcherReady();
});
$("#predictButton").on("click", function (e) {
e.preventDefault();
$(this).prop("disabled", true);
// loading button
// validation
// existing pws...
// submit form
$("#predict_modal_form").submit();
});
});
</script>

View File

@ -1,5 +1,10 @@
{% load static %}
<dialog id="search_modal" class="modal @max-sm:modal-top justify-center">
<dialog
id="search_modal"
class="modal @max-sm:modal-top justify-center"
x-data="searchModal()"
@close="reset()"
>
<div class="modal-box h-full w-lvw p-1 sm:h-8/12 sm:w-[85vw] sm:max-w-5xl">
<!-- Search Input and Mode Selector -->
<div class="form-control mb-4 w-full shrink-0">
@ -23,7 +28,9 @@
<input
type="text"
autofocus
id="modal_searchbar"
x-ref="searchbar"
x-model="query"
@keydown.enter="performSearch('{{ SERVER_BASE }}')"
placeholder="Benfuracarb"
class="grow"
aria-label="Search"
@ -35,12 +42,11 @@
<button
type="button"
tabindex="0"
id="modal_mode_button"
popovertarget="search_dropdown_menu"
style="anchor-name:--1"
style="anchor-name: --1"
class="btn join-item btn-ghost"
>
Text
<span x-text="searchModeLabel"></span>
<svg
class="ml-1 h-4 w-4"
fill="none"
@ -59,13 +65,14 @@
tabindex="0"
class="dropdown dropdown-end menu bg-base-200 rounded-box w-64 p-2 shadow-lg"
popover
x-ref="modeDropdown"
id="search_dropdown_menu"
style="position-anchor:--anchor-2"
style="position-anchor: --anchor-2"
>
<li class="menu-title">Text</li>
<li>
<a
id="modal_dropdown_text"
@click.prevent="setSearchMode('text', 'Text')"
class="tooltip tooltip-left"
data-tip="Search on object names and descriptions"
>
@ -75,7 +82,7 @@
<li class="menu-title">SMILES</li>
<li>
<a
id="modal_dropdown_smiles_default"
@click.prevent="setSearchMode('smiles_default', 'Default')"
class="tooltip tooltip-left"
data-tip="Ignores stereochemistry and charge"
>
@ -84,7 +91,7 @@
</li>
<li>
<a
id="modal_dropdown_smiles_canonical"
@click.prevent="setSearchMode('smiles_canonical', 'Canonical')"
class="tooltip tooltip-left"
data-tip="Ignores stereochemistry, preserves charge"
>
@ -93,7 +100,7 @@
</li>
<li>
<a
id="modal_dropdown_smiles_exact"
@click.prevent="setSearchMode('smiles_exact', 'Exact')"
class="tooltip tooltip-left"
data-tip="Exact match for stereochemistry and charge"
>
@ -103,7 +110,7 @@
<li class="menu-title">InChI</li>
<li>
<a
id="modal_dropdown_inchikey"
@click.prevent="setSearchMode('inchikey', 'InChIKey')"
class="tooltip tooltip-left"
data-tip="Search by InChIKey"
>
@ -115,7 +122,7 @@
<button
type="button"
id="modal_search_button"
@click="performSearch('{{ SERVER_BASE }}')"
class="btn btn-xs btn-ghost join-item"
>
<kbd class="kbd kbd-sm text-base-content/50 p-1">
@ -143,18 +150,62 @@
<div class="form-control mb-4 shrink-0">
<!-- Pills Container -->
<div
id="modal_package_pills_container"
class="border-base-300 m-3 flex min-h-12 flex-wrap items-center gap-2 rounded-lg border-2 border-dashed p-3"
>
<!-- Pills will be added here dynamically -->
<!-- Dynamic Pills -->
<template x-for="pkg in selectedPackages" :key="pkg.url">
<span class="badge badge-outline gap-2 max-w-xs">
<span class="truncate" :title="pkg.name" x-text="pkg.name"></span>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4 cursor-pointer hover:text-error shrink-0 rotate-45"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
@click="removePackage(pkg.url)"
>
<path d="M5 12h14" />
<path d="M12 5v14" />
</svg>
</span>
</template>
<!-- Add Package Button -->
<button
type="button"
popovertarget="package_dropdown_menu"
style="anchor-name: --anchor-packages"
class="btn btn-sm btn-ghost gap-2 text-base-content/50"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-plus-icon lucide-plus"
>
<path d="M5 12h14" />
<path d="M12 5v14" />
</svg>
Add Package
</button>
</div>
<!-- Package Dropdown Menu -->
<ul
class="dropdown dropdown-center menu bg-base-200 rounded-box max-h-96 w-80 overflow-y-auto p-2 shadow-lg"
popover
x-ref="packageDropdown"
id="package_dropdown_menu"
style="position-anchor:--anchor-packages"
style="position-anchor: --anchor-packages"
>
{% if unreviewed_packages %}
<li class="menu-title">Reviewed Packages</li>
@ -164,11 +215,13 @@
class="package-option flex items-center justify-between"
data-package-url="{{ obj.url }}"
data-package-name="{{ obj.name }}"
@click.prevent.stop="togglePackage('{{ obj.url }}', '{{ obj.name }}')"
>
<span>{{ obj.name }}</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class="package-checkmark hidden h-4 w-4"
class="h-4 w-4"
:class="isPackageSelected('{{ obj.url }}') ? '' : 'hidden'"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
@ -190,11 +243,13 @@
class="package-option flex items-center justify-between"
data-package-url="{{ obj.url }}"
data-package-name="{{ obj.name }}"
@click.prevent.stop="togglePackage('{{ obj.url }}', '{{ obj.name }}')"
>
<span>{{ obj.name }}</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class="package-checkmark hidden h-4 w-4"
class="h-4 w-4"
:class="isPackageSelected('{{ obj.url }}') ? '' : 'hidden'"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
@ -217,11 +272,13 @@
class="package-option flex items-center justify-between"
data-package-url="{{ obj.url }}"
data-package-name="{{ obj.name }}"
@click.prevent.stop="togglePackage('{{ obj.url }}', '{{ obj.name }}')"
>
<span>{{ obj.name }}</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class="package-checkmark hidden h-4 w-4"
class="h-4 w-4"
:class="isPackageSelected('{{ obj.url }}') ? '' : 'hidden'"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
@ -241,12 +298,201 @@
</div>
<!-- Loading Indicator -->
<div id="search_loading" class="hidden shrink-0 justify-center py-8">
<div x-show="isSearching" class="flex shrink-0 justify-center py-8">
<span class="loading loading-spinner loading-lg text-primary"></span>
</div>
<!-- Results Container - scrollable -->
<div id="search_results" class="min-h-0 flex-1 overflow-y-auto p-2"></div>
<!-- Results Container -->
<div class="min-h-0 flex-1 overflow-y-auto p-2">
<!-- No packages selected error -->
<template x-if="results && results.error === 'no_packages'">
<div class="alert alert-info">
<svg
class="w-6 h-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span>Please select at least one package</span>
</div>
</template>
<!-- Search error -->
<template x-if="error">
<div class="alert alert-error">
<svg
class="w-6 h-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span x-text="error"></span>
</div>
</template>
<!-- No results -->
<template x-if="results && !results.error && !hasResults()">
<div class="alert alert-warning">
<svg
class="w-6 h-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
/>
</svg>
<span>No results found</span>
</div>
</template>
<!-- Results display -->
<template x-if="results && !results.error && hasResults()">
<div class="mb-2">
<div class="text-sm font-semibold text-base-content/70 mb-2">
Results
</div>
<!-- Compounds -->
<template x-if="results.Compounds && results.Compounds.length > 0">
<div class="collapse collapse-arrow bg-base-200 mb-2">
<input type="checkbox" checked />
<div class="collapse-title font-medium">
Compounds
<span
class="badge badge-neutral badge-sm ml-2"
x-text="results.Compounds.length"
></span>
</div>
<div class="collapse-content">
<template x-for="item in results.Compounds" :key="item.url">
<a
:href="item.url"
class="block px-4 py-2 hover:bg-base-300 rounded-lg transition-colors"
x-text="item.name"
></a>
</template>
</div>
</div>
</template>
<!-- Compound Structures -->
<template
x-if="results['Compound Structures'] && results['Compound Structures'].length > 0"
>
<div class="collapse collapse-arrow bg-base-200 mb-2">
<input type="checkbox" checked />
<div class="collapse-title font-medium">
Compound Structures
<span
class="badge badge-neutral badge-sm ml-2"
x-text="results['Compound Structures'].length"
></span>
</div>
<div class="collapse-content">
<template
x-for="item in results['Compound Structures']"
:key="item.url"
>
<a
:href="item.url"
class="block px-4 py-2 hover:bg-base-300 rounded-lg transition-colors"
x-text="item.name"
></a>
</template>
</div>
</div>
</template>
<!-- Rules -->
<template x-if="results.Rules && results.Rules.length > 0">
<div class="collapse collapse-arrow bg-base-200 mb-2">
<input type="checkbox" checked />
<div class="collapse-title font-medium">
Rules
<span
class="badge badge-neutral badge-sm ml-2"
x-text="results.Rules.length"
></span>
</div>
<div class="collapse-content">
<template x-for="item in results.Rules" :key="item.url">
<a
:href="item.url"
class="block px-4 py-2 hover:bg-base-300 rounded-lg transition-colors"
x-text="item.name"
></a>
</template>
</div>
</div>
</template>
<!-- Reactions -->
<template x-if="results.Reactions && results.Reactions.length > 0">
<div class="collapse collapse-arrow bg-base-200 mb-2">
<input type="checkbox" checked />
<div class="collapse-title font-medium">
Reactions
<span
class="badge badge-neutral badge-sm ml-2"
x-text="results.Reactions.length"
></span>
</div>
<div class="collapse-content">
<template x-for="item in results.Reactions" :key="item.url">
<a
:href="item.url"
class="block px-4 py-2 hover:bg-base-300 rounded-lg transition-colors"
x-text="item.name"
></a>
</template>
</div>
</div>
</template>
<!-- Pathways -->
<template x-if="results.Pathways && results.Pathways.length > 0">
<div class="collapse collapse-arrow bg-base-200 mb-2">
<input type="checkbox" checked />
<div class="collapse-title font-medium">
Pathways
<span
class="badge badge-neutral badge-sm ml-2"
x-text="results.Pathways.length"
></span>
</div>
<div class="collapse-content">
<template x-for="item in results.Pathways" :key="item.url">
<a
:href="item.url"
class="block px-4 py-2 hover:bg-base-300 rounded-lg transition-colors"
x-text="item.name"
></a>
</template>
</div>
</div>
</template>
</div>
</template>
</div>
</div>
<!-- Backdrop to close -->
@ -254,433 +500,3 @@
<button>close</button>
</form>
</dialog>
<script>
(function () {
// Package Selector Module - Data-driven multiselect package selection
const PackageSelector = {
// Single source of truth: array of selected packages
selectedPackages: [],
elements: {
pillsContainer: null,
packageDropdown: null,
packageOptions: null,
},
init() {
this.cacheElements();
this.loadInitialSelection();
this.attachEventListeners();
this.render();
},
cacheElements() {
this.elements.pillsContainer = document.getElementById(
"modal_package_pills_container",
);
this.elements.packageDropdown = document.getElementById(
"package_dropdown_menu",
);
this.elements.packageOptions =
document.querySelectorAll(".package-option");
},
loadInitialSelection() {
// Load pre-selected packages from server-rendered pills
const existingPills =
this.elements.pillsContainer.querySelectorAll(".badge");
existingPills.forEach((pill) => {
this.selectedPackages.push({
url: pill.dataset.packageUrl,
name: pill.dataset.packageName,
});
});
// If no pills found, select all reviewed packages by default
if (this.selectedPackages.length === 0) {
// Iterate through all menu items and collect reviewed packages
const menuItems =
this.elements.packageDropdown.querySelectorAll("li");
for (const item of menuItems) {
// Check if this is the "Unreviewed Packages" menu title
if (
item.classList.contains("menu-title") &&
item.textContent.trim() === "Unreviewed Packages"
) {
break; // Stop processing after this point
}
// Check for package options (only reviewed packages reach here)
const packageOption = item.querySelector(".package-option");
if (packageOption) {
this.selectedPackages.push({
url: packageOption.dataset.packageUrl,
name: packageOption.dataset.packageName,
});
}
}
}
},
attachEventListeners() {
// Toggle package selection on dropdown item click
this.elements.packageOptions.forEach((option) => {
option.addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation(); // Prevent dropdown from closing
const packageUrl = option.dataset.packageUrl;
const packageName = option.dataset.packageName;
this.togglePackageSelection(packageUrl, packageName);
});
});
// Remove package when X is clicked (using event delegation)
this.elements.pillsContainer.addEventListener("click", (e) => {
if (
e.target.classList.contains("package-remove-btn") ||
e.target.closest(".package-remove-btn")
) {
const pill = e.target.closest(".badge");
if (pill) {
const packageUrl = pill.dataset.packageUrl;
this.removePackage(packageUrl);
}
}
});
},
togglePackageSelection(packageUrl, packageName) {
const index = this.selectedPackages.findIndex(
(pkg) => pkg.url === packageUrl,
);
if (index !== -1) {
// Remove from selection
this.selectedPackages.splice(index, 1);
} else {
// Add to selection
this.selectedPackages.push({ url: packageUrl, name: packageName });
}
this.render();
},
removePackage(packageUrl) {
const index = this.selectedPackages.findIndex(
(pkg) => pkg.url === packageUrl,
);
if (index !== -1) {
this.selectedPackages.splice(index, 1);
this.render();
}
},
render() {
this.renderPills();
this.renderAddButton();
this.renderCheckmarks();
},
renderPills() {
// Clear existing pills and button (except placeholder)
const pills = this.elements.pillsContainer.querySelectorAll(".badge");
pills.forEach((pill) => pill.remove());
const existingButton = this.elements.pillsContainer.querySelector(
"#modal_package_add_button",
);
if (existingButton) {
existingButton.remove();
}
// Create pills from data
this.selectedPackages.forEach((pkg) => {
const pill = this.createPillElement(pkg.url, pkg.name);
this.elements.pillsContainer.appendChild(pill);
});
},
renderAddButton() {
// Only render button if there are packages available
if (this.elements.packageOptions.length === 0) {
return;
}
const button = document.createElement("button");
button.type = "button";
button.id = "modal_package_add_button";
button.setAttribute("popovertarget", "package_dropdown_menu");
button.style.cssText = "anchor-name:--anchor-packages";
button.className = "btn btn-sm btn-ghost gap-2 text-base-content/50";
button.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-plus-icon lucide-plus"><path d="M5 12h14"/><path d="M12 5v14"/></svg>
Add Package
`;
this.elements.pillsContainer.appendChild(button);
},
createPillElement(packageUrl, packageName) {
const pill = document.createElement("span");
pill.className = "badge badge-outline gap-2 max-w-xs";
pill.dataset.packageUrl = packageUrl;
pill.dataset.packageName = packageName;
pill.innerHTML = `
<span class="truncate" title="${packageName}">${packageName}</span>
<svg xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4 cursor-pointer hover:text-error package-remove-btn flex-shrink-0 rotate-45"
viewBox="0 0 24 24"
fill="none" stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M5 12h14"/><path d="M12 5v14"/>
</svg>
`;
return pill;
},
renderCheckmarks() {
// Update all checkmarks based on selected packages
this.elements.packageOptions.forEach((option) => {
const packageUrl = option.dataset.packageUrl;
const isSelected = this.selectedPackages.some(
(pkg) => pkg.url === packageUrl,
);
const checkmark = option.querySelector(".package-checkmark");
if (checkmark) {
checkmark.classList.toggle("hidden", !isSelected);
}
});
},
getSelectedPackages() {
return this.selectedPackages.map((pkg) => pkg.url);
},
};
// Modal and Search Management
const modal = document.getElementById("search_modal");
const searchbar = document.getElementById("modal_searchbar");
const searchButton = document.getElementById("modal_search_button");
const modeButton = document.getElementById("modal_mode_button");
const resultsDiv = document.getElementById("search_results");
const loadingDiv = document.getElementById("search_loading");
// MutationObserver to detect when modal opens
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.attributeName === "open" && modal.open) {
PackageSelector.render();
// Delay focus to allow CSS transitions to complete (modal has 0.3s transition)
setTimeout(() => {
searchbar.focus();
}, 320);
}
});
});
observer.observe(modal, { attributes: true });
// Close modal when clicking outside (on the backdrop)
// According to DaisyUI docs: https://daisyui.com/components/modal/
// The backdrop form with method="dialog" should handle closing automatically when its button is clicked.
// We also handle clicks directly on the dialog element (backdrop area) or the backdrop form.
modal.addEventListener("click", function (event) {
const backdrop = modal.querySelector(".modal-backdrop");
const modalBox = modal.querySelector(".modal-box");
// Close if clicking directly on the dialog element (backdrop area)
// or on the backdrop form (but ensure we're not clicking on modal-box content)
if (
event.target === modal ||
(backdrop &&
(event.target === backdrop || backdrop.contains(event.target)) &&
!modalBox.contains(event.target))
) {
modal.close();
}
});
// Clear results when modal closes
modal.addEventListener("close", function () {
resultsDiv.innerHTML = "";
loadingDiv.classList.add("hidden");
searchbar.value = "";
});
// Mode dropdown handlers
const dropdownMenu = document.getElementById("search_dropdown_menu");
const modeButtons = [
{ id: "modal_dropdown_text", text: "Text" },
{ id: "modal_dropdown_smiles_default", text: "Default" },
{ id: "modal_dropdown_smiles_canonical", text: "Canonical" },
{ id: "modal_dropdown_smiles_exact", text: "Exact" },
{ id: "modal_dropdown_inchikey", text: "InChIKey" },
];
modeButtons.forEach(({ id, text }) => {
document.getElementById(id).addEventListener("click", function (e) {
e.preventDefault();
modeButton.innerHTML =
text +
` <svg class="w-4 h-4 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
</svg>`;
// Close dropdown using popover API
if (dropdownMenu && typeof dropdownMenu.hidePopover === "function") {
dropdownMenu.hidePopover();
}
});
});
// Initialize Package Selector
PackageSelector.init();
// Search Response Handler
function handleSearchResponse(data) {
resultsDiv.innerHTML = "";
function makeContent(objs) {
let links = "";
objs.forEach((obj) => {
links += `<a href="${obj.url}" class="block px-4 py-2 hover:bg-base-300 rounded-lg transition-colors">${obj.name}</a>`;
});
return links;
}
let allEmpty = true;
let content = "";
// Category order for better UX
const categoryOrder = [
"Compounds",
"Compound Structures",
"Rules",
"Reactions",
"Pathways",
];
categoryOrder.forEach((key) => {
if (!data[key] || data[key].length < 1) {
return;
}
allEmpty = false;
content += `
<div class="collapse collapse-arrow bg-base-200 mb-2">
<input type="checkbox" checked />
<div class="collapse-title font-medium">
${key} <span class="badge badge-neutral badge-sm ml-2">${data[key].length}</span>
</div>
<div class="collapse-content">
${makeContent(data[key])}
</div>
</div>
`;
});
if (allEmpty) {
resultsDiv.innerHTML = `
<div class="alert alert-warning">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
</svg>
<span>No results found</span>
</div>
`;
} else {
resultsDiv.innerHTML = `
<div class="mb-2">
<div class="text-sm font-semibold text-base-content/70 mb-2">Results</div>
${content}
</div>
`;
}
}
// Search Execution
function performSearch(e) {
e.preventDefault();
const query = searchbar.value.trim();
if (!query) {
console.log("Search phrase empty, won't do search");
return;
}
const selPacks = PackageSelector.getSelectedPackages();
if (selPacks.length < 1) {
console.log("No package selected, won't do search");
resultsDiv.innerHTML = `
<div class="alert alert-info">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<span>Please select at least one package</span>
</div>
`;
return;
}
const mode = modeButton.textContent.trim().toLowerCase();
const params = new URLSearchParams();
selPacks.forEach((pack) => params.append("packages", pack));
params.append("search", query);
params.append("mode", mode);
// Show loading
loadingDiv.classList.remove("hidden");
resultsDiv.innerHTML = "";
fetch(`{{ SERVER_BASE }}/search?${params.toString()}`, {
method: "GET",
headers: {
Accept: "application/json",
},
})
.then((response) => {
if (!response.ok) {
throw new Error("Search request failed");
}
return response.json();
})
.then((result) => {
loadingDiv.classList.add("hidden");
handleSearchResponse(result);
})
.catch((error) => {
loadingDiv.classList.add("hidden");
console.error("Search error:", error);
resultsDiv.innerHTML = `
<div class="alert alert-error">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<span>Search failed. Please try again.</span>
</div>
`;
});
}
// Event listeners for search
searchButton.addEventListener("click", performSearch);
searchbar.addEventListener("keydown", function (e) {
if (e.key === "Enter") {
performSearch(e);
}
});
})();
</script>