Example #1
0
 (data, settings) => {
   if (isEmpty(data)) return null;
   const { loss, extent } = data;
   const filteredByYears = loss.filter(
     d => d.year >= settings.startYear && d.year <= settings.endYear
   );
   const groupedByIso = groupBy(filteredByYears, 'iso');
   const isos = Object.keys(groupedByIso);
   const mappedData = isos.map(i => {
     const isoLoss = sumBy(groupedByIso[i], 'loss') || 0;
     const isoExtent = extent.find(e => e.iso === i).value;
     return {
       id: i,
       loss: isoLoss,
       extent: isoExtent,
       percentage: isoExtent ? 100 * isoLoss / isoExtent : 0
     };
   });
   return sortByKey(
     uniqBy(mappedData, 'id'),
     settings.unit === 'ha' ? 'loss' : 'percentage',
     true
   ).map((d, i) => ({
     ...d,
     rank: i + 1
   }));
 }
Example #2
0
normalizePost.waitForImagesToLoad = function waitForImagesToLoad( post, callback ) {
	function acceptLoadedImages( images ) {
		post.images = map( images, convertImageToObject );

		post.content_images = filter( map( post.content_images, function( image ) {
			return find( post.images, { src: image.src } );
		} ), Boolean );

		callback();
	}

	let imagesToCheck = [];

	if ( post.featured_image ) {
		imagesToCheck.push( imageForURL( post.featured_image ) );
	}

	forEach( post.content_images, function( image ) {
		imagesToCheck.push( imageForURL( image.src ) );
	} );

	// dedupe the set of images
	imagesToCheck = uniqBy( imagesToCheck, function( image ) {
		return image.src;
	} );

	if ( imagesToCheck.length === 0 ) {
		callback();
		return;
	}

	post.images = imagesToCheck;
	async.filter( post.images, keepImagesThatLoad, acceptLoadedImages );
};
Example #3
0
  mergeDuplicateOption: function(key) {
    var duplicateOptions, mergedOption, mergedAliases;
    // get duplicates to merge
    duplicateOptions = filter(this.availableOptions, { 'name': key });

    if (duplicateOptions.length > 1) {
      // TODO: warn on duplicates and overwriting
      mergedAliases = [];

      map(duplicateOptions, 'aliases').map(function(alias) {
        alias.map(function(a) {
          mergedAliases.push(a);
        });
      });

      // merge duplicate options
      mergedOption = assign.apply(null,duplicateOptions);

      // replace aliases with unique aliases
      mergedOption.aliases = uniqBy(mergedAliases, function(alias) {
        if (typeof alias === 'object') {
          return alias[Object.keys(alias)[0]];
        }
        return alias;
      });

      // remove duplicates from options
      this.availableOptions = reject(this.availableOptions, { 'name': key });
      this.availableOptions.push(mergedOption);
    }
    return this.availableOptions;
  },
function SelectStopRow(props) {
  const patternData = JSON.parse(props.patterns).sort(routeCompare);
  const patterns = [];

  patterns.push(
    <div key="first" className="route-detail-text" >
      <span className={`${patternData[0].type.toLowerCase()} vehicle-number no-padding`} >
        {patternData[0].shortName}
      </span>
      {'\u00a0'}
      <RouteDestination mode={patternData[0].type} destination={patternData[0].headsign} />
    </div>
  );

  if (patternData.length > 1) {
    const otherPatterns = reject(patternData, ['shortName', patternData[0].shortName]);
    if (otherPatterns.length > 0) {
      patterns.push(
        <div key="second" className="route-detail-text">
          <FormattedMessage id="in-addition" defaultMessage="In addition" />
          {uniqBy(otherPatterns, pattern => pattern.shortName).map(getName)}
        </div>);
    }
  }

  return (
    <div className="no-margin">
      <hr className="no-margin" />
      <div className="no-margin cursor-pointer" onClick={props.selectRow}>
        <div className="left padding-vertical-normal" style={{ width: 40 }}>
          <svg
            xmlns="http://www.w3.org/svg/2000"
            viewBox="0 0 30 30"
            width="30"
            height="30"
            style={{ position: 'relative', left: 5 }}
            className={`${props.type.toLowerCase()} left`}
          >
            <circle
              r="7"
              cx="15"
              cy="15"
              strokeWidth="6.5"
              fill="None"
              stroke="currentColor"
            />
          </svg>
        </div>
        <div className="left padding-vertical-normal" style={{ width: 'calc(100% - 40px)' }}>
          <span className="h4 no-margin link-color" >
            {props.name} ›
          </span>
          {patterns}
        </div>
        <div className="clear">
        </div>
      </div>
    </div>
  );
}
/**
 * Extract the matched courses from all children.
 * @private
 * @param {Object} expr - the current result expression
 * @param {Requirement} ctx - the host requirement
 * @returns {Course[]} - the list of matched courses
 */
