<commit_before>var classNames = require("classnames");
var React = require("react/addons");

var AppHealthComponent = require("../components/AppHealthComponent");
var AppListItemLabelsComponent =
  require("../components/AppListItemLabelsComponent");
var AppListViewTypes = require("../constants/AppListViewTypes");
var AppStatusComponent = require("../components/AppStatusComponent");
var Util = require("../helpers/Util");
var PathUtil = require("../helpers/PathUtil");
var DOMUtil = require("../helpers/DOMUtil");

var AppListItemComponent = React.createClass({
  displayName: "AppListItemComponent",

  contextTypes: {
    router: React.PropTypes.func
  },

  propTypes: {
    currentGroup: React.PropTypes.string.isRequired,
    model: React.PropTypes.object.isRequired,
    viewType: React.PropTypes.string
  },

  getDefaultProps: function () {
    return {
      viewType: AppListViewTypes.GROUPED_LIST
    };
  },

  getInitialState: function () {
    return {
      numberOfVisibleLabels: -1
    };
  },

  componentDidMount: function () {
    // Avoid referencing window from Node context
    if (global.window != null) {
      window.addEventListener("resize", this.handleResize);
      window.addEventListener("focus", this.handleResize);
    }
    this.updateNumberOfVisibleLabels();
  },

  componentDidUpdate: function (prevProps) {
    if (this.didPropsChange(prevProps)) {
      this.updateNumberOfVisibleLabels();
    }
  },

  componentWillUnmount: function () {
    if (global.window != null) {
      window.removeEventListener("resize", this.handleResize);
      window.removeEventListener("focus", this.handleResize);
    }
  },

  shouldComponentUpdate: function (nextProps, nextState) {
    if (nextState.numberOfVisibleLabels === -1 && !this.props.model.isGroup) {
      this.updateNumberOfVisibleLabels();
      return false;
    }

    if (this.state.numberOfVisibleLabels !== nextState.numberOfVisibleLabels) {
      return true;
    }

    return this.didPropsChange(nextProps);
  },

  didPropsChange: function (nextProps) {
    var props = this.props;

    return props.viewType !== nextProps.viewType ||
      !Util.compareProperties(props.model, nextProps.model, "status",
      "tasksRunning", "health", "totalMem", "totalCpus", "instances", "labels");
  },

  handleResize: function () {
    requestAnimationFrame(this.updateNumberOfVisibleLabels);
  },

  updateNumberOfVisibleLabels: function () {
    var labels = this.props.model.labels;

    if (labels == null || Object.keys(labels).length === 0) {
      this.setState({numberOfVisibleLabels: 0});
      return;
    }

    let refs = this.refs;

    let cellNode = React.findDOMNode(refs.nameCell);
    let nameNode = React.findDOMNode(refs.nameNode);
    let moreNode = React.findDOMNode(refs.moreLabel);

    let availableWidth = DOMUtil.getInnerWidth(cellNode) -
      DOMUtil.getOuterWidth(nameNode) -
      DOMUtil.getOuterWidth(moreNode);

    let labelsWidth = 0;
    let numberOfVisibleLabels = 0;
    let labelNodes = React.findDOMNode(refs.labels).querySelectorAll(".label");

    // labelNodes is not an Array, but a NodeList
    [].forEach.call(labelNodes, function (label) {
      labelsWidth += DOMUtil.getOuterWidth(label);
      if (labelsWidth > availableWidth) {
        return true;
      }
      numberOfVisibleLabels++;
    });

    this.setState({numberOfVisibleLabels: numberOfVisibleLabels});
  },

  getIcon: function () {
    var model = this.props.model;
    if (model.isGroup) {
      return (<i className="icon icon-small group"></i>);
    }
    return (<i className="icon icon-small app" title="Application"></i>);
  },

  getLabels: function () {
    var labels = this.props.model.labels;
    if (labels == null || Object.keys(labels).length === 0) {
      return null;
    }

    var moreLabelClassName = classNames("more", {
      "visible": Object.keys(labels).length > this.state.numberOfVisibleLabels
    });

    return (
     <AppListItemLabelsComponent ref="labels"
          labels={this.props.model.labels}
          numberOfVisibleLabels={this.state.numberOfVisibleLabels}>
        <span className={moreLabelClassName} ref="moreLabel">
          &hellip;
        </span>
     </AppListItemLabelsComponent>
    );
  },

  onClick: function () {
    var model = this.props.model;
    var router = this.context.router;
    if (model.isGroup) {
      let query = router.getCurrentQuery();
      let param = {
        groupId: encodeURIComponent(model.id)
      };
      router.transitionTo("group", param, query);
    } else {
      router.transitionTo("app", {appId: encodeURIComponent(model.id)});
    }
  },

  getHealthBar: function () {
    return (
      <td className="text-right health-bar-column">
        <AppHealthComponent model={this.props.model} />
      </td>
    );
  },

  getStatus: function () {
    return (
      <td className="text-right status">
        <AppStatusComponent model={this.props.model} />
      </td>
    );
  },

  getAppName: function () {
    var props = this.props;
    var model = props.model;

    if (props.viewType === AppListViewTypes.APP_LIST) {
      var groupId = PathUtil.getGroupFromAppId(model.id);
      var appName = PathUtil.getAppName(model.id);

      return (
        <td className="overflow-ellipsis name-cell global-app-list"
            title={model.id} ref="nameCell">
          <span className="name" ref="nameNode">
            <span className="app-name">{appName}</span>
            {this.getLabels()}
            <span className="group-id">{groupId}</span>
          </span>
        </td>
      );
    }

    let relativeAppName =
      PathUtil.getRelativePath(model.id, props.currentGroup);
    return (
      <td className="overflow-ellipsis name-cell"
          title={model.id} ref="nameCell">
        <span className="name" ref="nameNode">{relativeAppName}</span>
        {this.getLabels()}
      </td>
    );
  },

  render: function () {
    var props = this.props;
    var model = props.model;
<commit_msg>Show complete appId in path<commit_after>var classNames = require("classnames");
var React = require("react/addons");

var AppHealthComponent = require("../components/AppHealthComponent");
var AppListItemLabelsComponent =
  require("../components/AppListItemLabelsComponent");
var AppListViewTypes = require("../constants/AppListViewTypes");
var AppStatusComponent = require("../components/AppStatusComponent");
var Util = require("../helpers/Util");
var PathUtil = require("../helpers/PathUtil");
var DOMUtil = require("../helpers/DOMUtil");

var AppListItemComponent = React.createClass({
  displayName: "AppListItemComponent",

  contextTypes: {
    router: React.PropTypes.func
  },

  propTypes: {
    currentGroup: React.PropTypes.string.isRequired,
    model: React.PropTypes.object.isRequired,
    viewType: React.PropTypes.string
  },

  getDefaultProps: function () {
    return {
      viewType: AppListViewTypes.GROUPED_LIST
    };
  },

  getInitialState: function () {
    return {
      numberOfVisibleLabels: -1
    };
  },

  componentDidMount: function () {
    // Avoid referencing window from Node context
    if (global.window != null) {
      window.addEventListener("resize", this.handleResize);
      window.addEventListener("focus", this.handleResize);
    }
    this.updateNumberOfVisibleLabels();
  },

  componentDidUpdate: function (prevProps) {
    if (this.didPropsChange(prevProps)) {
      this.updateNumberOfVisibleLabels();
    }
  },

  componentWillUnmount: function () {
    if (global.window != null) {
      window.removeEventListener("resize", this.handleResize);
      window.removeEventListener("focus", this.handleResize);
    }
  },

  shouldComponentUpdate: function (nextProps, nextState) {
    if (nextState.numberOfVisibleLabels === -1 && !this.props.model.isGroup) {
      this.updateNumberOfVisibleLabels();
      return false;
    }

    if (this.state.numberOfVisibleLabels !== nextState.numberOfVisibleLabels) {
      return true;
    }

    return this.didPropsChange(nextProps);
  },

  didPropsChange: function (nextProps) {
    var props = this.props;

    return props.viewType !== nextProps.viewType ||
      !Util.compareProperties(props.model, nextProps.model, "status",
      "tasksRunning", "health", "totalMem", "totalCpus", "instances", "labels");
  },

  handleResize: function () {
    requestAnimationFrame(this.updateNumberOfVisibleLabels);
  },

  updateNumberOfVisibleLabels: function () {
    var labels = this.props.model.labels;

    if (labels == null || Object.keys(labels).length === 0) {
      this.setState({numberOfVisibleLabels: 0});
      return;
    }

    let refs = this.refs;

    let cellNode = React.findDOMNode(refs.nameCell);
    let nameNode = React.findDOMNode(refs.nameNode);
    let moreNode = React.findDOMNode(refs.moreLabel);

    let availableWidth = DOMUtil.getInnerWidth(cellNode) -
      DOMUtil.getOuterWidth(nameNode) -
      DOMUtil.getOuterWidth(moreNode);

    let labelsWidth = 0;
    let numberOfVisibleLabels = 0;
    let labelNodes = React.findDOMNode(refs.labels).querySelectorAll(".label");

    // labelNodes is not an Array, but a NodeList
    [].forEach.call(labelNodes, function (label) {
      labelsWidth += DOMUtil.getOuterWidth(label);
      if (labelsWidth > availableWidth) {
        return true;
      }
      numberOfVisibleLabels++;
    });

    this.setState({numberOfVisibleLabels: numberOfVisibleLabels});
  },

  getIcon: function () {
    var model = this.props.model;
    if (model.isGroup) {
      return (<i className="icon icon-small group"></i>);
    }
    return (<i className="icon icon-small app" title="Application"></i>);
  },

  getLabels: function () {
    var labels = this.props.model.labels;
    if (labels == null || Object.keys(labels).length === 0) {
      return null;
    }

    var moreLabelClassName = classNames("more", {
      "visible": Object.keys(labels).length > this.state.numberOfVisibleLabels
    });

    return (
     <AppListItemLabelsComponent ref="labels"
          labels={this.props.model.labels}
          numberOfVisibleLabels={this.state.numberOfVisibleLabels}>
        <span className={moreLabelClassName} ref="moreLabel">
          &hellip;
        </span>
     </AppListItemLabelsComponent>
    );
  },

  onClick: function () {
    var model = this.props.model;
    var router = this.context.router;
    if (model.isGroup) {
      let query = router.getCurrentQuery();
      let param = {
        groupId: encodeURIComponent(model.id)
      };
      router.transitionTo("group", param, query);
    } else {
      router.transitionTo("app", {appId: encodeURIComponent(model.id)});
    }
  },

  getHealthBar: function () {
    return (
      <td className="text-right health-bar-column">
        <AppHealthComponent model={this.props.model} />
      </td>
    );
  },

  getStatus: function () {
    return (
      <td className="text-right status">
        <AppStatusComponent model={this.props.model} />
      </td>
    );
  },

  getAppName: function () {
    var props = this.props;
    var model = props.model;

    if (props.viewType === AppListViewTypes.APP_LIST) {
      var groupId = model.id;
      var appName = PathUtil.getAppName(model.id);

      return (
        <td className="overflow-ellipsis name-cell global-app-list"
            title={model.id} ref="nameCell">
          <span className="name" ref="nameNode">
            <span className="app-name">{appName}</span>
            {this.getLabels()}
            <span className="group-id">{groupId}</span>
          </span>
        </td>
      );
    }

    let relativeAppName =
      PathUtil.getRelativePath(model.id, props.currentGroup);
    return (
      <td className="overflow-ellipsis name-cell"
          title={model.id} ref="nameCell">
        <span className="name" ref="nameNode">{relativeAppName}</span>
        {this.getLabels()}
      </td>
    );
  },

  render: function () {
    var props = this.props;
    var model = props.model;

{'fraction_non_alphanumeric': 0.13634849242045644, 'fraction_numerical': 0.0011660836248542396, 'mean_word_length': 3.084013605442177, 'pattern_counts': {'":': 2, '<': 55, '<?xml version=': 0, '>': 59, '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': '3737104', 'n_tokens_mistral': 3569, 'n_tokens_neox': 3502, 'n_words': 660}