<commit_before>// TODO: make with real data
import React, {PropTypes} from 'react';
import _ from 'lodash';

const AlertsTable = React.createClass({
  propTypes: {
    alerts: PropTypes.arrayOf(PropTypes.shape({
      name: PropTypes.string,
      time: PropTypes.string,
      value: PropTypes.string,
      host: PropTypes.string,
      level: PropTypes.string,
    })),
    source: PropTypes.shape({
      id: PropTypes.string.isRequired,
      name: PropTypes.string.isRequired,
    }).isRequired,
  },

  getInitialState() {
    return {
      searchTerm: '',
      filteredAlerts: this.props.alerts,
      sortDirection: null,
      sortKey: null,
    };
  },

  componentWillReceiveProps(newProps) {
    this.filterAlerts(newProps.alerts, this.state.searchTerm);
  },

  filterAlerts(allAlerts, searchTerm) {
    const alerts = allAlerts.filter((h) => {
      return h.name.toLowerCase().search(searchTerm.toLowerCase()) !== -1 ||
              h.host.toLowerCase().search(searchTerm.toLowerCase()) !== -1 ||
              h.level.toLowerCase().search(searchTerm.toLowerCase()) !== -1;
    });
    this.setState({searchTerm, filteredAlerts: alerts});
  },

  changeSort(key) {
    // if we're using the key, reverse order; otherwise, set it with ascending
    if (this.state.sortKey === key) {
      const reverseDirection = (this.state.sortDirection === 'asc' ? 'desc' : 'asc');
      this.setState({sortDirection: reverseDirection});
    } else {
      this.setState({sortKey: key, sortDirection: 'asc'});
    }
  },

  sort(alerts, key, direction) {
    switch (direction) {
      case 'asc':
        return _.sortBy(alerts, (e) => e[key]);
      case 'desc':
        return _.sortBy(alerts, (e) => e[key]).reverse();
      default:
        return alerts;
    }
  },

  render() {
    const alerts = this.sort(this.state.filteredAlerts, this.state.sortKey, this.state.sortDirection);
    return (
      <div className="panel panel-minimal">
        <div className="panel-heading u-flex u-ai-center u-jc-space-between">
          <h2 className="panel-title">{this.props.alerts.length} Alerts</h2>
          <SearchBar onSearch={_.wrap(this.props.alerts, this.filterAlerts)} />
        </div>
        <div className="panel-body">
          <table className="table v-center">
            <thead>
              <tr>
                <th onClick={() => this.changeSort('name')} className="sortable-header">Name</th>
                <th onClick={() => this.changeSort('level')} className="sortable-header">Level</th>
                <th onClick={() => this.changeSort('time')} className="sortable-header">Time</th>
                <th onClick={() => this.changeSort('host')} className="sortable-header">Host</th>
                <th onClick={() => this.changeSort('value')} className="sortable-header">Value</th>
              </tr>
            </thead>
            <tbody>
              {
                alerts.map(({name, time, value, host, level}) => {
                  return (
                    <tr key={`${name}-${time}-${host}-${value}`}>
                      <td className="monotype">{name}</td>
                      <td className="monotype">{level}</td>
                      <td className="monotype">{(new Date(Number(time)).toISOString())}</td>
                      <td className="monotype">{host}</td>
                      <td className="monotype">{value}</td>
                    </tr>
                  );
                })
              }
            </tbody>
          </table>
        </div>
      </div>
    );
  },
});