export default function getMatchesFromChildren(
	expr: ModifierChildrenExpression | ModifierChildrenWhereExpression,
	ctx: Requirement,
): Course[] {
	if (expr.$type !== 'modifier') {
		return []
	}

	// grab all the child requirement names from this requirement
	let childKeys = keys(ctx).filter(isRequirementName)

	// either use all of the child requirements in the computation,
	if (expr.$children === '$all') {
		// do nothing; the default case.
	} else if (Array.isArray(expr.$children)) {
		// or just use some of them (those listed in expr.$children)
		const requested = expr.$children.map(c => c.$requirement)
		childKeys = childKeys.filter(key => requested.includes(key))
	}

	// `uniq` had the same problem here that the dirty course stuff struggles
	// with. That is, uniq works on a per-object basis, so when you write down
	// the same course for several reqs, they'll be different objects.
	// Therefore, we turn each object into a sorted JSON representation of
	// itself, and uniq based on that.
	// (I opted for passing iteratee to uniq, rather than mapping, to let lodash optimize a bit.)

	// finally, collect the matching courses from the requested children
	const matches = childKeys.map(key => collectMatches((ctx: any)[key]))
	const flatMatches = flatten(matches)
	const uniquedMatches = uniqBy(flatMatches, stringify)

	return uniquedMatches
}
Example #6
0
export const getSortedData = createSelector([getData], data => {
  if (!data || !data.length) return null;
  return sortByKey(uniqBy(data, 'iso'), 'rate', true).map((d, i) => ({
    ...d,
    rank: i + 1
  }));
});
Example #7
0
 (data, settings) => {
   if (!data || !data.length) return null;
   return sortByKey(
     uniqBy(data, 'id'),
     settings.unit === 'ha' ? 'loss' : 'percentage',
     true
   );
 }
