KarrLab/datanator_frontend

View on GitHub
src/scenes/BiochemicalEntityDetails/Reaction/MetadataSection.js

Summary

Maintainability
D
2 days
Test Coverage
A
93%
import React, { Component } from "react";
import PropTypes from "prop-types";
import BaseMetadataSection from "../MetadataSection";
import { Link } from "react-router-dom";
import { LoadMetabolites } from "../LoadContent";
import { naturalSort } from "~/utils/utils";

const DB_LINKS = [
  { label: "BRENDA", url: "https://www.brenda-enzymes.org/enzyme.php?ecno=" },
  { label: "ENZYME", url: "https://enzyme.expasy.org/EC/" },
  { label: "ExplorEnz", url: "https://www.enzyme-database.org/query.php?ec=" },
  {
    label: "IntEnz",
    url: "https://www.ebi.ac.uk/intenz/query?cmd=SearchEC&ec=",
  },
  { label: "KEGG", url: "https://www.genome.jp/dbget-bin/www_bget?ec:" },
  {
    label: "MetaCyc",
    url: "http://biocyc.org/META/substring-search?type=REACTION&object=",
  },
  { label: "SABIO-RK", url: "http://sabiork.h-its.org/newSearch?q=ecnumber:" },
];

class MetadataSection extends Component {
  static propTypes = {
    "set-scene-metadata": PropTypes.func.isRequired,
  };

  constructor(props) {
    super(props);
    this.state = { metadata: null };
  }

  getMetadataUrl(query) {
    if (query == null) {
      return;
    }

    const args = ["_from=0", "size=1000", "bound=tight", "dof=0"];

    const substratesProducts = query.split("-->");
    if (substratesProducts.length < 2) {
      this.props["set-scene-metadata"]({ error404: true });
      return;
    }

    args.push("substrates=" + substratesProducts[0]);
    args.push("products=" + substratesProducts[1]);

    return "reactions/kinlaw_by_rxn/?" + args.join("&");
  }

  static processMetadata(query, organism, rawData) {
    const processedData = {};

    const reactionId = MetadataSection.getReactionId(rawData[0].resource);
    const ecNumber = MetadataSection.getEcNum(rawData[0].resource);
    const name = rawData[0]["enzymes"][0]["enzyme"][0]["enzyme_name"];
    const substrates = MetadataSection.getReactantNames(
      rawData[0].reaction_participant[0].substrate,
      "substrate"
    );
    const products = MetadataSection.getReactantNames(
      rawData[0].reaction_participant[1].product,
      "product"
    );
    processedData["reactionId"] = reactionId;
    processedData["substrates"] = substrates;
    processedData["products"] = products;
    if (ecNumber !== "-.-.-.-") {
      processedData["ecNumber"] = ecNumber;
    }

    if (rawData[0]["ec_meta"]) {
      if (rawData[0]["ec_meta"]["cofactor"]) {
        processedData["cofactor"] = rawData[0]["ec_meta"]["cofactor"];
      }
    }

    if (name) {
      const start = name[0].toUpperCase();
      const end = name.substring(1, name.length);
      processedData["enzyme"] = start + end;
    }

    // todo: get OrthoDB id for enzyme
    processedData["orthoDbId"] = null;

    const substrateNames = substrates.map((part) => part.name);
    const productNames = products.map((part) => part.name);

    substrateNames.sort(naturalSort);
    productNames.sort(naturalSort);

    processedData["equation"] =
      MetadataSection.formatSide(substrateNames) +
      " → " +
      MetadataSection.formatSide(productNames);

    return processedData;
  }

  static formatTitle(processedData) {
    let title = processedData.enzyme;
    if (!title) {
      title = processedData.equation;
    }
    return title;
  }

  static processRelatedMetabolites(partLinks, metabolites, organism) {
    metabolites.sort((a, b) => {
      return naturalSort(a.name, b.name);
    });

    for (const met of metabolites) {
      let inchiKey = null;
      let route = null;
      if (met.inchiKey !== null) {
        inchiKey = met.inchiKey;
        route = "/metabolite/" + encodeURIComponent(inchiKey) + "/";
        if (organism) {
          route += organism + "/";
        }
      }
      partLinks.push(
        <LoadMetabolites
          url={"metabolites/meta/?inchikey=" + inchiKey}
          key={inchiKey}
          inchiKey={inchiKey}
          name={met.name}
          route={route}
        />
      );
      partLinks.push(" + ");
    }
    if (metabolites.length) {
      partLinks.pop();
    }
  }

