forked from enviPath/enviPy
[Feature] Server pagination implementation (#243)
## Major Changes - Implement a REST style API app in epapi - Currently implements a GET method for all entity types in the browse menu (both package level and global) - Provides paginated results per default with query style filtering for reviewed vs unreviewed. - Provides new paginated templates with thin wrappers per entity types for easier maintainability - Implements e2e tests for the API ## Minor changes - Added more comprehensive gitignore to cover coverage reports and other test/node.js etc. data. - Add additional CI file for API tests that only gets triggered on API relevant changes. ## ⚠️ Currently only works with session-based authentication. Token based will be added in new PR. Co-authored-by: Tim Lorsbach <tim@lorsba.ch> Co-authored-by: jebus <lorsbach@envipath.com> Reviewed-on: enviPath/enviPy#243 Co-authored-by: Tobias O <tobias.olenyi@envipath.com> Co-committed-by: Tobias O <tobias.olenyi@envipath.com>
This commit is contained in:
@ -1,10 +0,0 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
onclick="document.getElementById('new_compound_modal').showModal(); return false;"
|
||||
>
|
||||
<span class="glyphicon glyphicon-plus"></span> New Compound</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,10 +0,0 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
onclick="document.getElementById('new_compound_structure_modal').showModal(); return false;"
|
||||
>
|
||||
<span class="glyphicon glyphicon-plus"></span> New Compound Structure</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,10 +0,0 @@
|
||||
{% if meta.can_edit and meta.enabled_features.MODEL_BUILDING %}
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
onclick="document.getElementById('new_model_modal').showModal(); return false;"
|
||||
>
|
||||
<span class="glyphicon glyphicon-plus"></span> New Model</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,25 +0,0 @@
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
onclick="document.getElementById('new_package_modal').showModal(); return false;"
|
||||
>
|
||||
<span class="glyphicon glyphicon-plus"></span> New Package</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
onclick="document.getElementById('import_package_modal').showModal(); return false;"
|
||||
>
|
||||
<span class="glyphicon glyphicon-import"></span> Import Package from JSON</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
onclick="document.getElementById('import_legacy_package_modal').showModal(); return false;"
|
||||
>
|
||||
<span class="glyphicon glyphicon-import"></span> Import Package from legacy
|
||||
JSON</a
|
||||
>
|
||||
</li>
|
||||
@ -1,9 +0,0 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a
|
||||
href="{% if meta.current_package %}{{ meta.current_package.url }}/predict{% else %}{{ meta.server_url }}/predict{% endif %}"
|
||||
>
|
||||
<span class="glyphicon glyphicon-plus"></span> New Pathway</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,10 +0,0 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
onclick="document.getElementById('new_reaction_modal').showModal(); return false;"
|
||||
>
|
||||
<span class="glyphicon glyphicon-plus"></span> New Reaction</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,10 +0,0 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
onclick="document.getElementById('new_rule_modal').showModal(); return false;"
|
||||
>
|
||||
<span class="glyphicon glyphicon-plus"></span> New Rule</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
@ -1,10 +0,0 @@
|
||||
{% if meta.can_edit %}
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
onclick="document.getElementById('new_scenario_modal').showModal(); return false;"
|
||||
>
|
||||
<span class="glyphicon glyphicon-plus"></span> New Scenario</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
98
templates/collections/_paginated_list_partial.html
Normal file
98
templates/collections/_paginated_list_partial.html
Normal file
@ -0,0 +1,98 @@
|
||||
{# Partial for paginated list content - expects to be inside a remotePaginatedList Alpine.js context #}
|
||||
{# Variables: empty_text (string), show_review_badge (bool), always_show_badge (bool) #}
|
||||
|
||||
{# Loading state #}
|
||||
<div x-show="isLoading">{% include "components/loading-spinner.html" %}</div>
|
||||
|
||||
{# Error state #}
|
||||
<div
|
||||
x-show="!isLoading && error"
|
||||
class="alert alert-error/50 text-sm"
|
||||
x-text="error"
|
||||
></div>
|
||||
|
||||
{# Content #}
|
||||
<template x-if="!isLoading && !error">
|
||||
<div>
|
||||
{# Empty state #}
|
||||
<div
|
||||
x-show="totalItems === 0"
|
||||
class="text-base-content/70 py-8 text-center"
|
||||
>
|
||||
<p>No {{ empty_text|default:"items" }} found.</p>
|
||||
</div>
|
||||
|
||||
{# Items list #}
|
||||
<ul class="menu bg-base-100 rounded-box w-full" x-show="totalItems > 0">
|
||||
<template x-for="obj in paginatedItems" :key="obj.url">
|
||||
<li>
|
||||
<a :href="obj.url" class="hover:bg-base-200">
|
||||
<span x-text="obj.name"></span>
|
||||
{% if show_review_badge %}
|
||||
<span
|
||||
class="tooltip tooltip-left ml-auto"
|
||||
data-tip="Reviewed"
|
||||
{% if not always_show_badge %}
|
||||
x-show="obj.review_status === 'reviewed'"
|
||||
{% endif %}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-check-icon lucide-check"
|
||||
>
|
||||
<path d="M20 6 9 17l-5-5" />
|
||||
</svg>
|
||||
</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
|
||||
{# Pagination controls #}
|
||||
<div
|
||||
x-show="totalPages > 1"
|
||||
class="mt-4 flex items-center justify-between px-2"
|
||||
>
|
||||
<span class="text-base-content/70 text-sm">
|
||||
Showing <span x-text="showingStart"></span>-<span
|
||||
x-text="showingEnd"
|
||||
></span>
|
||||
of <span x-text="totalItems"></span>
|
||||
</span>
|
||||
<div class="join">
|
||||
<button
|
||||
class="join-item btn btn-sm"
|
||||
:disabled="currentPage === 1"
|
||||
@click="prevPage()"
|
||||
>
|
||||
«
|
||||
</button>
|
||||
<template x-for="item in pageNumbers" :key="item.key">
|
||||
<button
|
||||
class="join-item btn btn-sm"
|
||||
:class="{ 'btn-active': item.page === currentPage }"
|
||||
:disabled="item.isEllipsis"
|
||||
@click="!item.isEllipsis && goToPage(item.page)"
|
||||
x-text="item.page"
|
||||
></button>
|
||||
</template>
|
||||
<button
|
||||
class="join-item btn btn-sm"
|
||||
:disabled="currentPage === totalPages"
|
||||
@click="nextPage()"
|
||||
>
|
||||
»
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
33
templates/collections/compounds_paginated.html
Normal file
33
templates/collections/compounds_paginated.html
Normal file
@ -0,0 +1,33 @@
|
||||
{% extends "collections/paginated_base.html" %}
|
||||
|
||||
{% block page_title %}Compounds{% endblock %}
|
||||
|
||||
{% block action_button %}
|
||||
{% if meta.can_edit %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary btn-sm"
|
||||
onclick="document.getElementById('new_compound_modal').showModal(); return false;"
|
||||
>
|
||||
New Compound
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endblock action_button %}
|
||||
|
||||
{% block action_modals %}
|
||||
{% include "modals/collections/new_compound_modal.html" %}
|
||||
{% endblock action_modals %}
|
||||
|
||||
{% block description %}
|
||||
<p>
|
||||
A compound stores the structure of a molecule and can include
|
||||
meta-information.
|
||||
</p>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/compounds"
|
||||
class="link link-primary"
|
||||
>
|
||||
Learn more >>
|
||||
</a>
|
||||
{% endblock description %}
|
||||
32
templates/collections/models_paginated.html
Normal file
32
templates/collections/models_paginated.html
Normal file
@ -0,0 +1,32 @@
|
||||
{% extends "collections/paginated_base.html" %}
|
||||
|
||||
{% block page_title %}Models{% endblock %}
|
||||
|
||||
{% block action_button %}
|
||||
{% if meta.can_edit and meta.enabled_features.MODEL_BUILDING %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary btn-sm"
|
||||
onclick="document.getElementById('new_model_modal').showModal(); return false;"
|
||||
>
|
||||
New Model
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endblock action_button %}
|
||||
|
||||
{% block action_modals %}
|
||||
{% if meta.enabled_features.MODEL_BUILDING %}
|
||||
{% include "modals/collections/new_model_modal.html" %}
|
||||
{% endif %}
|
||||
{% endblock action_modals %}
|
||||
|
||||
{% block description %}
|
||||
<p>A model applies machine learning to limit the combinatorial explosion.</p>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/relative_reasoning"
|
||||
class="link link-primary"
|
||||
>
|
||||
Learn more >>
|
||||
</a>
|
||||
{% endblock description %}
|
||||
@ -4,7 +4,8 @@
|
||||
|
||||
{# Serialize objects data for Alpine pagination #}
|
||||
{# prettier-ignore-start #}
|
||||
{# FIXME: This is a hack to get the objects data into the JavaScript code. #}
|
||||
{# FIXME: This is a hack to get the objects data into the JavaScript code. #}
|
||||
{% if object_type != 'scenario' %}
|
||||
<script>
|
||||
window.reviewedObjects = [
|
||||
{% for obj in reviewed_objects %}
|
||||
@ -17,46 +18,23 @@
|
||||
{% endfor %}
|
||||
];
|
||||
</script>
|
||||
{# prettier-ignore-end #}
|
||||
{% endif %}
|
||||
{# prettier-ignore-end #}
|
||||
|
||||
{% if object_type != 'package' %}
|
||||
<div class="px-8 py-4">
|
||||
<input
|
||||
type="text"
|
||||
id="object-search"
|
||||
class="input input-bordered hidden w-full max-w-xs"
|
||||
placeholder="Search by name"
|
||||
/>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="px-8 py-4">
|
||||
<input
|
||||
type="text"
|
||||
id="object-search"
|
||||
class="input input-bordered hidden w-full max-w-xs"
|
||||
placeholder="Search by name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{% block action_modals %}
|
||||
{% if object_type == 'package' %}
|
||||
{% include "modals/collections/new_package_modal.html" %}
|
||||
{% include "modals/collections/import_package_modal.html" %}
|
||||
{% include "modals/collections/import_legacy_package_modal.html" %}
|
||||
{% elif object_type == 'compound' %}
|
||||
{% include "modals/collections/new_compound_modal.html" %}
|
||||
{% elif object_type == 'rule' %}
|
||||
{% include "modals/collections/new_rule_modal.html" %}
|
||||
{% elif object_type == 'reaction' %}
|
||||
{% include "modals/collections/new_reaction_modal.html" %}
|
||||
{% elif object_type == 'pathway' %}
|
||||
{# {% include "modals/collections/new_pathway_modal.html" %} #}
|
||||
{% elif object_type == 'node' %}
|
||||
{% if object_type == 'node' %}
|
||||
{% include "modals/collections/new_node_modal.html" %}
|
||||
{% elif object_type == 'edge' %}
|
||||
{% include "modals/collections/new_edge_modal.html" %}
|
||||
{% elif object_type == 'scenario' %}
|
||||
{% include "modals/collections/new_scenario_modal.html" %}
|
||||
{% elif object_type == 'model' %}
|
||||
{% include "modals/collections/new_model_modal.html" %}
|
||||
{% elif object_type == 'setting' %}
|
||||
{#{% include "modals/collections/new_setting_modal.html" %}#}
|
||||
{% elif object_type == 'user' %}
|
||||
<div></div>
|
||||
{% elif object_type == 'group' %}
|
||||
{% include "modals/collections/new_group_modal.html" %}
|
||||
{% endif %}
|
||||
{% endblock action_modals %}
|
||||
|
||||
@ -66,32 +44,10 @@
|
||||
<div class="card-body px-0 py-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="card-title text-2xl">
|
||||
{% if object_type == 'package' %}
|
||||
Packages
|
||||
{% elif object_type == 'compound' %}
|
||||
Compounds
|
||||
{% elif object_type == 'structure' %}
|
||||
Compound structures
|
||||
{% elif object_type == 'rule' %}
|
||||
Rules
|
||||
{% elif object_type == 'reaction' %}
|
||||
Reactions
|
||||
{% elif object_type == 'pathway' %}
|
||||
Pathways
|
||||
{% elif object_type == 'node' %}
|
||||
{% if object_type == 'node' %}
|
||||
Nodes
|
||||
{% elif object_type == 'edge' %}
|
||||
Edges
|
||||
{% elif object_type == 'scenario' %}
|
||||
Scenarios
|
||||
{% elif object_type == 'model' %}
|
||||
Model
|
||||
{% elif object_type == 'setting' %}
|
||||
Settings
|
||||
{% elif object_type == 'user' %}
|
||||
Users
|
||||
{% elif object_type == 'group' %}
|
||||
Groups
|
||||
{% endif %}
|
||||
</h2>
|
||||
<div id="actionsButton" class="dropdown dropdown-end hidden">
|
||||
@ -119,103 +75,17 @@
|
||||
class="dropdown-content menu bg-base-100 rounded-box z-50 w-52 p-2"
|
||||
>
|
||||
{% block actions %}
|
||||
{% if object_type == 'package' %}
|
||||
{% include "actions/collections/package.html" %}
|
||||
{% elif object_type == 'compound' %}
|
||||
{% include "actions/collections/compound.html" %}
|
||||
{% elif object_type == 'structure' %}
|
||||
{% include "actions/collections/compound_structure.html" %}
|
||||
{% elif object_type == 'rule' %}
|
||||
{% include "actions/collections/rule.html" %}
|
||||
{% elif object_type == 'reaction' %}
|
||||
{% include "actions/collections/reaction.html" %}
|
||||
{% elif object_type == 'setting' %}
|
||||
{% include "actions/collections/setting.html" %}
|
||||
{% elif object_type == 'scenario' %}
|
||||
{% include "actions/collections/scenario.html" %}
|
||||
{% elif object_type == 'model' %}
|
||||
{% include "actions/collections/model.html" %}
|
||||
{% elif object_type == 'pathway' %}
|
||||
{% include "actions/collections/pathway.html" %}
|
||||
{% elif object_type == 'node' %}
|
||||
{% if object_type == 'node' %}
|
||||
{% include "actions/collections/node.html" %}
|
||||
{% elif object_type == 'edge' %}
|
||||
{% include "actions/collections/edge.html" %}
|
||||
{% elif object_type == 'group' %}
|
||||
{% include "actions/collections/group.html" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<!-- Set Text above links -->
|
||||
{% if object_type == 'package' %}
|
||||
<p>
|
||||
A package contains pathways, rules, etc. and can reflect specific
|
||||
experimental conditions.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/packages"
|
||||
class="link link-primary"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'compound' %}
|
||||
<p>
|
||||
A compound stores the structure of a molecule and can include
|
||||
meta-information.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/compounds"
|
||||
class="link link-primary"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'structure' %}
|
||||
<p>
|
||||
The structures stored in this compound
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/compounds"
|
||||
class="link link-primary"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'rule' %}
|
||||
<p>
|
||||
A rule describes a biotransformation reaction template that is
|
||||
defined as SMIRKS.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/Rules"
|
||||
class="link link-primary"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'reaction' %}
|
||||
<p>
|
||||
A reaction is a specific biotransformation from educt compounds to
|
||||
product compounds.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/reactions"
|
||||
class="link link-primary"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'pathway' %}
|
||||
<p>
|
||||
A pathway displays the (predicted) biodegradation of a compound as
|
||||
graph.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/pathways"
|
||||
class="link link-primary"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'node' %}
|
||||
{% if object_type == 'node' %}
|
||||
<p>
|
||||
Nodes represent the (predicted) compounds in a graph.
|
||||
<a
|
||||
@ -227,7 +97,7 @@
|
||||
</p>
|
||||
{% elif object_type == 'edge' %}
|
||||
<p>
|
||||
Edges represent the links between Nodes in a graph
|
||||
Edges represent the links between nodes in a graph.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/edges"
|
||||
@ -235,70 +105,15 @@
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'scenario' %}
|
||||
<p>
|
||||
A scenario contains meta-information that can be attached to other
|
||||
data (compounds, rules, ..).
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/scenarios"
|
||||
class="link link-primary"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'model' %}
|
||||
<p>
|
||||
A model applies machine learning to limit the combinatorial
|
||||
explosion.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/relative_reasoning"
|
||||
class="link link-primary"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'setting' %}
|
||||
<p>
|
||||
A setting includes configuration parameters for pathway
|
||||
predictions.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/settings"
|
||||
class="link link-primary"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'user' %}
|
||||
<p>
|
||||
Register now to create own packages and to submit and manage your
|
||||
data.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/users"
|
||||
class="link link-primary"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% elif object_type == 'group' %}
|
||||
<p>
|
||||
Users can team up in groups to share packages.
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/groups"
|
||||
class="link link-primary"
|
||||
>Learn more >></a
|
||||
>
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<!-- If theres nothing to show extend the text above -->
|
||||
{% if reviewed_objects and unreviewed_objects %}
|
||||
{% if reviewed_objects|length == 0 and unreviewed_objects|length == 0 %}
|
||||
<p class="mt-4">
|
||||
Nothing found. There are two possible reasons: <br /><br />1.
|
||||
There is no content yet.<br />2. You have no reading
|
||||
permissions.<br /><br />Please be sure you have at least reading
|
||||
permissions.
|
||||
Nothing found. There are two possible reasons:<br /><br />
|
||||
1. There is no content yet.<br />
|
||||
2. You have no reading permissions.<br /><br />
|
||||
Please ensure you have at least reading permissions.
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@ -306,7 +121,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Lists Container - Full Width with Reviewed on Right -->
|
||||
<!-- Lists Container -->
|
||||
<div class="w-full">
|
||||
{% if reviewed_objects %}
|
||||
{% if reviewed_objects|length > 0 %}
|
||||
@ -404,7 +219,7 @@
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
{% if reviewed_objects|length == 0 or object_type == 'package' %}checked{% endif %}
|
||||
{% if reviewed_objects|length == 0 %}checked{% endif %}
|
||||
/>
|
||||
<div class="collapse-title text-xl font-medium">
|
||||
Unreviewed
|
||||
@ -466,31 +281,6 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if objects %}
|
||||
<!-- Unreviewable objects such as User / Group / Setting -->
|
||||
<div class="card bg-base-100">
|
||||
<div class="card-body">
|
||||
<ul class="menu bg-base-200 rounded-box w-full">
|
||||
{% for obj in objects %}
|
||||
{% if object_type == 'user' %}
|
||||
<li>
|
||||
<a href="{{ obj.url }}" class="hover:bg-base-300"
|
||||
>{{ obj.username }}</a
|
||||
>
|
||||
</li>
|
||||
{% else %}
|
||||
<li>
|
||||
<a href="{{ obj.url }}" class="hover:bg-base-300"
|
||||
>{{ obj.name }}</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
95
templates/collections/packages_paginated.html
Normal file
95
templates/collections/packages_paginated.html
Normal file
@ -0,0 +1,95 @@
|
||||
{% extends "collections/paginated_base.html" %}
|
||||
|
||||
{% block page_title %}Packages{% endblock %}
|
||||
|
||||
{% block action_button %}
|
||||
{% if meta.can_edit %}
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary btn-sm"
|
||||
id="new-package-button"
|
||||
onclick="document.getElementById('new_package_modal').showModal(); return false;"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-folder-plus-icon lucide-folder-plus"
|
||||
>
|
||||
<path d="M12 10v6" />
|
||||
<path d="M9 13h6" />
|
||||
<path
|
||||
d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="dropdown dropdown-end">
|
||||
<div tabindex="0" role="button" class="btn btn-sm">
|
||||
Import
|
||||
<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-chevron-down ml-1"
|
||||
>
|
||||
<path d="m6 9 6 6 6-6" />
|
||||
</svg>
|
||||
</div>
|
||||
<ul
|
||||
tabindex="-1"
|
||||
class="dropdown-content menu bg-base-100 rounded-box z-50 w-56 p-2"
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
onclick="document.getElementById('import_package_modal').showModal(); return false;"
|
||||
>
|
||||
Import Package from JSON
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
role="button"
|
||||
onclick="document.getElementById('import_legacy_package_modal').showModal(); return false;"
|
||||
>
|
||||
Import Package from legacy JSON
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock action_button %}
|
||||
|
||||
{% block action_modals %}
|
||||
{% include "modals/collections/new_package_modal.html" %}
|
||||
{% include "modals/collections/import_package_modal.html" %}
|
||||
{% include "modals/collections/import_legacy_package_modal.html" %}
|
||||
{% endblock action_modals %}
|
||||
|
||||
{% block description %}
|
||||
<p>
|
||||
A package contains pathways, rules, etc. and can reflect specific
|
||||
experimental conditions.
|
||||
</p>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/packages"
|
||||
class="link link-primary"
|
||||
>
|
||||
Learn more >>
|
||||
</a>
|
||||
{% endblock description %}
|
||||
134
templates/collections/paginated_base.html
Normal file
134
templates/collections/paginated_base.html
Normal file
@ -0,0 +1,134 @@
|
||||
{% extends "framework_modern.html" %}
|
||||
{% load static %}
|
||||
|
||||
{# List title for empty text - defaults to "items", should be overridden by child templates #}
|
||||
{% block list_title %}items{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% block action_modals %}
|
||||
{% endblock action_modals %}
|
||||
|
||||
<div class="px-8 py-4">
|
||||
<!-- Header Section -->
|
||||
<div class="card bg-base-100">
|
||||
<div class="card-body px-0 py-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="card-title text-2xl">
|
||||
{% block page_title %}{{ page_title|default:"Items" }}{% endblock %}
|
||||
</h2>
|
||||
{% block action_button %}
|
||||
{# Can be overridden by including action buttons for entity type #}
|
||||
{% endblock %}
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
{% block description %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if list_mode == "combined" %}
|
||||
{# ===== COMBINED MODE: Single list without tabs ===== #}
|
||||
<div
|
||||
class="mt-6 w-full"
|
||||
x-data="remotePaginatedList({
|
||||
endpoint: '{{ api_endpoint }}',
|
||||
instanceId: '{{ entity_type }}_combined',
|
||||
perPage: {{ per_page|default:50 }}
|
||||
})"
|
||||
>
|
||||
{% include "collections/_paginated_list_partial.html" with empty_text=list_title|default:"items" show_review_badge=True %}
|
||||
</div>
|
||||
{% else %}
|
||||
{# ===== TABBED MODE: Reviewed/Unreviewed tabs (default) ===== #}
|
||||
<div
|
||||
class="mt-6 w-full"
|
||||
x-data="{
|
||||
activeTab: 'reviewed',
|
||||
reviewedCount: 0,
|
||||
unreviewedCount: 0,
|
||||
reviewedLoaded: false,
|
||||
unreviewedLoaded: false,
|
||||
updateTabSelection() {
|
||||
// Only auto-select unreviewed tab if both have loaded and there are no reviewed items
|
||||
if (this.reviewedLoaded && this.unreviewedLoaded && this.reviewedCount === 0 && this.unreviewedCount > 0) {
|
||||
this.activeTab = 'unreviewed';
|
||||
}
|
||||
}
|
||||
}"
|
||||
>
|
||||
{# No items found message #}
|
||||
<div
|
||||
x-show="reviewedCount === 0 && unreviewedCount === 0"
|
||||
class="text-base-content/70 py-8 text-center"
|
||||
>
|
||||
<p>No items found.</p>
|
||||
</div>
|
||||
|
||||
{# Tabs Navigation #}
|
||||
<div
|
||||
role="tablist"
|
||||
class="tabs tabs-border"
|
||||
x-show="reviewedCount > 0 || unreviewedCount > 0"
|
||||
>
|
||||
<button
|
||||
role="tab"
|
||||
class="tab"
|
||||
:class="{ 'tab-active': activeTab === 'reviewed' }"
|
||||
@click="activeTab = 'reviewed'"
|
||||
x-show="reviewedCount > 0"
|
||||
>
|
||||
Reviewed
|
||||
<span
|
||||
class="badge badge-xs badge-dash badge-info mb-2 ml-2"
|
||||
x-text="reviewedCount"
|
||||
></span>
|
||||
</button>
|
||||
<button
|
||||
role="tab"
|
||||
class="tab"
|
||||
:class="{ 'tab-active': activeTab === 'unreviewed' }"
|
||||
@click="activeTab = 'unreviewed'"
|
||||
x-show="unreviewedCount > 0"
|
||||
>
|
||||
Unreviewed
|
||||
<span
|
||||
class="badge badge-xs badge-dash badge-info mb-2 ml-2"
|
||||
x-text="unreviewedCount"
|
||||
></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{# Reviewed Tab Content #}
|
||||
<div
|
||||
class="mt-6"
|
||||
x-show="activeTab === 'reviewed' && (reviewedCount > 0 || unreviewedCount > 0)"
|
||||
x-data="remotePaginatedList({
|
||||
endpoint: '{{ api_endpoint }}?review_status=true',
|
||||
instanceId: '{{ entity_type }}_reviewed',
|
||||
isReviewed: true,
|
||||
perPage: {{ per_page|default:50 }}
|
||||
})"
|
||||
@items-loaded="reviewedCount = totalItems; reviewedLoaded = true; updateTabSelection()"
|
||||
>
|
||||
{% include "collections/_paginated_list_partial.html" with empty_text="reviewed "|add:list_title|default:"items" show_review_badge=True always_show_badge=True %}
|
||||
</div>
|
||||
|
||||
{# Unreviewed Tab Content #}
|
||||
<div
|
||||
class="mt-6"
|
||||
x-show="activeTab === 'unreviewed' && (reviewedCount > 0 || unreviewedCount > 0)"
|
||||
x-data="remotePaginatedList({
|
||||
endpoint: '{{ api_endpoint }}?review_status=false',
|
||||
instanceId: '{{ entity_type }}_unreviewed',
|
||||
isReviewed: false,
|
||||
perPage: {{ per_page|default:50 }}
|
||||
})"
|
||||
@items-loaded="unreviewedCount = totalItems; unreviewedLoaded = true; updateTabSelection()"
|
||||
>
|
||||
{% include "collections/_paginated_list_partial.html" with empty_text="unreviewed "|add:list_title|default:"items" %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
29
templates/collections/pathways_paginated.html
Normal file
29
templates/collections/pathways_paginated.html
Normal file
@ -0,0 +1,29 @@
|
||||
{% extends "collections/paginated_base.html" %}
|
||||
|
||||
{% block page_title %}Pathways{% endblock %}
|
||||
|
||||
{% block action_button %}
|
||||
{% if meta.can_edit %}
|
||||
<div class="flex items-center gap-2">
|
||||
<a
|
||||
class="btn btn-primary btn-sm"
|
||||
href="{% if meta.current_package %}{{ meta.current_package.url }}/predict{% else %}/predict{% endif %}"
|
||||
>
|
||||
New Pathway
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock action_button %}
|
||||
|
||||
{% block description %}
|
||||
<p>
|
||||
A pathway displays the (predicted) biodegradation of a compound as graph.
|
||||
</p>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/pathways"
|
||||
class="link link-primary"
|
||||
>
|
||||
Learn more >>
|
||||
</a>
|
||||
{% endblock description %}
|
||||
33
templates/collections/reactions_paginated.html
Normal file
33
templates/collections/reactions_paginated.html
Normal file
@ -0,0 +1,33 @@
|
||||
{% extends "collections/paginated_base.html" %}
|
||||
|
||||
{% block page_title %}Reactions{% endblock %}
|
||||
|
||||
{% block action_button %}
|
||||
{% if meta.can_edit %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary btn-sm"
|
||||
onclick="document.getElementById('new_reaction_modal').showModal(); return false;"
|
||||
>
|
||||
New Reaction
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endblock action_button %}
|
||||
|
||||
{% block action_modals %}
|
||||
{% include "modals/collections/new_reaction_modal.html" %}
|
||||
{% endblock action_modals %}
|
||||
|
||||
{% block description %}
|
||||
<p>
|
||||
A reaction is a specific biotransformation from educt compounds to product
|
||||
compounds.
|
||||
</p>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/reactions"
|
||||
class="link link-primary"
|
||||
>
|
||||
Learn more >>
|
||||
</a>
|
||||
{% endblock description %}
|
||||
33
templates/collections/rules_paginated.html
Normal file
33
templates/collections/rules_paginated.html
Normal file
@ -0,0 +1,33 @@
|
||||
{% extends "collections/paginated_base.html" %}
|
||||
|
||||
{% block page_title %}Rules{% endblock %}
|
||||
|
||||
{% block action_button %}
|
||||
{% if meta.can_edit %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary btn-sm"
|
||||
onclick="document.getElementById('new_rule_modal').showModal(); return false;"
|
||||
>
|
||||
New Rule
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endblock action_button %}
|
||||
|
||||
{% block action_modals %}
|
||||
{% include "modals/collections/new_rule_modal.html" %}
|
||||
{% endblock action_modals %}
|
||||
|
||||
{% block description %}
|
||||
<p>
|
||||
A rule describes a biotransformation reaction template that is defined as
|
||||
SMIRKS.
|
||||
</p>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/Rules"
|
||||
class="link link-primary"
|
||||
>
|
||||
Learn more >>
|
||||
</a>
|
||||
{% endblock description %}
|
||||
33
templates/collections/scenarios_paginated.html
Normal file
33
templates/collections/scenarios_paginated.html
Normal file
@ -0,0 +1,33 @@
|
||||
{% extends "collections/paginated_base.html" %}
|
||||
|
||||
{% block page_title %}Scenarios{% endblock %}
|
||||
|
||||
{% block action_button %}
|
||||
{% if meta.can_edit %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary btn-sm"
|
||||
onclick="document.getElementById('new_scenario_modal').showModal(); return false;"
|
||||
>
|
||||
New Scenario
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endblock action_button %}
|
||||
|
||||
{% block action_modals %}
|
||||
{% include "modals/collections/new_scenario_modal.html" %}
|
||||
{% endblock action_modals %}
|
||||
|
||||
{% block description %}
|
||||
<p>
|
||||
A scenario contains meta-information that can be attached to other data
|
||||
(compounds, rules, ..).
|
||||
</p>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/scenarios"
|
||||
class="link link-primary"
|
||||
>
|
||||
Learn more >>
|
||||
</a>
|
||||
{% endblock description %}
|
||||
30
templates/collections/structures_paginated.html
Normal file
30
templates/collections/structures_paginated.html
Normal file
@ -0,0 +1,30 @@
|
||||
{% extends "collections/paginated_base.html" %}
|
||||
|
||||
{% block page_title %}{{ page_title|default:"Structures" }}{% endblock %}
|
||||
|
||||
{% block action_button %}
|
||||
{% if meta.can_edit %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary btn-sm"
|
||||
onclick="document.getElementById('new_compound_structure_modal').showModal(); return false;"
|
||||
>
|
||||
New Structure
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endblock action_button %}
|
||||
|
||||
{% block action_modals %}
|
||||
{# FIXME: New Compound Structure Modal #}
|
||||
{% endblock action_modals %}
|
||||
|
||||
{% block description %}
|
||||
<p>The structures stored in this compound.</p>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://wiki.envipath.org/index.php/compounds"
|
||||
class="link link-primary"
|
||||
>
|
||||
Learn more >>
|
||||
</a>
|
||||
{% endblock description %}
|
||||
11
templates/components/loading-spinner.html
Normal file
11
templates/components/loading-spinner.html
Normal file
@ -0,0 +1,11 @@
|
||||
<div class="benzene-spinner">
|
||||
<svg viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
class="hexagon"
|
||||
d="m 758.78924,684.71562 0.65313,-363.85 33.725,0.066 -0.65313,363.85001 z M 201.52187,362.53368 512.50834,173.66181 530.01077,202.48506 219.03091,391.35694 z M 510.83924,841.63056 199.3448,653.59653 216.77465,624.72049 528.2691,812.76111 z M 500,975 85.905556,742.30278 l 0,-474.94722 L 500,24.999998 914.09445,257.64444 l 0,475.00001 z M 124.90833,722.45834 500,936.15556 880.26389,713.69722 l 0,-436.15555 L 500,63.949998 124.90833,286.40833 z"
|
||||
fill="black"
|
||||
stroke="black"
|
||||
stroke-width="2"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
@ -68,7 +68,7 @@
|
||||
{% endif %}
|
||||
</head>
|
||||
<body class="bg-base-300 min-h-screen">
|
||||
{% include "includes/navbar.html" %}
|
||||
{% include "components/navbar.html" %}
|
||||
|
||||
{# Main Content Area #}
|
||||
<main class="w-full">
|
||||
@ -128,7 +128,7 @@
|
||||
{% endblock main_content %}
|
||||
</main>
|
||||
|
||||
{% include "includes/footer.html" %}
|
||||
{% include "components/footer.html" %}
|
||||
|
||||
{# Floating Help Tab #}
|
||||
{% if not public_mode %}
|
||||
|
||||
Reference in New Issue
Block a user