Example #8
0
// Given a node, it will return {species:[],nm:[]} where `species` is a list
// of individuals under that node and `nm` is a list of flagged hybrids
function recursiveSearch(node, nmInstances = []) {
	if (!node.branchset) {
		return { species: [node], nm: nmInstances }
	}

	let combinations = combs(node.branchset, 2)

	let speciesList = []
	let forRemoval = []
	for (let speciesSet of combinations) {
		// if species is in speciesList: continue
		let resultsA = recursiveSearch(speciesSet[1], nmInstances)
		let speciesListA = resultsA.species

		let resultsB = recursiveSearch(speciesSet[0], nmInstances)
		let speciesListB = resultsB.species

		const speciesChecker = otherSpeciesList => species1 => {
			const otherSpeciesNames = otherSpeciesList.map(s => s.name)

			let hasName = otherSpeciesNames.includes(species1.name)
			let notAllEqual = !otherSpeciesNames.every(n => n === species1.name)

			if (hasName && notAllEqual) {
				otherSpeciesList
					.filter(species3 => species3.name === species1.name)
					.forEach(species3 => {
						const count = nmInstances.filter(sp => sp === species3).length

						if (!count) {
							nmInstances.push(species3)
							forRemoval.push(species3.ident)
						}
					})
			}
		}

		speciesListA.forEach(speciesChecker(speciesListB))
		remove(speciesListA, n => forRemoval.includes(n.ident))

		speciesListB.forEach(speciesChecker(speciesListA))
		remove(speciesListB, n => forRemoval.includes(n.ident))

		if (speciesListA.length) {
			speciesList.push(...speciesListA)
		}
		if (speciesListB.length) {
			speciesList.push(...speciesListB)
		}
	}

	speciesList = uniqBy(speciesList, 'ident')

	return { species: speciesList, nm: nmInstances }
}
Example #9
0
test('it returns POJAs of models unaffected', function(assert) {
  this.schema.wordSmiths.create({ name: 'Sam' });
  this.schema.wordSmiths.create({ name: 'Sam' });
  this.schema.wordSmiths.create({ name: 'Ganondorf' });

  let wordSmiths = this.schema.wordSmiths.all().models;
  let uniqueNames = _uniqBy(wordSmiths, 'name');
  let result = this.registry.serialize(uniqueNames);

  assert.deepEqual(result, uniqueNames);
});
test('#serialize noops on plain JS arrays', function(assert) {
  this.server.schema.users.create({ name: 'Sam' });
  this.server.schema.users.create({ name: 'Sam' });
  this.server.schema.users.create({ name: 'Ganondorf' });

  let users = this.schema.users.all().models;
  let uniqueNames = _uniqBy(users, 'name');
  let serializedResponse = this.functionHandler.serialize(uniqueNames);

  assert.deepEqual(serializedResponse, uniqueNames);
});
export function filterByQualification(
	list: Course[],
	qualification: Qualification,
	{
		distinct = false,
		fullList,
		counter,
	}: {distinct: boolean, fullList?: Course[], counter?: Counter} = {},
) {
	assertKeys(qualification, '$key', '$operator', '$value')
	const value = qualification.$value

	if (typeof value === 'object' && !Array.isArray(value)) {
		if (value.$type === 'boolean') {
			if (!('$or' in value) && !('$and' in value)) {
				throw new TypeError(
					`filterByQualification: neither $or nor $and were present in ${JSON.stringify(
						value,
					)}`,
				)
			}
		} else if (value.$type === 'function') {
			applyQualifictionFunction({value, fullList, list})
		} else {
			throw new TypeError(
				`filterByQualification: ${
					value.$type
				} is not a valid type for a query.`,
			)
		}
	}

	let filtered = filter(list, course =>
		compareCourseToQualification(course, qualification),
	)

	// If we have a limit on the number of courses, then only return the
	// number that we're allowed to accept.
	if (
		counter &&
		(counter.$operator === '$lte' || counter.$operator === '$eq')
	) {
		filtered = take(filtered, counter.$num)
	}

	if (distinct) {
		filtered = uniqBy(filtered, simplifyCourse)
	}

	return filtered
}
 processCss() {
     const combinedInput = this.state.textfieldContent + " " + this.state.cssFileContent;
     let detectedColors = getColorValues(combinedInput) || [];
     detectedColors = uniqBy(detectedColors, (detectedColor) => {
         // cf. http://stackoverflow.com/a/26306963
         return [detectedColor.red, detectedColor.green, detectedColor.blue].join(" ");
     });
     this.setState({colorPalette: detectedColors});
     try {
         localStorage.setItem('colorPalette', JSON.stringify(detectedColors));
     } catch (error) {
         return;
     }
 }
Example #13
0
  onSelectAllRows = isSelect => {
    let rowKeysCurrentPage = [];
    let rowsCurrentPage = [];
    let {
      rowKey,
      datasets,
      selection,
      getRowConf = () => {
        return { canSelect: true };
      }
    } = this.props;

    this.setSelection();

    let allRowKeys = this.selectedRowKeys;
    let allRows = this.selectedRows;

    // 找出所有canSelect为true的row
    for (let i = 0, len = datasets.length; i < len; i++) {
      let { canSelect = true } = getRowConf(datasets[i], i);
      if (canSelect) {
        rowKeysCurrentPage.push(datasets[i][rowKey]);
        rowsCurrentPage.push(datasets[i]);
      }
    }

    if (isSelect) {
      if (this.props.selection.needCrossPage) {
        allRowKeys = uniq(allRowKeys.concat(rowKeysCurrentPage));
        allRows = uniqBy(allRows.concat(rowsCurrentPage), rowKey);
      } else {
        allRowKeys = rowKeysCurrentPage;
        allRows = rowsCurrentPage;
      }
    } else {
      if (this.props.selection.needCrossPage) {
        allRowKeys = pullAll(allRowKeys, rowKeysCurrentPage);
        allRows = pullAllBy(allRows, rowsCurrentPage, rowKey);
      } else {
        allRowKeys = [];
        allRows = [];
      }
    }

    this.selectedRowKeys = allRowKeys;
    this.selectedRows = allRows;

    selection.onSelect(this.selectedRowKeys, this.selectedRows, null);
  };
