diff --git a/epdb/migrations/0026_auto_20260602_1718.py b/epdb/migrations/0026_auto_20260602_1718.py new file mode 100644 index 00000000..da3bd22e --- /dev/null +++ b/epdb/migrations/0026_auto_20260602_1718.py @@ -0,0 +1,48 @@ +# Generated by Django 6.0.3 on 2026-06-02 17:18 + +from django.db import migrations +from envipy_additional_information import DOI + + +def forward_func(apps, schema_editor): + AdditionalInformation = apps.get_model("epdb", "AdditionalInformation") + + refs = AdditionalInformation.objects.filter(type="Reference") + + remaining = [] + + for ref in refs: + r = ref.data["reference"] + try: + # PubMed IDs are plain ints, try parsing + _ = int(r) + # Nothing to do + except ValueError: + DOMAINS = [ + "http://dx.doi.org/", + "https://dx.doi.org/", + "http://doi.org/", + "https://doi.org/", + ] + for d in DOMAINS: + r = r.replace(d, "") + + if r.startswith("10."): + ref.type = DOI.__name__ + ref.data = {"doi": r} + ref.save() + else: + remaining.append(ref) + + if len(remaining) > 0: + raise ValueError(f"Could not parse {len(remaining)} references") + + +class Migration(migrations.Migration): + dependencies = [ + ("epdb", "0025_auto_20260511_2025"), + ] + + operations = [ + migrations.RunPython(forward_func, reverse_code=migrations.RunPython.noop), + ] diff --git a/epdb/models.py b/epdb/models.py index b1b1bb20..3acad772 100644 --- a/epdb/models.py +++ b/epdb/models.py @@ -1773,7 +1773,7 @@ class Reaction( return new_reaction def smirks(self): - return f"{'.'.join([cs.smiles for cs in self.educts.all()])}>>{'.'.join([cs.smiles for cs in self.products.all()])}" + return f"{'.'.join([cs.smiles for cs in self.educts.all().order_by('-pk')])}>>{'.'.join([cs.smiles for cs in self.products.all().order_by('-pk')])}" @property def as_svg(self): @@ -1886,6 +1886,9 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMix if n not in queue: queue.append(n) + for i in queue: + processed.add(i) + while len(queue): current = queue.pop() processed.add(current) @@ -2194,17 +2197,8 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMix depth_map[0] = list() processed = set() - for n in self.nodes: - num_parents = in_count[str(n.uuid)] - if num_parents == 0: - # must be a root node or unconnected node - if n.depth != 0: - n.depth = 0 - n.save() - - # Only root node may have children - if out_count[str(n.uuid)] > 0: - depth_map[0].append(n) + for n in self.root_nodes: + depth_map[0].append(n) # At most depth len(nodes) is possible for i in range(self.nodes.count()): @@ -2227,7 +2221,7 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMix for depth, nodes in depth_map.items(): for n in nodes: - if n.depth != depth: + if n.depth != depth and depth != 0: n.depth = depth n.save() diff --git a/static/js/alpine/components/widgets.js b/static/js/alpine/components/widgets.js index 9da8c22d..a0577b2e 100644 --- a/static/js/alpine/components/widgets.js +++ b/static/js/alpine/components/widgets.js @@ -293,6 +293,34 @@ document.addEventListener("alpine:init", () => { }), ); + // PubMed link widget + Alpine.data( + "doiWidget", + (fieldName, data, schema, uiSchema, mode, debugErrors, context = null) => ({ + ...baseWidget( + fieldName, + data, + schema, + uiSchema, + mode, + debugErrors, + context, + ), + + get value() { + return this.data[this.fieldName] || ""; + }, + set value(v) { + this.data[this.fieldName] = v; + }, + get doiUrl() { + return this.value + ? `https://dx.doi.org/${this.value}` + : null; + }, + }), + ); + // Compound link widget Alpine.data( "compoundWidget", diff --git a/static/js/pw.js b/static/js/pw.js index 7bf7fff7..de259beb 100644 --- a/static/js/pw.js +++ b/static/js/pw.js @@ -581,11 +581,11 @@ function draw(pathway, elem) { for (idx in parents) { p = nodes[parents[idx]] // console.log(p.depth) - if (p.depth >= n.depth) { - // keep the .5 steps for pseudo nodes - n.depth = n.pseudo ? p.depth + 1 : Math.floor(p.depth + 1); - // console.log("Adjusting", orig_depth, Math.floor(p.depth + 1)); - } + // if (p.depth >= n.depth) { + // // keep the .5 steps for pseudo nodes + // n.depth = n.pseudo ? p.depth + 1 : Math.floor(p.depth + 1); + // // console.log("Adjusting", orig_depth, Math.floor(p.depth + 1)); + // } } }); diff --git a/templates/components/schema_form.html b/templates/components/schema_form.html index 75cc9591..37050c26 100644 --- a/templates/components/schema_form.html +++ b/templates/components/schema_form.html @@ -123,6 +123,17 @@ + + + + {% include "components/widgets/doi_link_widget.html" %} + + + + + + + + + + + + + + + + + + + + + + + + + + — + + + + + + + + + + + + + + + + + + + + diff --git a/uv.lock b/uv.lock index 634ae6af..32b161e0 100644 --- a/uv.lock +++ b/uv.lock @@ -894,7 +894,7 @@ provides-extras = ["ms-login", "dev", "pepper-plugin"] [[package]] name = "envipy-additional-information" version = "0.4.2" -source = { git = "ssh://git@git.envipath.com/enviPath/enviPy-additional-information.git?branch=develop#79285f522e0a6ed3f2e805dfeeb6b9fa5cea4323" } +source = { git = "ssh://git@git.envipath.com/enviPath/enviPy-additional-information.git?branch=develop#f2f251e0214f016760348730c45e56183d961201" } dependencies = [ { name = "pydantic" }, ]