const SearchBar = React.createClass({
  propTypes: {
    onSearch: PropTypes.func.isRequired,
  },

  handleChange() {
    this.props.onSearch(this.refs.searchInput.value);
  },

  render() {
    return (
      <div className="users__search-widget input-group">
        <input
          type="text"
          className="form-control"
          placeholder="Filter Alerts"
          ref="searchInput"
          onChange={this.handleChange}
        />
        <div className="input-group-addon">
          <span className="icon search" aria-hidden="true"></span><commit_msg>UI microcopy tweak<commit_after>// TODO: make with real data
import React, {PropTypes} from 'react';
import _ from 'lodash';

const AlertsTable = React.createClass({
  propTypes: {
    alerts: PropTypes.arrayOf(PropTypes.shape({
      name: PropTypes.string,
      time: PropTypes.string,
      value: PropTypes.string,
      host: PropTypes.string,
      level: PropTypes.string,
    })),
    source: PropTypes.shape({
      id: PropTypes.string.isRequired,
      name: PropTypes.string.isRequired,
    }).isRequired,
  },

  getInitialState() {
    return {
      searchTerm: '',
      filteredAlerts: this.props.alerts,
      sortDirection: null,
      sortKey: null,
    };
  },

  componentWillReceiveProps(newProps) {
    this.filterAlerts(newProps.alerts, this.state.searchTerm);
  },

  filterAlerts(allAlerts, searchTerm) {
    const alerts = allAlerts.filter((h) => {
      return h.name.toLowerCase().search(searchTerm.toLowerCase()) !== -1 ||
              h.host.toLowerCase().search(searchTerm.toLowerCase()) !== -1 ||
              h.level.toLowerCase().search(searchTerm.toLowerCase()) !== -1;
    });
    this.setState({searchTerm, filteredAlerts: alerts});
  },

  changeSort(key) {
    // if we're using the key, reverse order; otherwise, set it with ascending
    if (this.state.sortKey === key) {
      const reverseDirection = (this.state.sortDirection === 'asc' ? 'desc' : 'asc');
      this.setState({sortDirection: reverseDirection});
    } else {
      this.setState({sortKey: key, sortDirection: 'asc'});
    }
  },

  sort(alerts, key, direction) {
    switch (direction) {
      case 'asc':
        return _.sortBy(alerts, (e) => e[key]);
      case 'desc':
        return _.sortBy(alerts, (e) => e[key]).reverse();
      default:
        return alerts;
    }
  },

  render() {
    const alerts = this.sort(this.state.filteredAlerts, this.state.sortKey, this.state.sortDirection);
    return (
      <div className="panel panel-minimal">
        <div className="panel-heading u-flex u-ai-center u-jc-space-between">
          <h2 className="panel-title">{this.props.alerts.length} Alerts</h2>
          <SearchBar onSearch={_.wrap(this.props.alerts, this.filterAlerts)} />
        </div>
        <div className="panel-body">
          <table className="table v-center">
            <thead>
              <tr>
                <th onClick={() => this.changeSort('name')} className="sortable-header">Name</th>
                <th onClick={() => this.changeSort('level')} className="sortable-header">Level</th>
                <th onClick={() => this.changeSort('time')} className="sortable-header">Time</th>
                <th onClick={() => this.changeSort('host')} className="sortable-header">Host</th>
                <th onClick={() => this.changeSort('value')} className="sortable-header">Value</th>
              </tr>
            </thead>
            <tbody>
              {
                alerts.map(({name, time, value, host, level}) => {
                  return (
                    <tr key={`${name}-${time}-${host}-${value}`}>
                      <td className="monotype">{name}</td>
                      <td className="monotype">{level}</td>
                      <td className="monotype">{(new Date(Number(time)).toISOString())}</td>
                      <td className="monotype">{host}</td>
                      <td className="monotype">{value}</td>
                    </tr>
                  );
                })
              }
            </tbody>
          </table>
        </div>
      </div>
    );
  },
});

const SearchBar = React.createClass({
  propTypes: {
    onSearch: PropTypes.func.isRequired,
  },

  handleChange() {
    this.props.onSearch(this.refs.searchInput.value);
  },

  render() {
    return (
      <div className="users__search-widget input-group">
        <input
          type="text"
          className="form-control"
          placeholder="Filter Alerts by Name..."
          ref="searchInput"
          onChange={this.handleChange}
        />
        <div className="input-group-addon">
          <span className="icon search" aria-hidden="true"></span>
{'fraction_non_alphanumeric': 0.16061486322924232, 'fraction_numerical': 0.0012103606874848704, 'mean_word_length': 2.2151750972762647, 'pattern_counts': {'":': 0, '<': 91, '<?xml version=': 0, '>': 109, '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': '6801874', 'n_tokens_mistral': 2424, 'n_tokens_neox': 2412, 'n_words': 433}