Example #14
0
  /**
   * Sort the import statements by path and group them based on our heuristic
   * of style and path type.
   */
  _toGroups(): Array<Array<ImportStatement>> {
    const groups = [];

    const importsArray = Object.keys(this.imports)
      .map((key: string): ImportStatement => this.imports[key]);

    // There's a chance we have duplicate imports (can happen when switching
    // declaration_keyword for instance). By first sorting imports so that new
    // ones are first, then removing duplicates, we guarantee that we delete
    // the old ones that are now redundant.
    let result = partition(
      importsArray,
      (importStatement: ImportStatement): boolean =>
        !importStatement.isParsedAndUntouched(),
    );
    result = flattenDeep(result);

    if (this.config.get('sortImports')) {
      result = sortBy(result, (is: ImportStatement): Array<string> => is.toNormalized());
    }

    result = uniqBy(result, (is: ImportStatement): Array<string> =>
      is.toNormalized());

    if (!this.config.get('groupImports')) {
      return [result];
    }

    const packageDependencies = this.config.get('packageDependencies');
    const coreModules = this.config.get('coreModules');
    result.forEach((importStatement: ImportStatement) => {
      // Figure out what group to put this import statement in
      const groupIndex = importStatementGroupIndex(
        importStatement,
        packageDependencies,
        coreModules,
      );

      // Add the import statement to the group
      groups[groupIndex] = groups[groupIndex] || [];
      groups[groupIndex].push(importStatement);
    });

    if (groups.length) {
      groups.filter(Boolean); // compact
    }
    return groups;
  }
test('#serialize on a Collection takes an optional serializer type', function(assert) {
  this.server.schema.users.create({ name: 'Sam', tall: true, evil: false });
  this.server.schema.users.create({ name: 'Sam', tall: true, evil: false });
  this.server.schema.users.create({ name: 'Ganondorf', tall: true, evil: true });

  let users = this.schema.users.all().models;
  let uniqueNames = _uniqBy(users, 'name');
  let collection = new Collection('user', uniqueNames);
  let json = this.functionHandler.serialize(collection, 'sparse-user');

  assert.deepEqual(json, {
    users: [
      { id: '1', name: 'Sam', tall: true },
      { id: '3', name: 'Ganondorf', tall: true }
    ]
  });
});
Example #16
0
  /**
   * 根据选择的keys拼装一个选好的列
   * @param rowKeys Array 一个keys的数组
   * @return rows Array 一个每行的数据的数组
   */
  getSelectedRowsByKeys(rowKeys) {
    let rows = [];
    let self = this;
    // 之前缓存的rows和本页的总datasets整个作为搜索的区间
    let allRows = uniqBy(
      this.selectedRows.concat(this.props.datasets),
      this.props.rowKey
    );

    allRows.forEach(item => {
      if (rowKeys.indexOf(item[self.props.rowKey]) >= 0) {
        rows.push(item);
      }
    });

    return rows;
  }
Example #17
0
                grid.grid.api.core.registerColumnsProcessor((cp) => {
                    const oldCategories = grid.grid.options.categories;
                    const newCategories = uniqBy(cp.filter(notSelectionColumn).map(({colDef: cd}) => {
                        cd.categoryDisplayName = cd.categoryDisplayName || cd.displayName;
                        return {
                            name: cd.categoryDisplayName || cd.displayName,
                            enableHiding: cd.enableHiding,
                            visible: !!cd.visible
                        };
                    }), 'name');

                    if (visibilityChanged(oldCategories, newCategories)) {
                        grid.grid.options.categories = newCategories;
                        // If you don't call this, grid-column-selector won't apply calculated categories
                        grid.grid.callDataChangeCallbacks(uiGridConstants.dataChange.COLUMN);
                    }

                    return cp;
                });
