<commit_before>import * as React from 'react';
import { filter, flatten, get, groupBy, set, uniq } from 'lodash';
import { FormikErrors, FormikProps } from 'formik';
import { Observable, Subject } from 'rxjs';

import {
  Application,
  HelpField,
  IWizardPageComponent,
  spelNumberCheck,
  SpInput,
  ValidationMessage,
} from '@spinnaker/core';

import { IAmazonApplicationLoadBalancer, IAmazonNetworkLoadBalancerUpsertCommand } from 'amazon/domain';

export interface ITargetGroupsProps {
  app: Application;
  formik: FormikProps<IAmazonNetworkLoadBalancerUpsertCommand>;
  isNew: boolean;
  loadBalancer: IAmazonApplicationLoadBalancer;
}

export interface ITargetGroupsState {
  existingTargetGroupNames: { [account: string]: { [region: string]: string[] } };
  oldTargetGroupCount: number;
}

export class TargetGroups extends React.Component<ITargetGroupsProps, ITargetGroupsState>
  implements IWizardPageComponent<IAmazonNetworkLoadBalancerUpsertCommand> {
  public protocols = ['TCP'];
  public healthProtocols = ['TCP', 'HTTP', 'HTTPS'];
  public targetTypes = ['instance', 'ip'];
  private destroy$ = new Subject();

  constructor(props: ITargetGroupsProps) {
    super(props);

    const oldTargetGroupCount = !props.isNew ? props.formik.initialValues.targetGroups.length : 0;
    this.state = {
      existingTargetGroupNames: {},
      oldTargetGroupCount,
    };
  }

  public validate(
    values: IAmazonNetworkLoadBalancerUpsertCommand,
  ): FormikErrors<IAmazonNetworkLoadBalancerUpsertCommand> {
    const errors = {} as any;

    let hasErrors = false;
    const duplicateTargetGroups = uniq(
      flatten(filter(groupBy(values.targetGroups, 'name'), count => count.length > 1)).map(tg => tg.name),
    );
    const targetGroupsErrors = values.targetGroups.map((targetGroup: any) => {
      const tgErrors: { [key: string]: string } = {};

      if (
        targetGroup.name &&
        get(this.state.existingTargetGroupNames, [values.credentials, values.region], []).includes(
          targetGroup.name.toLowerCase(),
        )
      ) {
        tgErrors.name = `There is already a target group in ${values.credentials}:${values.region} with that name.`;
      }

      if (targetGroup.name && targetGroup.name.length > 32 - this.props.app.name.length) {
        tgErrors.name =
          'Target group name is automatically prefixed with the application name and cannot exceed 32 characters in length.';
      }

      if (duplicateTargetGroups.includes(targetGroup.name)) {
        tgErrors.name = 'Duplicate target group name in this load balancer.';
      }

      ['port', 'healthCheckInterval', 'healthCheckPort', 'healthyThreshold', 'unhealthyThreshold'].forEach(key => {
        const err = spelNumberCheck(targetGroup[key]);
        if (err) {
          tgErrors[key] = err;
        }
      });

      [
        'name',
        'protocol',
        'port',
        'healthCheckInterval',
        'healthCheckPort',
        'healthCheckProtocol',<commit_msg>fix(amazon/loadBalancer): Fix NLB health check port validator (#6514)<commit_after>import * as React from 'react';
import { filter, flatten, get, groupBy, set, uniq } from 'lodash';
import { FormikErrors, FormikProps } from 'formik';
import { Observable, Subject } from 'rxjs';

import {
  Application,
  HelpField,
  IWizardPageComponent,
  spelNumberCheck,
  SpInput,
  ValidationMessage,
} from '@spinnaker/core';

import { IAmazonApplicationLoadBalancer, IAmazonNetworkLoadBalancerUpsertCommand } from 'amazon/domain';

export interface ITargetGroupsProps {
  app: Application;
  formik: FormikProps<IAmazonNetworkLoadBalancerUpsertCommand>;
  isNew: boolean;
  loadBalancer: IAmazonApplicationLoadBalancer;
}

export interface ITargetGroupsState {
  existingTargetGroupNames: { [account: string]: { [region: string]: string[] } };
  oldTargetGroupCount: number;
}

export class TargetGroups extends React.Component<ITargetGroupsProps, ITargetGroupsState>
  implements IWizardPageComponent<IAmazonNetworkLoadBalancerUpsertCommand> {
  public protocols = ['TCP'];
  public healthProtocols = ['TCP', 'HTTP', 'HTTPS'];
  public targetTypes = ['instance', 'ip'];
  private destroy$ = new Subject();

  constructor(props: ITargetGroupsProps) {
    super(props);

    const oldTargetGroupCount = !props.isNew ? props.formik.initialValues.targetGroups.length : 0;
    this.state = {
      existingTargetGroupNames: {},
      oldTargetGroupCount,
    };
  }

  public validate(
    values: IAmazonNetworkLoadBalancerUpsertCommand,
  ): FormikErrors<IAmazonNetworkLoadBalancerUpsertCommand> {
    const errors = {} as any;

    let hasErrors = false;
    const duplicateTargetGroups = uniq(
      flatten(filter(groupBy(values.targetGroups, 'name'), count => count.length > 1)).map(tg => tg.name),
    );
    const targetGroupsErrors = values.targetGroups.map((targetGroup: any) => {
      const tgErrors: { [key: string]: string } = {};

      if (
        targetGroup.name &&
        get(this.state.existingTargetGroupNames, [values.credentials, values.region], []).includes(
          targetGroup.name.toLowerCase(),
        )
      ) {
        tgErrors.name = `There is already a target group in ${values.credentials}:${values.region} with that name.`;
      }

      if (targetGroup.name && targetGroup.name.length > 32 - this.props.app.name.length) {
        tgErrors.name =
          'Target group name is automatically prefixed with the application name and cannot exceed 32 characters in length.';
      }

      if (duplicateTargetGroups.includes(targetGroup.name)) {
        tgErrors.name = 'Duplicate target group name in this load balancer.';
      }

      ['port', 'healthCheckInterval', 'healthyThreshold', 'unhealthyThreshold'].forEach(key => {
        const err = spelNumberCheck(targetGroup[key]);
        if (err) {
          tgErrors[key] = err;
        }
      });

      if (targetGroup.healthCheckPort !== 'traffic-port') {
        const err = spelNumberCheck(targetGroup.healthCheckPort);
        if (err) {
          tgErrors.healthCheckPort = err;
        }
      }

      [
        'name',
        'protocol',
        'port',
        'healthCheckInterval',
        'healthCheckPort',
        'healthCheckProtocol',
{'fraction_non_alphanumeric': 0.11474883646284706, 'fraction_numerical': 0.0025678061306371367, 'mean_word_length': 3.589101620029455, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 23, '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': '5046796', 'n_tokens_mistral': 1816, 'n_tokens_neox': 1774, 'n_words': 409}