[Feature] Alias Support (#151)

Fixes #149

Co-authored-by: Tim Lorsbach <tim@lorsba.ch>
Reviewed-on: enviPath/enviPy#151
This commit is contained in:
2025-10-09 23:14:34 +13:00
parent afeb56622c
commit 68a3f3b982
25 changed files with 675 additions and 31 deletions

View File

@ -3,6 +3,10 @@
<a role="button" data-toggle="modal" data-target="#edit_compound_modal">
<i class="glyphicon glyphicon-edit"></i> Edit Compound</a>
</li>
<li>
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
</li>
<li>
<a role="button" data-toggle="modal" data-target="#add_structure_modal">
<i class="glyphicon glyphicon-plus"></i> Add Structure</a>
@ -25,4 +29,4 @@
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
<i class="glyphicon glyphicon-trash"></i> Delete Compound</a>
</li>
{% endif %}
{% endif %}

View File

@ -3,6 +3,10 @@
<a role="button" data-toggle="modal" data-target="#edit_compound_structure_modal">
<i class="glyphicon glyphicon-edit"></i> Edit Compound Structure</a>
</li>
<li>
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
</li>
<li>
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
@ -15,4 +19,4 @@
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
<i class="glyphicon glyphicon-trash"></i> Delete Compound Structure</a>
</li>
{% endif %}
{% endif %}

View File

@ -1,4 +1,8 @@
{% if meta.can_edit %}
<li>
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
</li>
<li>
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>

View File

@ -3,6 +3,10 @@
<a role="button" data-toggle="modal" data-target="#edit_node_modal">
<i class="glyphicon glyphicon-edit"></i> Edit Node</a>
</li>
<li>
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
</li>
<li>
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>

View File

@ -31,6 +31,10 @@
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
</li>
<li>
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
</li>
{# <li>#}
{# <a class="button" data-toggle="modal" data-target="#add_pathway_edge_modal">#}
{# <i class="glyphicon glyphicon-plus"></i> Calculate Compound Properties</a>#}
@ -48,4 +52,4 @@
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
<i class="glyphicon glyphicon-trash"></i> Delete Pathway</a>
</li>
{% endif %}
{% endif %}

View File

@ -3,6 +3,10 @@
<a role="button" data-toggle="modal" data-target="#edit_reaction_modal">
<i class="glyphicon glyphicon-edit"></i> Edit Reaction</a>
</li>
<li>
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
</li>
<li>
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
@ -21,4 +25,4 @@
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
<i class="glyphicon glyphicon-trash"></i> Delete Reaction</a>
</li>
{% endif %}
{% endif %}

View File

@ -3,6 +3,10 @@
<a role="button" data-toggle="modal" data-target="#edit_rule_modal">
<i class="glyphicon glyphicon-edit"></i> Edit Rule</a>
</li>
<li>
<a role="button" data-toggle="modal" data-target="#set_aliases_modal">
<i class="glyphicon glyphicon-plus"></i> Set Aliases</a>
</li>
<li>
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
@ -17,4 +21,4 @@
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
<i class="glyphicon glyphicon-trash"></i> Delete Rule</a>
</li>
{% endif %}
{% endif %}

View File

@ -15,12 +15,12 @@
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)">
<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-file-info"></span>
<span class="label label-info" id="upload-legacy-file-info"></span>
<input type="hidden" value="import-legacy-package-json" name="hidden" readonly="">
</p>
</form>

View File

@ -0,0 +1,169 @@
{% 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" 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 }}</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;
// Avoid duplicate aliass
var exists = false;
$('#alias-box .alias').each(function () {
if ($(this).text().replace('×', '').trim().toLowerCase() === aliasText.toLowerCase()) {
exists = true;
return false;
}
});
if (!exists) {
var aliasHtml = '<span class="alias">' + $('<div>').text(aliasText).html() +
'<span class="remove">&times;</span></span>';
$(aliasHtml).insertBefore('#alias-input');
}
$('#alias-input').val('');
}
// Add alias when Enter is pressed
$('#alias-input').on('keypress', function (e) {
if (e.which === 13) {
e.preventDefault();
addAlias($(this).val());
}
});
// Add alias when input loses focus
$('#alias-input').on('blur', function () {
var val = $(this).val();
if (val.trim() !== '') {
addAlias(val);
}
});
// Remove alias when clicking ×
$('#alias-box').on('click', '.remove', function () {
$(this).closest('.alias').remove();
});
// 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 = ['']
}
formData = {
'aliases': aliases
}
$.ajax({
type: 'post',
data: formData,
url: '{{ current_object.url }}',
traditional: true,
success: function (data, textStatus) {
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>

View File

@ -64,8 +64,8 @@
$('#set_scenario_modal_form_submit').on('click', function (e) {
e.preventDefault();
if ($('##scenario-select').val().length == 0) {
$('##scenario-select').val([''])
if ($('#scenario-select').val().length == 0) {
$('#scenario-select').val([''])
}
$('#set_scenario_modal_form').submit();
});

View File

@ -2,12 +2,13 @@
{% block content %}
{% block action_modals %}
{% include "modals/objects/edit_rule_modal.html" %}
{% include "modals/objects/generic_set_scenario_modal.html" %}
{% include "modals/objects/generic_copy_object_modal.html" %}
{% include "modals/objects/generic_delete_modal.html" %}
{% endblock action_modals %}
{% block action_modals %}
{% include "modals/objects/edit_rule_modal.html" %}
{% include "modals/objects/generic_set_aliases_modal.html" %}
{% include "modals/objects/generic_set_scenario_modal.html" %}
{% include "modals/objects/generic_copy_object_modal.html" %}
{% include "modals/objects/generic_delete_modal.html" %}
{% endblock action_modals %}
<div class="panel-group" id="rule-detail">
<div class="panel panel-default">
@ -32,6 +33,23 @@
</p>
</div>
{% if rule.aliases %}
<!-- Aliases -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="rule-aliases-link" data-toggle="collapse" data-parent="#rule-detail"
href="#rule-aliases">Aliases</a>
</h4>
</div>
<div id="rule-aliases" class="panel-collapse collapse in">
<div class="panel-body list-group-item">
{% for alias in rule.aliases %}
<a class="list-group-item">{{ alias }}</a>
{% endfor %}
</div>
</div>
{% endif %}
<!-- Reaction Patterns -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">

View File

@ -4,6 +4,7 @@
{% block action_modals %}
{% include "modals/objects/edit_compound_modal.html" %}
{% include "modals/objects/generic_set_aliases_modal.html" %}
{% include "modals/objects/add_structure_modal.html" %}
{% include "modals/objects/generic_set_scenario_modal.html" %}
{% include "modals/objects/generic_set_external_reference_modal.html" %}
@ -37,6 +38,23 @@
</p>
</div>
{% if compound.aliases %}
<!-- Aliases -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="compound-aliases-link" data-toggle="collapse" data-parent="#compound-detail"
href="#compound-aliases">Aliases</a>
</h4>
</div>
<div id="compound-aliases" class="panel-collapse collapse in">
<div class="panel-body list-group-item">
{% for alias in compound.aliases %}
<a class="list-group-item">{{ alias }}</a>
{% endfor %}
</div>
</div>
{% endif %}
<!-- Description -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">

View File

@ -2,12 +2,13 @@
{% block content %}
{% block action_modals %}
{% include "modals/objects/edit_compound_structure_modal.html" %}
{% include "modals/objects/generic_set_scenario_modal.html" %}
{% include "modals/objects/generic_set_external_reference_modal.html" %}
{% include "modals/objects/generic_delete_modal.html" %}
{% endblock action_modals %}
{% block action_modals %}
{% include "modals/objects/edit_compound_structure_modal.html" %}
{% include "modals/objects/generic_set_aliases_modal.html" %}
{% include "modals/objects/generic_set_scenario_modal.html" %}
{% include "modals/objects/generic_set_external_reference_modal.html" %}
{% include "modals/objects/generic_delete_modal.html" %}
{% endblock action_modals %}
<div class="panel-group" id="compound-structure-detail">
<div class="panel panel-default">
@ -33,34 +34,52 @@
<!-- Image -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="compound-image-link" data-toggle="collapse" data-parent="#compound-detail"
href="#compound-image">Image Representation</a>
<a id="compound-structure-image-link" data-toggle="collapse" data-parent="#compound-structure-detail"
href="#compound-structure-image">Image Representation</a>
</h4>
</div>
<div id="compound-image" class="panel-collapse collapse in">
<div id="compound-structure-image" class="panel-collapse collapse in">
<div class="panel-body list-group-item">
<div id="image-div" align="center">
{{ compound_structure.as_svg|safe }}
</div>
</div>
</div>
<!-- SMILES -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="compound-smiles-link" data-toggle="collapse" data-parent="#compound-detail"
href="#compound-smiles">SMILES Representation</a>
<a id="compound-structure-smiles-link" data-toggle="collapse" data-parent="#compound-structure-detail"
href="#compound-structure-smiles">SMILES Representation</a>
</h4>
</div>
<div id="compound-smiles" class="panel-collapse collapse in">
<div id="compound-structure-smiles" class="panel-collapse collapse in">
<div class="panel-body list-group-item">
{{ compound_structure.smiles }}
</div>
</div>
{% if compound_structure.aliases %}
<!-- Aliases -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="compound-structure-aliases-link" data-toggle="collapse" data-parent="#compound-structure-detail"
href="#compound-structure-aliases">Aliases</a>
</h4>
</div>
<div id="compound-structure-aliases" class="panel-collapse collapse in">
<div class="panel-body list-group-item">
{% for alias in compound_structure.aliases %}
<a class="list-group-item">{{ alias }}</a>
{% endfor %}
</div>
</div>
{% endif %}
{% if compound_structure.scenarios.all %}
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="compound_structure-scenario-link" data-toggle="collapse" data-parent="#compound-structure-detail"
<a id="compound-structure-scenario-link" data-toggle="collapse" data-parent="#compound-structure-detail"
href="#compound-structure-scenario">Scenarios</a>
</h4>
</div>

View File

@ -4,6 +4,7 @@
{% block action_modals %}
{# {% include "modals/objects/edit_edge_modal.html" %}#}
{% include "modals/objects/generic_set_aliases_modal.html" %}
{% include "modals/objects/generic_set_scenario_modal.html" %}
{% include "modals/objects/generic_delete_modal.html" %}
{% endblock action_modals %}
@ -39,6 +40,23 @@
</div>
</div>
{% if edge.aliases %}
<!-- Aliases -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="edge-aliases-link" data-toggle="collapse" data-parent="#edge-detail"
href="#edge-aliases">Aliases</a>
</h4>
</div>
<div id="edge-aliases" class="panel-collapse collapse in">
<div class="panel-body list-group-item">
{% for alias in edge.aliases %}
<a class="list-group-item">{{ alias }}</a>
{% endfor %}
</div>
</div>
{% endif %}
<!-- Image -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">

View File

@ -4,6 +4,7 @@
{% block action_modals %}
{% include "modals/objects/edit_node_modal.html" %}
{% include "modals/objects/generic_set_aliases_modal.html" %}
{% include "modals/objects/generic_set_scenario_modal.html" %}
{% include "modals/objects/generic_delete_modal.html" %}
{% endblock action_modals %}
@ -42,6 +43,23 @@
</div>
</div>
{% if node.aliases %}
<!-- Aliases -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="node-aliases-link" data-toggle="collapse" data-parent="#node-detail"
href="#node-aliases">Aliases</a>
</h4>
</div>
<div id="node-aliases" class="panel-collapse collapse in">
<div class="panel-body list-group-item">
{% for alias in node.aliases %}
<a class="list-group-item">{{ alias }}</a>
{% endfor %}
</div>
</div>
{% endif %}
<!-- Image -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">

View File

@ -85,6 +85,7 @@
{% include "modals/objects/download_pathway_image_modal.html" %}
{% include "modals/objects/generic_copy_object_modal.html" %}
{% include "modals/objects/edit_pathway_modal.html" %}
{% include "modals/objects/generic_set_aliases_modal.html" %}
{% include "modals/objects/generic_set_scenario_modal.html" %}
{% include "modals/objects/delete_pathway_node_modal.html" %}
{% include "modals/objects/delete_pathway_edge_modal.html" %}
@ -210,6 +211,23 @@
</div>
</div>
{% if pathway.aliases %}
<!-- Aliases -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="pathway-aliases-link" data-toggle="collapse" data-parent="#pathway-detail"
href="#pathway-aliases">Aliases</a>
</h4>
</div>
<div id="pathway-aliases" class="panel-collapse collapse in">
<div class="panel-body list-group-item">
{% for alias in pathway.aliases %}
<a class="list-group-item">{{ alias }}</a>
{% endfor %}
</div>
</div>
{% endif %}
{% if pathway.scenarios.all %}
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">

View File

@ -4,6 +4,7 @@
{% block action_modals %}
{% include "modals/objects/edit_reaction_modal.html" %}
{% include "modals/objects/generic_set_aliases_modal.html" %}
{% include "modals/objects/generic_set_scenario_modal.html" %}
{% include "modals/objects/generic_copy_object_modal.html" %}
{% include "modals/objects/generic_set_external_reference_modal.html" %}
@ -41,6 +42,23 @@
</div>
</div>
{% if reaction.aliases %}
<!-- Aliases -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="reaction-aliases-link" data-toggle="collapse" data-parent="#reaction-detail"
href="#reaction-aliases">Aliases</a>
</h4>
</div>
<div id="reaction-aliases" class="panel-collapse collapse in">
<div class="panel-body list-group-item">
{% for alias in reaction.aliases %}
<a class="list-group-item">{{ alias }}</a>
{% endfor %}
</div>
</div>
{% endif %}
<!-- Image -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">

View File

@ -4,6 +4,7 @@
{% block action_modals %}
{% include "modals/objects/edit_rule_modal.html" %}
{% include "modals/objects/generic_set_aliases_modal.html" %}
{% include "modals/objects/generic_set_scenario_modal.html" %}
{% include "modals/objects/generic_copy_object_modal.html" %}
{% include "modals/objects/generic_delete_modal.html" %}
@ -32,6 +33,23 @@
</p>
</div>
{% if rule.aliases %}
<!-- Aliases -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="rule-aliases-link" data-toggle="collapse" data-parent="#rule-detail"
href="#rule-aliases">Aliases</a>
</h4>
</div>
<div id="rule-aliases" class="panel-collapse collapse in">
<div class="panel-body list-group-item">
{% for alias in rule.aliases %}
<a class="list-group-item">{{ alias }}</a>
{% endfor %}
</div>
</div>
{% endif %}
<!-- Representation -->
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">