Example #18
0
 Meteor.call('getMentions', {mentionSearch: search}, function (err, res) {
   if (err) {
     //
   }
   if (res) {
     let users = Meteor.users.find({ 'profile.name': { $regex: '^' + search, $options: 'i' } }).fetch()
     let suggestions = []
     users = users.concat(res)
     users.forEach(function (user) {
       suggestions.push({ id: user._id, display: user.profile.name })
     })
     let filteredPossibleSuggestions = possibleSuggestions.filter(function (suggestion) {
       return startsWith(suggestion.display, search, 0)
     })
     suggestions = uniqBy(filteredPossibleSuggestions.concat(suggestions), 'id')
     suggestions = sortBy(suggestions, 'display')
     callback(suggestions)
   }
 })
Example #19
0
const getClearableCellsForClue = (
    grid: Grid,
    clueMap: ClueMap,
    entries: Array<Clue>,
    clue: Clue
): Array<Position> => {
    if (clueIsInGroup(clue)) {
        const entriesForClue = getGroupEntriesForClue(entries, clue.group);
        return uniqBy(
            flattenDeep(
                entriesForClue.map(entry =>
                    getClearableCellsForEntry(grid, clueMap, entries, entry)
                )
            ),
            cell => [cell.x, cell.y].join()
        );
    }
    return getClearableCellsForEntry(grid, clueMap, entries, clue);
};
Example #20
0
    .then((data) => {
        const dataKeys = Object.keys(data);
        const missingData = dataKeys.filter((key) => !data[key]);

        if (missingData.length) {
            if (missingData.length === dataKeys.length) {
                log.info(logPrefix, `The GitHub repository ${repository} no longer exists, is invalid or blocked`);
            } else {
                log.info(logPrefix, `It seems that the GitHub repository ${repository} is empty`);
            }

            return null;
        }

        return deepCompact({
            homepage: data.info.homepage,
            forkOf: (data.info.fork && data.info.parent && data.info.parent.full_name) || null,

            starsCount: data.info.stargazers_count,
            forksCount: data.info.forks_count,
            subscribersCount: data.info.subscribers_count,

            issues: Object.assign(data.issueStats, { isDisabled: !data.info.has_issues }),

            // Contributors (top 100)
            contributors: data.contributors
            .map((contributor) => {
                const author = contributor.author;

                // Empty entries will be stripped by deepCompact
                return author && { username: contributor.author.login, commitsCount: contributor.total };
            })
            .reverse(),

            // Commit activity
            commits: extractCommits(data.commitActivity),

            // Statuses
            statuses: uniqBy(data.statuses, (status) => status.context)
            .map((status) => pick(status, 'context', 'state')),
        });
    })
function authorcount (papers) {
  const authors = uniqBy(papers, 'key').map(paper => {
    const author = paper.author

    if (!author) return null

    if (isString(author)) {
      return author.split(',').map((a) => a.trim())
    } else {
      return author.map((a) => {
        return `${a['given-names'].slice(0, 1)} ${a.surname}`
      })
    }
  })

  const counts = countBy(flatten(authors.filter(nonull)))

  return sortBy(toPairs(counts), 1)
    .reverse()
    .map((pair) => {
      return { author: pair[0], count: pair[1] }
    })
}
Example #22
0
	wpcom.undocumented().saveSharingButtons( siteId, buttons, function( error, data ) {
		if ( error || ! data.updated ) {
			debug( 'error saving SharingButtonsList to api', error );
			this.saving = false;
			callback( error );
			return;
		}

		// 1. Original form response and current data
		//   - [ 1Y, 2N, 3Y ] [ 1N, 2Y, 3N, 4N, 5N ]
		// 2. Sort response data with enabled (Y) first
		//   - [ 1Y, 3Y, 2N ] [ 1N, 2Y, 3N, 4N, 5N ]
		// 3. Concatenate the two together
		//   - [ 1Y, 3Y, 2N, 1N, 2Y, 3N, 4N, 5N ]
		// 4. Only take the first value of each ID (#) encountered
		//   - [ 1Y, 3Y, 2N, 4N, 5N ]

		data.updated = orderBy( data.updated, 'enabled', 'desc' );
		this.data = uniqBy( data.updated.concat( this.data ), 'ID' );
		this.emit( 'change' );
		this.saving = false;
		callback( null );
	}.bind( this ) );
