<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import styled, {css} from 'styled-components';

import AsyncPage from '../components/AsyncPage';
import Badge from '../components/Badge';
import BuildAuthor from '../components/BuildAuthor';
import {Breadcrumbs, Crumb, CrumbLink} from '../components/Breadcrumbs';
import ObjectCoverage from '../components/ObjectCoverage';
import ObjectDuration from '../components/ObjectDuration';
import ObjectResult from '../components/ObjectResult';
import RepositoryHeader from '../components/RepositoryHeader';
import ScrollView from '../components/ScrollView';
import TabbedNavItem from '../components/TabbedNavItem';
import TimeSince from '../components/TimeSince';

import IconClock from '../assets/IconClock';

export default class BuildDetails extends AsyncPage {
  static contextTypes = {
    ...AsyncPage.contextTypes,
    repo: PropTypes.object.isRequired
  };

  static childContextTypes = {
    ...AsyncPage.childContextTypes,
    ...BuildDetails.contextTypes,
    build: PropTypes.object
  };

  getChildContext() {
    return {
      ...this.context,
      build: this.state.build
    };
  }

  getEndpoints() {
    let {repo} = this.context;
    let {buildNumber} = this.props.params;
    return [['build', `/repos/${repo.full_name}/builds/${buildNumber}`]];
  }

  getTitle() {
    return 'Build Details';
  }

  shouldFetchUpdates() {
    return (this.state.build || {}).status !== 'finished';
  }

  render() {
    // happens before loading is done
    let {repo} = this.context;
    let {buildNumber} = this.props.params;
    return (
      <RepositoryHeader>
        <Breadcrumbs>
          <CrumbLink to={`/${repo.provider}/${repo.owner_name}`}>
            {repo.owner_name}
          </CrumbLink>
          <CrumbLink to={`/${repo.full_name}`}>
            {repo.name}
          </CrumbLink>
          <Crumb>
            #{buildNumber}
          </Crumb>
        </Breadcrumbs>
        <ScrollView>
          {this.renderContent()}
        </ScrollView>
      </RepositoryHeader>
    );
  }

