<commit_before>import React from "react";
import { isEmpty, set } from "lodash/fp";
import cx from "classnames";

import ERCCScatterPlot from "~/components/ERCCScatterPlot";
import PropTypes from "~/components/utils/propTypes";
import { humanize } from "~/helpers/strings";
import { getDownloadLinks } from "~/components/views/report/utils/download";
import { logAnalyticsEvent } from "~/api/analytics";
import { getSamplePipelineResults } from "~/api";
import ColumnHeaderTooltip from "~/components/ui/containers/ColumnHeaderTooltip";
import FieldList from "~/components/common/DetailsSidebar/FieldList";

import { PIPELINE_INFO_FIELDS, HOST_FILTERING_WIKI } from "./constants";
import MetadataSection from "./MetadataSection";
import cs from "./sample_details_mode.scss";

class PipelineTab extends React.Component {
  state = {
    sectionOpen: {
      pipelineInfo: true,
      readsRemaining: false,
      erccScatterplot: false,
      downloads: false,
    },
    sectionEditing: {},
    graphWidth: 0,
    pipelineStepDict: {},
  };

  componentDidMount() {
    this.updateGraphDimensions();
    this.getReadCounts();
  }

  componentDidUpdate() {
    this.updateGraphDimensions();
  }

  updateGraphDimensions = () => {
    if (this._graphContainer && this.state.graphWidth === 0) {
      this.setState({
        graphWidth: this._graphContainer.offsetWidth,
      });
    }
  };

  toggleSection = section => {
    const { sectionOpen } = this.state;

    const newValue = !sectionOpen[section];
    this.setState({
      sectionOpen: set(section, newValue, sectionOpen),
    });
    logAnalyticsEvent("PipelineTab_section_toggled", {
      section: section,
      sectionOpen: newValue,
      sampleId: this.props.sampleId,
    });
  };

  getPipelineInfoField = field => {
    const { pipelineInfo } = this.props;
    const { text, linkLabel, link } = pipelineInfo[field.key] || {};

    const metadataLink = linkLabel &&
      link && (
        <a
          className={cs.vizLink}
          href={link}
          target="_blank"
          rel="noopener noreferrer"
        >
          {linkLabel}
          <i className={cx("fa fa-chevron-right", cs.rightArrow)} />
        </a>
      );

    return {
      label: field.name,
      value:
        text === undefined || text === null || text === "" ? (
          <div className={cs.emptyValue}>--</div>
        ) : (
          <div className={cs.metadataValue}>
            {text}
            {metadataLink}
          </div>
        ),
    };
  };

  getReadCounts = async () => {
    const { sampleId, pipelineRun } = this.props;
    const pipelineResults = await getSamplePipelineResults(
      sampleId,
      pipelineRun && pipelineRun.pipeline_version
    );

    if (pipelineResults && pipelineResults["displayed_data"]) {
      this.setState({
        pipelineStepDict: pipelineResults["displayed_data"]["Host Filtering"],
      });
    }
  };

