<commit_before>/* global $ */

import React from 'react';
import PropTypes from 'prop-types';
import Link from '../../components/Link';
import Layout from '../../components/Layout';
import BlueprintContents from '../../components/ListView/BlueprintContents';
import ComponentInputs from '../../components/ListView/ComponentInputs';
import ComponentDetailsView from '../../components/ListView/ComponentDetailsView';
import CreateImage from '../../components/Modal/CreateImage';
import ExportBlueprint from '../../components/Modal/ExportBlueprint';
import PendingChanges from '../../components/Modal/PendingChanges';
import EmptyState from '../../components/EmptyState/EmptyState';
import Pagination from '../../components/Pagination/Pagination';
import Toolbar from '../../components/Toolbar/Toolbar';
import BlueprintApi from '../../data/BlueprintApi';
import NotificationsApi from '../../data/NotificationsApi';
import { connect } from 'react-redux';
import {
  fetchingBlueprintContents, setBlueprint, addBlueprintComponent, committingBlueprint,
  removeBlueprintComponent, undo, redo, commitToWorkspace, deleteHistory,
} from '../../core/actions/blueprints';
import {
  fetchingInputs, setInputComponents, setSelectedInputPage,
  setSelectedInput, setSelectedInputStatus, setSelectedInputParent, deleteFilter,
} from '../../core/actions/inputs';
import { setModalActive } from '../../core/actions/modals';
import {
  componentsSortSetKey, componentsSortSetValue, dependenciesSortSetKey, dependenciesSortSetValue,
} from '../../core/actions/sort';
import {
  makeGetBlueprintById, makeGetSortedSelectedComponents, makeGetSortedDependencies, makeGetFutureLength, makeGetPastLength
} from '../../core/selectors';

class EditBlueprintPage extends React.Component {
  constructor() {
    super();
    this.setNotifications = this.setNotifications.bind(this);
    this.handleCommit = this.handleCommit.bind(this);
    this.handlePagination = this.handlePagination.bind(this);
    this.handleAddComponent = this.handleAddComponent.bind(this);
    this.handleUpdateComponent = this.handleUpdateComponent.bind(this);
    this.handleRemoveComponent = this.handleRemoveComponent.bind(this);
    this.handleComponentDetails = this.handleComponentDetails.bind(this);
    this.handleHideModal = this.handleHideModal.bind(this);
    this.handleShowModal = this.handleShowModal.bind(this);
    this.handleHistory = this.handleHistory.bind(this);
    this.handleDiscardChanges = this.handleDiscardChanges.bind(this);
  }

  componentWillMount() {
    // get blueprint, get inputs; then update inputs
    if (this.props.blueprint.components === undefined) {
      this.props.fetchingBlueprintContents(this.props.route.params.blueprint.replace(/\s/g, '-'));
      this.props.fetchingInputs(this.props.inputs.inputFilters, 0, 50, undefined);
    } else {
      this.props.fetchingInputs(this.props.inputs.inputFilters, 0, 50, this.props.blueprint.components);
    }
    this.props.setSelectedInputPage(0);
    this.props.setSelectedInput('');
    this.props.setSelectedInputParent('');
    this.props.setSelectedInputStatus('');
  }

  componentDidMount() {
    document.title = 'Blueprint';
  }

  componentWillUnmount() {
    this.props.deleteFilter();
  }

  setNotifications() {
    this.layout.setNotifications();
  }

  getFilteredInputs(event) {
    if (event.which === 13 || event.keyCode === 13) {
      const filter = {
        field: 'name',
        value: event.target.value,
      };
      this.props.fetchingInputs(filter, 0, this.props.inputs.pageSize, this.props.selectedComponents);
      this.props.setSelectedInputPage(0);
      // TODO handle the case where no results are returned
      $('#cmpsr-blueprint-input-filter').blur();
      event.preventDefault();
    }
  }