Example #23
0
      Promise.all(fetches).then((queryResponses) => {
        const allQueries = [];
        queryResponses.forEach((queryResponse) => {
          const result = showQueriesParser(queryResponse.data);
          if (result.errors.length) {
            result.erorrs.forEach((message) => this.props.addFlashMessage({type: 'error', text: message}));
          }

          allQueries.push(...result.queries);
        });

        const queries = uniqBy(flatten(allQueries), (q) => q.id);

        // sorting queries by magnitude, so generally longer queries will appear atop the list
        const sortedQueries = queries.sort((a, b) => {
          const aTime = times.find((t) => a.duration.match(t.test));
          const bTime = times.find((t) => b.duration.match(t.test));
          return +aTime.magnitude <= +bTime.magnitude;
        });
        this.setState({
          queries: sortedQueries,
        });
      });
Example #24
0
    _fireEventsToAnalytics(event, source) {
        const self = this;
        const { experience = {}, uniqBy, isUndefined } = this;
        const { config = {} } = experience;
        const { metadata = {} } = config;
        const { trackers = [], sendIVXEventsToAnalytics = [] } = metadata;
        const matchingTrackers = sendIVXEventsToAnalytics.reduce((currentMatchingTrackers, analyticMatching) => {
            const { type, id, trackingId, name } = analyticMatching;
            let matchedTrackersByProp = [];

            if (!isUndefined(type)) matchedTrackersByProp = trackers.filter(tracker => tracker.type === type);
            if (!isUndefined(id)) matchedTrackersByProp = trackers.filter(tracker => tracker.id === id);
            if (!isUndefined(trackingId)) matchedTrackersByProp = trackers.filter(tracker => tracker.trackingId === trackingId);
            if (!isUndefined(name)) matchedTrackersByProp = trackers.filter(tracker => tracker.name === name);

            return [
                ...matchedTrackersByProp,
                ...currentMatchingTrackers
            ]
        }, []);
        const runTrackers = uniqBy(matchingTrackers, 'id');
        const actions = runTrackers.map(currentRunTracker => {
            const { id: tracker } = currentRunTracker;
            const args = {
                tracker,
                event
            };

            return {
                eventName: "sendAnalyticsEvent",
                args
            }
        });

        return this.experience.processor.resolveActions(actions, () => { }, source);
    }
Example #25
0
    _this.beforeUpload = function (file, fileList) {
      if (!_this.props.beforeUpload) {
        return true;
      }

      var result = _this.props.beforeUpload(file, fileList);

      if (result === false) {
        _this.onChange({
          file: file,
          fileList: uniqBy(_this.state.fileList.concat(fileList.map(fileToObject)), function (item) {
            return item.uid;
          })
        });

        return false;
      }

      if (result && result.then) {
        return result;
      }

      return true;
    };
Example #26
0
function _mapContentSet(contentSet) {
  return uniqBy(contentSet, 'content_id').map(contentState);
}
Example #27
0
/**
 * _.pullAllBy
 */
pullAllBy([{ x: 1 }, { x: 2 }, { x: 3 }, { x: 1 }], [{ x: 1 }, { x: 3 }], "x");

/**
 * _.unionBy
 */
unionBy([2.1], [1.2, 2.3], Math.floor);
unionBy([{ x: 1 }], [{ x: 2 }, { x: 1 }], "x");

/**
 * _.uniqBy
 */
