<commit_before>/*
 * Copyright 2019 EPAM Systems
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { Component } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, intlShape } from 'react-intl';
import { connect } from 'react-redux';
import classNames from 'classnames/bind';
import { showModalAction } from 'controllers/modal';
import {
  updateFilterAction,
  resetFilterAction,
  unsavedFilterIdsSelector,
  createFilterAction,
  saveNewFilterAction,
  changeActiveFilterAction,
  dirtyFilterIdsSelector,
} from 'controllers/filter';
import { changeLaunchDistinctAction, launchDistinctSelector } from 'controllers/launch';
import { isEmptyObject, isEmptyValue } from 'common/utils';
import { GhostButton } from 'components/buttons/ghostButton';
import { levelSelector } from 'controllers/testItem';
import { EntitiesGroup } from 'components/filterEntities/entitiesGroup';
import AddFilterIcon from 'common/img/add-filter-inline.svg';
import { FilterList } from './filterList';
import { FiltersActionBar } from './filtersActionBar';
import { ExpandToggler } from './expandToggler';
import { filterShape } from './propTypes';
import { AllLatestDropdown } from './allLatestDropdown';
import styles from './launchFiltersToolbar.scss';

const cx = classNames.bind(styles);

@connect(
  (state) => ({
    unsavedFilterIds: unsavedFilterIdsSelector(state),
    dirtyFilterIds: dirtyFilterIdsSelector(state),
    launchDistinct: launchDistinctSelector(state),
    level: levelSelector(state),
  }),
  {
    showModal: showModalAction,
    updateFilter: updateFilterAction,
    resetFilter: resetFilterAction,
    createFilter: createFilterAction,
    saveNewFilter: saveNewFilterAction,
    changeLaunchDistinct: changeLaunchDistinctAction,
    redirectToLaunches: changeActiveFilterAction,
  },
)
export class LaunchFiltersToolbar extends Component {
  static propTypes = {
    filters: PropTypes.arrayOf(filterShape),
    activeFilterId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    activeFilter: PropTypes.object,
    unsavedFilterIds: PropTypes.array,
    dirtyFilterIds: PropTypes.array,
    onSelectFilter: PropTypes.func,
    onRemoveFilter: PropTypes.func,
    onFilterAdd: PropTypes.func,
    onFilterRemove: PropTypes.func,
    onFilterValidate: PropTypes.func,
    onFilterChange: PropTypes.func,
    onChangeSorting: PropTypes.func,
    sortingString: PropTypes.string,
    filterErrors: PropTypes.object,
    filterEntities: PropTypes.array,
    showModal: PropTypes.func,
    updateFilter: PropTypes.func,
    resetFilter: PropTypes.func,
    onResetFilter: PropTypes.func,
    createFilter: PropTypes.func,
    saveNewFilter: PropTypes.func,
    redirectToLaunches: PropTypes.func,
    changeLaunchDistinct: PropTypes.func,
    launchDistinct: PropTypes.string,
    level: PropTypes.string,
    intl: intlShape.isRequired,
  };

  static defaultProps = {
    filters: [],
    activeFilterId: null,
    activeFilter: null,
    unsavedFilterIds: [],
    dirtyFilterIds: [],
    onSelectFilter: () => {},
    onRemoveFilter: () => {},
    onFilterAdd: () => {},
    onFilterRemove: () => {},
    onFilterValidate: () => {},
    onFilterChange: () => {},
    onChangeSorting: () => {},
    sortingString: '',
    filterErrors: {},
    filterEntities: [],
    showModal: () => {},
    updateFilter: () => {},
    resetFilter: () => {},
    onResetFilter: () => {},
    createFilter: () => {},
    saveNewFilter: () => {},
    redirectToLaunches: () => {},
    changeLaunchDistinct: () => {},
    launchDistinct: '',
    level: '',
  };

  state = {
    expanded: true,
  };

  handleFilterClone = () => {
    const { activeFilter, createFilter } = this.props;
    createFilter(activeFilter);
  };

  handleFilterCreate = () => {
    this.props.createFilter();
  };

  handleFilterEdit = () => {
    const { showModal, activeFilter, updateFilter } = this.props;
    showModal({
      id: 'filterEditModal',
      data: {
        filter: activeFilter,
        onEdit: updateFilter,
      },
    });
  };

  handleFilterReset = () => {
    const { activeFilter, resetFilter, onResetFilter } = this.props;
    resetFilter(activeFilter.id);
    onResetFilter();
  };

  redirectToLaunches = () => this.props.redirectToLaunches(this.props.launchDistinct);

  updateActiveFilter = () => {
    const { activeFilter, updateFilter, activeFilterId, showModal, saveNewFilter } = this.props;
    if (activeFilterId < 0) {
      showModal({
        id: 'filterEditModal',
        data: {
          creationMode: true,
          filter: activeFilter,
          onEdit: saveNewFilter,
        },
      });
    } else {
      updateFilter(activeFilter);
    }
  };
  isNoFilterValues = () => {
    const {
      activeFilter: { conditions = [] },
    } = this.props;
    return !conditions.some((filter) => !isEmptyValue(filter.value));
  };
  toggleExpand = () => this.setState({ expanded: !this.state.expanded });
  isNewFilter = () => {
    const { activeFilterId } = this.props;
    return activeFilterId < 0;
  };
  isFilterUnsaved = () => {
    const { unsavedFilterIds, activeFilterId } = this.props;
    return unsavedFilterIds.indexOf(activeFilterId) !== -1;
  };
  isFilterDirty = () => {
    const { dirtyFilterIds, activeFilterId } = this.props;
    return dirtyFilterIds.indexOf(activeFilterId) !== -1;
  };
  isSaveDisabled = () => {
    const { filterErrors } = this.props;
    return !this.isFilterUnsaved() || !isEmptyObject(filterErrors) || this.isNoFilterValues();
  };
  isDiscardDisabled = () => !this.isFilterDirty();
  isEditDisabled = () => this.isFilterUnsaved() || this.isNewFilter();
  render() {
    const {
      filters,
      activeFilterId,
      launchDistinct,
      activeFilter,
      onSelectFilter,
      onRemoveFilter,
      filterEntities,
      filterErrors,
      onFilterChange,
      onChangeSorting,
      sortingString,
      onFilterValidate,
      onFilterAdd,
      onFilterRemove,
      changeLaunchDistinct,
      unsavedFilterIds,
      level,
      intl,<commit_msg>EPMRPP-42820: React. Filters. 'Save' button becomes enabled after editing shared filter for Customer, Member, Operator<commit_after>/*
 * Copyright 2019 EPAM Systems
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { Component } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, intlShape } from 'react-intl';
import { connect } from 'react-redux';
import classNames from 'classnames/bind';
import { showModalAction } from 'controllers/modal';
import {
  updateFilterAction,
  resetFilterAction,
  unsavedFilterIdsSelector,
  createFilterAction,
  saveNewFilterAction,
  changeActiveFilterAction,
  dirtyFilterIdsSelector,
} from 'controllers/filter';
import { changeLaunchDistinctAction, launchDistinctSelector } from 'controllers/launch';
import { userIdSelector, activeProjectRoleSelector, isAdminSelector } from 'controllers/user';
import { isEmptyObject, isEmptyValue } from 'common/utils';
import { PROJECT_MANAGER } from 'common/constants/projectRoles';
import { GhostButton } from 'components/buttons/ghostButton';
import { levelSelector } from 'controllers/testItem';
import { EntitiesGroup } from 'components/filterEntities/entitiesGroup';
import AddFilterIcon from 'common/img/add-filter-inline.svg';
import { FilterList } from './filterList';
import { FiltersActionBar } from './filtersActionBar';
import { ExpandToggler } from './expandToggler';
import { filterShape } from './propTypes';
import { AllLatestDropdown } from './allLatestDropdown';
import styles from './launchFiltersToolbar.scss';

const cx = classNames.bind(styles);

@connect(
  (state) => ({
    unsavedFilterIds: unsavedFilterIdsSelector(state),
    dirtyFilterIds: dirtyFilterIdsSelector(state),
    launchDistinct: launchDistinctSelector(state),
    level: levelSelector(state),
    userId: userIdSelector(state),
    userProjectRole: activeProjectRoleSelector(state),
    isAdmin: isAdminSelector(state),
  }),
  {
    showModal: showModalAction,
    updateFilter: updateFilterAction,
    resetFilter: resetFilterAction,
    createFilter: createFilterAction,
    saveNewFilter: saveNewFilterAction,
    changeLaunchDistinct: changeLaunchDistinctAction,
    redirectToLaunches: changeActiveFilterAction,
  },
)
export class LaunchFiltersToolbar extends Component {
  static propTypes = {
    filters: PropTypes.arrayOf(filterShape),
    activeFilterId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    activeFilter: PropTypes.object,
    unsavedFilterIds: PropTypes.array,
    dirtyFilterIds: PropTypes.array,
    onSelectFilter: PropTypes.func,
    onRemoveFilter: PropTypes.func,
    onFilterAdd: PropTypes.func,
    onFilterRemove: PropTypes.func,
    onFilterValidate: PropTypes.func,
    onFilterChange: PropTypes.func,
    onChangeSorting: PropTypes.func,
    sortingString: PropTypes.string,
    filterErrors: PropTypes.object,
    filterEntities: PropTypes.array,
    showModal: PropTypes.func,
    updateFilter: PropTypes.func,
    resetFilter: PropTypes.func,
    onResetFilter: PropTypes.func,
    createFilter: PropTypes.func,
    saveNewFilter: PropTypes.func,
    redirectToLaunches: PropTypes.func,
    changeLaunchDistinct: PropTypes.func,
    launchDistinct: PropTypes.string,
    level: PropTypes.string,
    userId: PropTypes.string.isRequired,
    userProjectRole: PropTypes.string.isRequired,
    isAdmin: PropTypes.bool.isRequired,
    intl: intlShape.isRequired,
  };

  static defaultProps = {
    filters: [],
    activeFilterId: null,
    activeFilter: null,
    unsavedFilterIds: [],
    dirtyFilterIds: [],
    onSelectFilter: () => {},
    onRemoveFilter: () => {},
    onFilterAdd: () => {},
    onFilterRemove: () => {},
    onFilterValidate: () => {},
    onFilterChange: () => {},
    onChangeSorting: () => {},
    sortingString: '',
    filterErrors: {},
    filterEntities: [],
    showModal: () => {},
    updateFilter: () => {},
    resetFilter: () => {},
    onResetFilter: () => {},
    createFilter: () => {},
    saveNewFilter: () => {},
    redirectToLaunches: () => {},
    changeLaunchDistinct: () => {},
    launchDistinct: '',
    level: '',
  };

  state = {
    expanded: true,
  };

  handleFilterClone = () => {
    const { activeFilter, createFilter } = this.props;
    createFilter(activeFilter);
  };

  handleFilterCreate = () => {
    this.props.createFilter();
  };

  handleFilterEdit = () => {
    const { showModal, activeFilter, updateFilter } = this.props;
    showModal({
      id: 'filterEditModal',
      data: {
        filter: activeFilter,
        onEdit: updateFilter,
      },
    });
  };

  handleFilterReset = () => {
    const { activeFilter, resetFilter, onResetFilter } = this.props;
    resetFilter(activeFilter.id);
    onResetFilter();
  };

  redirectToLaunches = () => this.props.redirectToLaunches(this.props.launchDistinct);

  updateActiveFilter = () => {
    const { activeFilter, updateFilter, activeFilterId, showModal, saveNewFilter } = this.props;
    if (activeFilterId < 0) {
      showModal({
        id: 'filterEditModal',
        data: {
          creationMode: true,
          filter: activeFilter,
          onEdit: saveNewFilter,
        },
      });
    } else {
      updateFilter(activeFilter);
    }
  };
  isNoFilterValues = () => {
    const {
      activeFilter: { conditions = [] },
    } = this.props;
    return !conditions.some((filter) => !isEmptyValue(filter.value));
  };
  toggleExpand = () => this.setState({ expanded: !this.state.expanded });
  isNewFilter = () => {
    const { activeFilterId } = this.props;
    return activeFilterId < 0;
  };
  isFilterUnsaved = () => {
    const { unsavedFilterIds, activeFilterId } = this.props;
    return unsavedFilterIds.indexOf(activeFilterId) !== -1;
  };
  isFilterDirty = () => {
    const { dirtyFilterIds, activeFilterId } = this.props;
    return dirtyFilterIds.indexOf(activeFilterId) !== -1;
  };
  isFilterCreatorCurrentUser = () => {
    const { userId, activeFilter } = this.props;
    return activeFilter.owner === userId;
  };
  isSaveDisabled = () => {
    const { filterErrors, isAdmin, userProjectRole } = this.props;
    return (
      !this.isFilterUnsaved() ||
      !isEmptyObject(filterErrors) ||
      this.isNoFilterValues() ||
      (!this.isFilterCreatorCurrentUser() && (!isAdmin || userProjectRole !== PROJECT_MANAGER))
    );
  };
  isDiscardDisabled = () => !this.isFilterDirty();
  isEditDisabled = () => this.isFilterUnsaved() || this.isNewFilter();
  render() {
    const {
      filters,
      activeFilterId,
      launchDistinct,
      activeFilter,
      onSelectFilter,
      onRemoveFilter,
      filterEntities,
      filterErrors,
      onFilterChange,
      onChangeSorting,
      sortingString,
      onFilterValidate,
      onFilterAdd,
      onFilterRemove,
      changeLaunchDistinct,
      unsavedFilterIds,
      level,
      intl,
{'fraction_non_alphanumeric': 0.12147723198278954, 'fraction_numerical': 0.0020795984223736107, 'mean_word_length': 3.6595389241563647, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 66, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '1465506', 'n_tokens_mistral': 3973, 'n_tokens_neox': 4037, 'n_words': 869}