  updateInputComponentData(inputs, page, componentData) {
    // updates the input component data to match the blueprint component data
    // where componentData represents either a single blueprint component
    // or the entire set of blueprint components
    if (componentData === undefined) {
      componentData = this.props.selectedComponents; // eslint-disable-line no-param-reassign
    }
    let updatedInputs = inputs;
    if (componentData.length > 0) {
      updatedInputs = componentData.map(component => {
        const index = inputs[page].map(input => input.name).indexOf(component.name);
        if (index >= 0) {
          inputs[page][index].inBlueprint = true; // eslint-disable-line no-param-reassign
          inputs[page][index].userSelected = true; // eslint-disable-line no-param-reassign
          inputs[page][index].versionSelected = component.version; // eslint-disable-line no-param-reassign
          inputs[page][index].releaseSelected = component.release; // eslint-disable-line no-param-reassign
        }
        return inputs;
      });
      updatedInputs = updatedInputs[0];
    }
    return updatedInputs;
  }

  handleClearFilters(event) {
    const filter = {
      field: 'name',
      value: '',
    };
    this.props.deleteFilter();
    this.props.fetchingInputs(filter, 0, this.props.inputs.pageSize, this.props.blueprint.components);
    $('#cmpsr-blueprint-input-filter').val('');
    event.preventDefault();
    event.stopPropagation();
  }

  handlePagination(event) {
    // the event target knows what page to get
    // the event target can either be the paging buttons on the page input
    let page;

    if (event.currentTarget.localName === 'a') {
      page = parseFloat(event.currentTarget.getAttribute('data-page'));
      event.preventDefault();
      event.stopPropagation();
    } else {
      if (event.which === 13 || event.keyCode === 13) {
        page = parseFloat(event.currentTarget.value) - 1;
        event.preventDefault();
        event.stopPropagation();
      } else {
        return; // don't continue if keypress was not the Enter key
      }
    }
    // if the data already exists, just update the selected page number and
    // the DOM will automatically reload
    this.props.setSelectedInputPage(page);
    const filter = this.props.inputs.inputFilters;
    // check if filters are set to determine current input set
    if (this.props.inputs.inputComponents.slice(0)[page].length === 0) {
      this.props.fetchingInputs(filter, page, this.props.inputs.pageSize, this.props.selectedComponents);
    }
  }

  clearInputAlert() {
    $('#cmpsr-blueprint-inputs .alert').remove();
  }

  handleCommit () {
    // clear existing notifications
    NotificationsApi.closeNotification(undefined, 'committed');
    NotificationsApi.closeNotification(undefined, 'committing');
    // display the committing notification
    NotificationsApi.displayNotification(this.props.blueprint.name, 'committing');
    this.setNotifications();
    // post blueprint (includes 'committed' notification)
    Promise.all([BlueprintApi.handleCommitBlueprint(this.props.blueprint)])
      .then(() => {
        // then after blueprint is posted, reload blueprint details
        // to get details that were updated during commit (i.e. version)
        Promise.all([BlueprintApi.reloadBlueprintDetails(this.props.blueprint)])
          .then(data => {
            const blueprintToSet = this.props.blueprint;
            blueprintToSet.name = data[0].name;
            blueprintToSet.description = data[0].description;
            blueprintToSet.version = data[0].version;
            this.props.setBlueprint(blueprintToSet);
          })
          .catch(e => console.log(`Error in reload blueprint details: ${e}`));
      })
      .catch(e => console.log(`Error in blueprint commit: ${e}`));
  }

  handleAddComponent(event, source, component) {
    // the user clicked Add in the sidebar, e.g. source === "input"
    // or the user clicked Add in the details view
    component.inBlueprint = true; // eslint-disable-line no-param-reassign
    component.userSelected = true; // eslint-disable-line no-param-reassign
    if (component !== undefined) {
      if (source === 'input') {
        $(event.currentTarget).tooltip('hide');
      }
      // if source is the details view, then metadata is already known and passed with component
      this.props.addBlueprintComponent(this.props.blueprint, component);
    }

    // update input component data to match the blueprint component data
    this.updateInputComponentsOnChange(component);
    // TODO if inputs also lists dependencies, should these be indicated as included in the list of available components?
    this.props.setSelectedInput('');
    this.props.setSelectedInputStatus('');
    // remove the inline message above the list of inputs
    this.clearInputAlert();
    event.preventDefault();
    event.stopPropagation();
  }