  renderReadCountsTable = stepKey => {
    // Humanize step name and remove "_out",
    // e.g. "validate_input_out" -> "Validate Input"
    let stepName = humanize(stepKey).slice(0, -4);
    let step = this.state.pipelineStepDict["steps"][stepKey];

    const totalReads = this.props.pipelineRun.total_reads;
    let readsAfter = step["reads_after"];
    let percentReads = (readsAfter / totalReads * 100).toFixed(2);

    return (
      <div className={cs.readsRemainingRow}>
        <div className={cs.label}>
          <ColumnHeaderTooltip
            position="top left"
            trigger={<div className={cs.labelText}>{stepName}</div>}
            content={step["step_description"]}
            title={stepName}
          />
        </div>
        <div className={cs.narrowMetadataValueContainer}>
          <div className={cs.metadataValue}>{readsAfter.toLocaleString()}</div>
        </div>
        <div className={cs.narrowMetadataValueContainer}><commit_msg>Handle null readsAfter case (#3111)<commit_after>import React from "react";
import { isEmpty, set } from "lodash/fp";
import cx from "classnames";

import ERCCScatterPlot from "~/components/ERCCScatterPlot";
import PropTypes from "~/components/utils/propTypes";
import { humanize } from "~/helpers/strings";
import { getDownloadLinks } from "~/components/views/report/utils/download";
import { logAnalyticsEvent } from "~/api/analytics";
import { getSamplePipelineResults } from "~/api";
import ColumnHeaderTooltip from "~/components/ui/containers/ColumnHeaderTooltip";
import FieldList from "~/components/common/DetailsSidebar/FieldList";

import { PIPELINE_INFO_FIELDS, HOST_FILTERING_WIKI } from "./constants";
import MetadataSection from "./MetadataSection";
import cs from "./sample_details_mode.scss";

class PipelineTab extends React.Component {
  state = {
    sectionOpen: {
      pipelineInfo: true,
      readsRemaining: false,
      erccScatterplot: false,
      downloads: false,
    },
    sectionEditing: {},
    graphWidth: 0,
    pipelineStepDict: {},
  };

  componentDidMount() {
    this.updateGraphDimensions();
    this.getReadCounts();
  }

  componentDidUpdate() {
    this.updateGraphDimensions();
  }

  updateGraphDimensions = () => {
    if (this._graphContainer && this.state.graphWidth === 0) {
      this.setState({
        graphWidth: this._graphContainer.offsetWidth,
      });
    }
  };

  toggleSection = section => {
    const { sectionOpen } = this.state;

    const newValue = !sectionOpen[section];
    this.setState({
      sectionOpen: set(section, newValue, sectionOpen),
    });
    logAnalyticsEvent("PipelineTab_section_toggled", {
      section: section,
      sectionOpen: newValue,
      sampleId: this.props.sampleId,
    });
  };

  getPipelineInfoField = field => {
    const { pipelineInfo } = this.props;
    const { text, linkLabel, link } = pipelineInfo[field.key] || {};

    const metadataLink = linkLabel &&
      link && (
        <a
          className={cs.vizLink}
          href={link}
          target="_blank"
          rel="noopener noreferrer"
        >
          {linkLabel}
          <i className={cx("fa fa-chevron-right", cs.rightArrow)} />
        </a>
      );

    return {
      label: field.name,
      value:
        text === undefined || text === null || text === "" ? (
          <div className={cs.emptyValue}>--</div>
        ) : (
          <div className={cs.metadataValue}>
            {text}
            {metadataLink}
          </div>
        ),
    };
  };

  getReadCounts = async () => {
    const { sampleId, pipelineRun } = this.props;
    const pipelineResults = await getSamplePipelineResults(
      sampleId,
      pipelineRun && pipelineRun.pipeline_version
    );

    if (pipelineResults && pipelineResults["displayed_data"]) {
      this.setState({
        pipelineStepDict: pipelineResults["displayed_data"]["Host Filtering"],
      });
    }
  };

  renderReadCountsTable = stepKey => {
    // Humanize step name and remove "_out",
    // e.g. "validate_input_out" -> "Validate Input"
    let stepName = humanize(stepKey).slice(0, -4);
    let step = this.state.pipelineStepDict["steps"][stepKey];

    const totalReads = this.props.pipelineRun.total_reads;
    let readsAfter = step["reads_after"];
    let percentReads = (readsAfter / totalReads * 100).toFixed(2);

    return (
      <div className={cs.readsRemainingRow}>
        <div className={cs.label}>
          <ColumnHeaderTooltip
            position="top left"
            trigger={<div className={cs.labelText}>{stepName}</div>}
            content={step["step_description"]}
            title={stepName}
          />
        </div>
        <div className={cs.narrowMetadataValueContainer}>
          <div className={cs.metadataValue}>
            {readsAfter ? readsAfter.toLocaleString() : ""}
          </div>
        </div>
        <div className={cs.narrowMetadataValueContainer}>
{'fraction_non_alphanumeric': 0.13364820015317846, 'fraction_numerical': 0.0025529742149604288, 'mean_word_length': 2.812652068126521, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4943640', 'n_tokens_mistral': 2314, 'n_tokens_neox': 2279, 'n_words': 448}