  static formatMetadata(query, organism, processedData) {
    const sections = [];

    sections.push({
      id: "id",
      title: "Id",
      content: query,
    });

    const partLinks = [];
    MetadataSection.processRelatedMetabolites(
      partLinks,
      processedData.substrates,
      organism
    );

    partLinks.push(" → ");
    MetadataSection.processRelatedMetabolites(
      partLinks,
      processedData.products,
      organism
    );

    // description
    const descriptions = [];
    if (processedData.enzyme) {
      if (processedData.orthoDbId) {
        let route = "/gene/" + processedData.orthoDbId + "/";
        if (organism) {
          route += organism + "/";
        }
        descriptions.push({
          label: "Enzyme",
          value: <Link to={route}>{processedData.enzyme}</Link>,
        });
      } else {
        descriptions.push({ label: "Enzyme", value: processedData.enzyme });
      }
    }
    if (processedData.equation) {
      descriptions.push({ label: "Equation", value: partLinks });
    }
    if (processedData.cofactor) {
      descriptions.push({
        label: "Cofactor",
        value: (
          <Link
            to={
              "/search/" +
              processedData.cofactor +
              "/" +
              (organism ? organism + "/" : "")
            }
          >
            {processedData.cofactor}
          </Link>
        ),
      });
    }
    if (processedData.ecNumber) {
      descriptions.push({
        label: "EC code",
        value: (
          <a
            href={"https://enzyme.expasy.org/EC/" + processedData.ecNumber}
            target="_blank"
            rel="noopener noreferrer"
          >
            {processedData.ecNumber}
          </a>
        ),
      });
    }
    if (descriptions) {
      sections.push({
        id: "description",
        title: "Description",
        content: (
          <ul className="key-value-list link-list">
            {descriptions.map((el) => (
              <li key={el.label}>
                <b>{el.label}:</b> {el.value}
              </li>
            ))}
          </ul>
        ),
      });
    }

    // database links
    if (processedData.ecNumber !== undefined) {
      const dbLinks = [];
      for (const dbLink of DB_LINKS) {
        dbLinks.push(
          <li key={dbLink.label}>
            <a
              href={dbLink.url + processedData.ecNumber}
              target="_blank"
              rel="noopener noreferrer"
              className="bulleted-list-item"
            >
              {dbLink.label}
            </a>
          </li>
        );
      }
      sections.push({
        id: "cross-refs",
        title: "Cross references",
        content: <ul className="three-col-list link-list">{dbLinks}</ul>,
      });
    }

    // return sections
    return sections;
  }

  static getReactionId(resources) {
    for (const resource of resources) {
      if (resource.namespace === "sabiork.reaction") {
        return resource.id;
      }
    }
  }

  static getEcNum(resources) {
    for (const resource of resources) {
      if (resource.namespace === "ec-code") {
        return resource.id;
      }
    }
  }

  static getReactantNames(reactants, reactant_type) {
    let structure_id = null;
    let name_id = null;
    if (reactant_type === "substrate") {
      structure_id = "substrate_structure";
      name_id = "substrate_name";
    } else if (reactant_type === "product") {
      structure_id = "product_structure";
      name_id = "product_name";
    }
    const molecules = [];
    for (const reactant of reactants) {
      const new_molecule = {
        name: null,
        inchiKey: null,
      };
      new_molecule["name"] = reactant[name_id];
      if (reactant[structure_id]) {
        for (var i = reactant[structure_id].length - 1; i >= 0; i--) {
          if (reactant[structure_id][i]["format"] === "inchi") {
            new_molecule["inchiKey"] = reactant[structure_id][i]["InChI_Key"];
          }
        }
      }
      molecules.push(new_molecule);
    }
    return molecules;
  }

  static formatSide(parts) {
    return parts.join(" + ");
  }

  render() {
    return (
      <BaseMetadataSection
        entity-type="reaction"
        get-metadata-url={this.getMetadataUrl.bind(this)}
        process-metadata={MetadataSection.processMetadata}
        format-title={MetadataSection.formatTitle}
        format-metadata={MetadataSection.formatMetadata}
        set-scene-metadata={this.props["set-scene-metadata"]}
      />
    );
  }
}
export { MetadataSection };