  handleUpdateComponent(event, component) {<commit_msg>Call updateComponent when adding components to Blueprint<commit_after>/* global $ */

import React from 'react';
import PropTypes from 'prop-types';
import Link from '../../components/Link';
import Layout from '../../components/Layout';
import BlueprintContents from '../../components/ListView/BlueprintContents';
import ComponentInputs from '../../components/ListView/ComponentInputs';
import ComponentDetailsView from '../../components/ListView/ComponentDetailsView';
import CreateImage from '../../components/Modal/CreateImage';
import ExportBlueprint from '../../components/Modal/ExportBlueprint';
import PendingChanges from '../../components/Modal/PendingChanges';
import EmptyState from '../../components/EmptyState/EmptyState';
import Pagination from '../../components/Pagination/Pagination';
import Toolbar from '../../components/Toolbar/Toolbar';
import BlueprintApi from '../../data/BlueprintApi';
import NotificationsApi from '../../data/NotificationsApi';
import { connect } from 'react-redux';
import {
  fetchingBlueprintContents, setBlueprint, addBlueprintComponent, committingBlueprint,
  removeBlueprintComponent, undo, redo, commitToWorkspace, deleteHistory,
} from '../../core/actions/blueprints';
import {
  fetchingInputs, setInputComponents, setSelectedInputPage,
  setSelectedInput, setSelectedInputStatus, setSelectedInputParent, deleteFilter,
} from '../../core/actions/inputs';
import { setModalActive } from '../../core/actions/modals';
import {
  componentsSortSetKey, componentsSortSetValue, dependenciesSortSetKey, dependenciesSortSetValue,
} from '../../core/actions/sort';
import {
  makeGetBlueprintById, makeGetSortedSelectedComponents, makeGetSortedDependencies, makeGetFutureLength, makeGetPastLength
} from '../../core/selectors';

class EditBlueprintPage extends React.Component {
  constructor() {
    super();
    this.setNotifications = this.setNotifications.bind(this);
    this.handleCommit = this.handleCommit.bind(this);
    this.handlePagination = this.handlePagination.bind(this);
    this.handleAddComponent = this.handleAddComponent.bind(this);
    this.handleUpdateComponent = this.handleUpdateComponent.bind(this);
    this.handleRemoveComponent = this.handleRemoveComponent.bind(this);
    this.handleComponentDetails = this.handleComponentDetails.bind(this);
    this.handleHideModal = this.handleHideModal.bind(this);
    this.handleShowModal = this.handleShowModal.bind(this);
    this.handleHistory = this.handleHistory.bind(this);
    this.handleDiscardChanges = this.handleDiscardChanges.bind(this);
  }

  componentWillMount() {
    // get blueprint, get inputs; then update inputs
    if (this.props.blueprint.components === undefined) {
      this.props.fetchingBlueprintContents(this.props.route.params.blueprint.replace(/\s/g, '-'));
      this.props.fetchingInputs(this.props.inputs.inputFilters, 0, 50, undefined);
    } else {
      this.props.fetchingInputs(this.props.inputs.inputFilters, 0, 50, this.props.blueprint.components);
    }
    this.props.setSelectedInputPage(0);
    this.props.setSelectedInput('');
    this.props.setSelectedInputParent('');
    this.props.setSelectedInputStatus('');
  }

  componentDidMount() {
    document.title = 'Blueprint';
  }

  componentWillUnmount() {
    this.props.deleteFilter();
  }

  setNotifications() {
    this.layout.setNotifications();
  }

  getFilteredInputs(event) {
    if (event.which === 13 || event.keyCode === 13) {
      const filter = {
        field: 'name',
        value: event.target.value,
      };
      this.props.fetchingInputs(filter, 0, this.props.inputs.pageSize, this.props.selectedComponents);
      this.props.setSelectedInputPage(0);
      // TODO handle the case where no results are returned
      $('#cmpsr-blueprint-input-filter').blur();
      event.preventDefault();
    }
  }

  updateInputComponentData(inputs, page, componentData) {
    // updates the input component data to match the blueprint component data
    // where componentData represents either a single blueprint component
    // or the entire set of blueprint components
    if (componentData === undefined) {
      componentData = this.props.selectedComponents; // eslint-disable-line no-param-reassign
    }
    let updatedInputs = inputs;
    if (componentData.length > 0) {
      updatedInputs = componentData.map(component => {
        const index = inputs[page].map(input => input.name).indexOf(component.name);
        if (index >= 0) {
          inputs[page][index].inBlueprint = true; // eslint-disable-line no-param-reassign
          inputs[page][index].userSelected = true; // eslint-disable-line no-param-reassign
          inputs[page][index].versionSelected = component.version; // eslint-disable-line no-param-reassign
          inputs[page][index].releaseSelected = component.release; // eslint-disable-line no-param-reassign
        }
        return inputs;
      });
      updatedInputs = updatedInputs[0];
    }
    return updatedInputs;
  }

  handleClearFilters(event) {
    const filter = {
      field: 'name',
      value: '',
    };
    this.props.deleteFilter();
    this.props.fetchingInputs(filter, 0, this.props.inputs.pageSize, this.props.blueprint.components);
    $('#cmpsr-blueprint-input-filter').val('');
    event.preventDefault();
    event.stopPropagation();
  }

  handlePagination(event) {
    // the event target knows what page to get
    // the event target can either be the paging buttons on the page input
    let page;

    if (event.currentTarget.localName === 'a') {
      page = parseFloat(event.currentTarget.getAttribute('data-page'));
      event.preventDefault();
      event.stopPropagation();
    } else {
      if (event.which === 13 || event.keyCode === 13) {
        page = parseFloat(event.currentTarget.value) - 1;
        event.preventDefault();
        event.stopPropagation();
      } else {
        return; // don't continue if keypress was not the Enter key
      }
    }
    // if the data already exists, just update the selected page number and
    // the DOM will automatically reload
    this.props.setSelectedInputPage(page);
    const filter = this.props.inputs.inputFilters;
    // check if filters are set to determine current input set
    if (this.props.inputs.inputComponents.slice(0)[page].length === 0) {
      this.props.fetchingInputs(filter, page, this.props.inputs.pageSize, this.props.selectedComponents);
    }
  }

  clearInputAlert() {
    $('#cmpsr-blueprint-inputs .alert').remove();
  }

  handleCommit () {
    // clear existing notifications
    NotificationsApi.closeNotification(undefined, 'committed');
    NotificationsApi.closeNotification(undefined, 'committing');
    // display the committing notification
    NotificationsApi.displayNotification(this.props.blueprint.name, 'committing');
    this.setNotifications();
    // post blueprint (includes 'committed' notification)
    Promise.all([BlueprintApi.handleCommitBlueprint(this.props.blueprint)])
      .then(() => {
        // then after blueprint is posted, reload blueprint details
        // to get details that were updated during commit (i.e. version)
        Promise.all([BlueprintApi.reloadBlueprintDetails(this.props.blueprint)])
          .then(data => {
            const blueprintToSet = this.props.blueprint;
            blueprintToSet.name = data[0].name;
            blueprintToSet.description = data[0].description;
            blueprintToSet.version = data[0].version;
            this.props.setBlueprint(blueprintToSet);
          })
          .catch(e => console.log(`Error in reload blueprint details: ${e}`));
      })
      .catch(e => console.log(`Error in blueprint commit: ${e}`));
  }

  handleAddComponent(event, source, component) {
    // the user clicked Add in the sidebar, e.g. source === "input"
    // or the user clicked Add in the details view
    component.inBlueprint = true; // eslint-disable-line no-param-reassign
    component.userSelected = true; // eslint-disable-line no-param-reassign
    if (component !== undefined) {
      if (source === 'input') {
        $(event.currentTarget).tooltip('hide');
      }
      // if source is the details view, then metadata is already known and passed with component
      this.props.addBlueprintComponent(this.props.blueprint, component);
    }
    BlueprintApi.updateBlueprint(component, 'add');
    // update input component data to match the blueprint component data
    this.updateInputComponentsOnChange(component);
    // TODO if inputs also lists dependencies, should these be indicated as included in the list of available components?
    this.props.setSelectedInput('');
    this.props.setSelectedInputStatus('');
    // remove the inline message above the list of inputs
    this.clearInputAlert();
    event.preventDefault();
    event.stopPropagation();
  }

  handleUpdateComponent(event, component) {
{'fraction_non_alphanumeric': 0.12501416109663532, 'fraction_numerical': 0.003058796873229863, 'mean_word_length': 3.5118834653718376, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 19, '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': '215519', 'n_tokens_mistral': 4785, 'n_tokens_neox': 4811, 'n_words': 1088}