<commit_before>import React             from 'react';
import CollapsibleWidget from 'paraviewweb/src/React/Widgets/CollapsibleWidget';
import LogFold           from './LogFold';
import { formatTime }    from '../../utils/Format';
import style             from 'HPCCloudStyle/JobMonitor.mcss';
import get               from '../../utils/get';

// takes log array -> jsx lines, or if there's more information LogFold
function logMapper(entry, index) {
  let content = '';
  let foldContent = null;
  let msg = entry.msg;
  let color = '';
  if (msg !== null && typeof msg === 'object') {
    msg = JSON.stringify(msg, null, 2);
  }

  if (entry.status) {
    msg += ` [${entry.status}]`;
  }

  if (entry.levelname === 'WARNING') {
    color = style.logWarn;
  } else if (entry.levelname === 'ERROR') {
    color = style.logError;
  }

  content += `[${formatTime(entry.created)}] ${entry.levelname}: ${msg}`;

  if (entry.exc_info) {
    foldContent = entry.exc_info[2].join('');
    foldContent += `${entry.exc_info[0]}: ${entry.exc_info[1]}`;
  }

  if (entry.data && Object.keys(entry.data).length > 0) {
    foldContent = `${JSON.stringify(entry.data, null, 2)}`;
  }

  if (foldContent !== null) {
    return (<LogFold key={`${entry.created}_${index}`}
      header={content} content={foldContent} color={color} />);
  }

  return (<p key={`${entry.created}_${index}`} className={`${style.logEntry} ${color}`}>
    {content}
  </p>);
}

export default React.createClass({
  displayName: 'ExecutionUnit',

  propTypes: {
    unit: React.PropTypes.object.isRequired,
    // optionals
    onToggle: React.PropTypes.func,
    alwaysShowLogToggle: React.PropTypes.bool,
    inline: React.PropTypes.bool,
    logOnly: React.PropTypes.bool,
    open: React.PropTypes.bool,
  },

  getDefaultProps() {
    return {
      alwaysShowLogToggle: false,
      inline: false,
      logOnly: false,
      open: false,
    };
  },

  getInitialState() {
    return { open: this.props.open };
  },

  componentWillUpdate(nextProps, nextState) {
    // we want to update other stuff, but if the unit log is empty, ignore it.
    if (!get(nextProps, 'unit.log.length')) {
      nextProps.unit.log = this.props.unit.log;
    }
  },

  componentDidUpdate(prevProps, prevState) {
    // the <pre> needs to be rendered open to have scrollHeight, then it scrolls
    if (this.state.open && this.refs.log) {
      this.refs.log.scrollTop = this.refs.log.scrollHeight;
    }
  },<commit_msg>proper log appending<commit_after>import React             from 'react';
import CollapsibleWidget from 'paraviewweb/src/React/Widgets/CollapsibleWidget';
import LogFold           from './LogFold';
import { formatTime }    from '../../utils/Format';
import style             from 'HPCCloudStyle/JobMonitor.mcss';
import get               from '../../utils/get';

// takes log array -> jsx lines, or if there's more information LogFold
function logMapper(entry, index) {
  if (!entry) {
    return null;
  }
  let content = '';
  let foldContent = null;
  let msg = entry.msg;
  let color = '';
  if (msg !== null && typeof msg === 'object') {
    msg = JSON.stringify(msg, null, 2);
  }

  if (entry.status) {
    msg += ` [${entry.status}]`;
  }

  if (entry.levelname === 'WARNING') {
    color = style.logWarn;
  } else if (entry.levelname === 'ERROR') {
    color = style.logError;
  }

  content += `[${formatTime(entry.created)}] ${entry.levelname}: ${msg}`;

  if (entry.exc_info) {
    foldContent = entry.exc_info[2].join('');
    foldContent += `${entry.exc_info[0]}: ${entry.exc_info[1]}`;
  }

  if (entry.data && Object.keys(entry.data).length > 0) {
    foldContent = `${JSON.stringify(entry.data, null, 2)}`;
  }

  if (foldContent !== null) {
    return (<LogFold key={`${entry.created}_${index}`}
      header={content} content={foldContent} color={color} />);
  }

  return (<p key={`${entry.created}_${index}`} className={`${style.logEntry} ${color}`}>
    {content}
  </p>);
}

export default React.createClass({
  displayName: 'ExecutionUnit',

  propTypes: {
    unit: React.PropTypes.object.isRequired,
    // optionals
    onToggle: React.PropTypes.func,
    alwaysShowLogToggle: React.PropTypes.bool,
    inline: React.PropTypes.bool,
    logOnly: React.PropTypes.bool,
    open: React.PropTypes.bool,
  },

  getDefaultProps() {
    return {
      alwaysShowLogToggle: false,
      inline: false,
      logOnly: false,
      open: false,
    };
  },

  getInitialState() {
    return { open: this.props.open };
  },

  componentWillUpdate(nextProps, nextState) {
    // we want to update other stuff, but if the unit log is empty, ignore it.
    if (get(nextProps, 'unit.log.length') < get(this.props, 'unit.log.length')) {
      nextProps.unit.log = (this.props.unit.log || []).concat(nextProps.unit.log);
    }
  },

  componentDidUpdate(prevProps, prevState) {
    // the <pre> needs to be rendered open to have scrollHeight, then it scrolls
    if (this.state.open && this.refs.log) {
      this.refs.log.scrollTop = this.refs.log.scrollHeight;
    }
  },
{'fraction_non_alphanumeric': 0.16485256283396002, 'fraction_numerical': 0.002374826835543242, 'mean_word_length': 3.0496794871794872, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 15, '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': '3817400', 'n_tokens_mistral': 1684, 'n_tokens_neox': 1660, 'n_words': 375}