  renderBody() {
    let {build} = this.state;
    let {repo} = this.context;
    let {buildNumber} = this.props.params;
    let hasCoverage =
      build.stats.coverage.lines_covered > 0 || build.stats.coverage.lines_uncovered > 0;
    let hasDiffCoverage =
      build.stats.coverage.diff_lines_covered > 0 ||
      build.stats.coverage.diff_lines_uncovered > 0;
    let hasTests = build.stats.tests.count > 0;
    return (
      <div>
        <BuildSummary>
          <Header>
            <Message>
              {build.source.revision.message}
            </Message>
          </Header>
          <Meta>
            {build.status === 'finished' &&
              <DurationWrapper result={build.result}>
                <ObjectResult data={build} />
                {build.result} <TimeSince date={build.finished_at} /> in{' '}
                <ObjectDuration data={build} short={true} />
              </DurationWrapper>}
            <Time>
              <IconClock size="15" />
              {build.status === 'queued'
                ? <span>
                    created <TimeSince date={build.created_at} />
                  </span>
                : <span>
                    started <TimeSince date={build.started_at} />
                  </span>}
            </Time>
            <Author>
              <BuildAuthor build={build} />
            </Author>
            <Commit>
              {build.source.revision.sha.substr(0, 7)}
            </Commit>
          </Meta>
          <Tabs>
            <TabbedNavItem
              to={`/${repo.full_name}/builds/${buildNumber}`}
              onlyActiveOnIndex={true}>
              Overview
            </TabbedNavItem>
            <TabbedNavItem
              to={`/${repo.full_name}/builds/${buildNumber}/tests`}
              disabled={!hasTests}>
              Tests
              {hasTests
                ? <Badge>
                    {build.stats.tests.count.toLocaleString()}
                  </Badge>
                : null}
            </TabbedNavItem>
            <TabbedNavItem
              to={`/${repo.full_name}/builds/${buildNumber}/coverage`}
              disabled={!hasCoverage}>
              Code Coverage
              {hasDiffCoverage
                ? <Badge>
                    <ObjectCoverage data={build} diff={false} />
                  </Badge>
                : null}
            </TabbedNavItem>
            <TabbedNavItem to={`/${repo.full_name}/builds/${buildNumber}/diff`}>
              Diff
            </TabbedNavItem><commit_msg>fix: Show coverage badge if any available<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import styled, {css} from 'styled-components';

import AsyncPage from '../components/AsyncPage';
import Badge from '../components/Badge';
import BuildAuthor from '../components/BuildAuthor';
import {Breadcrumbs, Crumb, CrumbLink} from '../components/Breadcrumbs';
import ObjectCoverage from '../components/ObjectCoverage';
import ObjectDuration from '../components/ObjectDuration';
import ObjectResult from '../components/ObjectResult';
import RepositoryHeader from '../components/RepositoryHeader';
import ScrollView from '../components/ScrollView';
import TabbedNavItem from '../components/TabbedNavItem';
import TimeSince from '../components/TimeSince';

import IconClock from '../assets/IconClock';

export default class BuildDetails extends AsyncPage {
  static contextTypes = {
    ...AsyncPage.contextTypes,
    repo: PropTypes.object.isRequired
  };

  static childContextTypes = {
    ...AsyncPage.childContextTypes,
    ...BuildDetails.contextTypes,
    build: PropTypes.object
  };

  getChildContext() {
    return {
      ...this.context,
      build: this.state.build
    };
  }

  getEndpoints() {
    let {repo} = this.context;
    let {buildNumber} = this.props.params;
    return [['build', `/repos/${repo.full_name}/builds/${buildNumber}`]];
  }

  getTitle() {
    return 'Build Details';
  }

  shouldFetchUpdates() {
    return (this.state.build || {}).status !== 'finished';
  }

  render() {
    // happens before loading is done
    let {repo} = this.context;
    let {buildNumber} = this.props.params;
    return (
      <RepositoryHeader>
        <Breadcrumbs>
          <CrumbLink to={`/${repo.provider}/${repo.owner_name}`}>
            {repo.owner_name}
          </CrumbLink>
          <CrumbLink to={`/${repo.full_name}`}>
            {repo.name}
          </CrumbLink>
          <Crumb>
            #{buildNumber}
          </Crumb>
        </Breadcrumbs>
        <ScrollView>
          {this.renderContent()}
        </ScrollView>
      </RepositoryHeader>
    );
  }

  renderBody() {
    let {build} = this.state;
    let {repo} = this.context;
    let {buildNumber} = this.props.params;
    let hasCoverage =
      build.stats.coverage.lines_covered > 0 || build.stats.coverage.lines_uncovered > 0;
    let hasTests = build.stats.tests.count > 0;
    return (
      <div>
        <BuildSummary>
          <Header>
            <Message>
              {build.source.revision.message}
            </Message>
          </Header>
          <Meta>
            {build.status === 'finished' &&
              <DurationWrapper result={build.result}>
                <ObjectResult data={build} />
                {build.result} <TimeSince date={build.finished_at} /> in{' '}
                <ObjectDuration data={build} short={true} />
              </DurationWrapper>}
            <Time>
              <IconClock size="15" />
              {build.status === 'queued'
                ? <span>
                    created <TimeSince date={build.created_at} />
                  </span>
                : <span>
                    started <TimeSince date={build.started_at} />
                  </span>}
            </Time>
            <Author>
              <BuildAuthor build={build} />
            </Author>
            <Commit>
              {build.source.revision.sha.substr(0, 7)}
            </Commit>
          </Meta>
          <Tabs>
            <TabbedNavItem
              to={`/${repo.full_name}/builds/${buildNumber}`}
              onlyActiveOnIndex={true}>
              Overview
            </TabbedNavItem>
            <TabbedNavItem
              to={`/${repo.full_name}/builds/${buildNumber}/tests`}
              disabled={!hasTests}>
              Tests
              {hasTests
                ? <Badge>
                    {build.stats.tests.count.toLocaleString()}
                  </Badge>
                : null}
            </TabbedNavItem>
            <TabbedNavItem
              to={`/${repo.full_name}/builds/${buildNumber}/coverage`}
              disabled={!hasCoverage}>
              Code Coverage
              {hasCoverage
                ? <Badge>
                    <ObjectCoverage data={build} diff={false} />
                  </Badge>
                : null}
            </TabbedNavItem>
            <TabbedNavItem to={`/${repo.full_name}/builds/${buildNumber}/diff`}>
              Diff
            </TabbedNavItem>
{'fraction_non_alphanumeric': 0.13550581522931754, 'fraction_numerical': 0.0017555409260478386, 'mean_word_length': 1.8193628209093722, 'pattern_counts': {'":': 0, '<': 109, '<?xml version=': 0, '>': 117, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2949833', 'n_tokens_mistral': 2555, 'n_tokens_neox': 2526, 'n_words': 483}