uniqBy([2.1, 1.2, 2.3], Math.floor);
uniqBy([{ x: 1 }, { x: 2 }, { x: 1 }], "x");

/**
 * _.clone
 */
clone({ a: 1 }).a == 1;
// $ExpectError property `b`. Property not found in object literal
clone({ a: 1 }).b == 1;
// $ExpectError number. This type is incompatible with function type.
clone({ a: 1 }).a == "c";

/**
 * _.isEqual
 */
isEqual("a", "b");
Example #28
0
const searchEmojisByAll = (term) => {
    const filteredEmojis = flatten(map([searchEmojisByNamePrefix, searchEmojisByKeywordPrefix, searchEmojisByCategoryPrefix], (fn) => fn(term)))
    return uniqBy(filteredEmojis, (e) => e.char)

}
Example #29
0
  render () {
    const {
        qualityGate,
        conditions,
        metrics,
        periods,
        edit,
        onAddCondition,
        onSaveCondition,
        onDeleteCondition
    } = this.props;

    const sortedConditions = _.sortBy(conditions, condition => {
      return metrics.find(metric => metric.key === condition.metric).name;
    });

    const duplicates = [];
    const savedConditions = conditions.filter(condition => condition.id != null);
    savedConditions.forEach(condition => {
      const sameCount = savedConditions
          .filter(sample => sample.metric === condition.metric && sample.period === condition.period)
          .length;
      if (sameCount > 1) {
        duplicates.push(condition);
      }
    });

    const uniqDuplicates = uniqBy(duplicates, d => d.metric)
        .map(condition => {
          const metric = metrics.find(metric => metric.key === condition.metric);
          return { ...condition, metric };
        });

    return (
        <div id="quality-gate-conditions" className="quality-gate-section">
          <h3 className="spacer-bottom">
            {translate('quality_gates.conditions')}
          </h3>

          <ConditionsAlert/>

          {this.state.error && (
              <div className="alert alert-danger">
                {this.state.error}
              </div>
          )}

          {uniqDuplicates.length > 0 && (
              <div className="alert alert-warning">
                <p>{translate('quality_gates.duplicated_conditions')}</p>
                <ul className="list-styled spacer-top">
                  {uniqDuplicates.map(d => (
                      <li>{getLocalizedMetricName(d.metric)}</li>
                  ))}
                </ul>
              </div>
          )}

          {sortedConditions.length ? (
              <table id="quality-gate-conditions" className="data zebra zebra-hover">
                <thead>
                <tr>
                  <th className="nowrap">
                    {translate('quality_gates.conditions.metric')}
                  </th>
                  <th className="thin nowrap">
                    {translate('quality_gates.conditions.leak')}
                  </th>
                  <th className="thin nowrap">
                    {translate('quality_gates.conditions.operator')}
                  </th>
                  <th className="thin nowrap">
                    {translate('quality_gates.conditions.warning')}
                  </th>
                  <th className="thin nowrap">
                    {translate('quality_gates.conditions.error')}
                  </th>
                  {edit && <th></th>}
                </tr>
                </thead>
                <tbody>
                {sortedConditions.map((condition, index) => (
                    <Condition
                        key={getKey(condition, index)}
                        qualityGate={qualityGate}
                        condition={condition}
                        metrics={metrics}
                        periods={periods}
                        edit={edit}
                        onSaveCondition={onSaveCondition}
                        onDeleteCondition={onDeleteCondition}
                        onError={this.handleError.bind(this)}
                        onResetError={this.handleResetError.bind(this)}/>
                ))}
                </tbody>
              </table>
          ) : (
              <div className="big-spacer-top">
                {translate('quality_gates.no_conditions')}
              </div>
          )}

          {edit && (
              <AddConditionForm metrics={metrics} onSelect={onAddCondition}/>
          )}
        </div>
    );
  }
/**
 * Removes duplicate marks from an array
 *
 * @param {Array} marks The marks to remove duplications from
 * @returns {Array} A list of de-duplicated marks.
 */
function removeDuplicateMarks( marks ) {
	return uniqBy( marks, function( mark ) {
		return mark.getOriginal();
	} );
}