<commit_before>import * as React from 'react';
import { defaultsDeep, set } from 'lodash';

import {
  AccountTag,
  IStageConfigProps,
  NgReact,
  RegionSelectField,
  StageConfigField,
  HelpField,
  IAggregatedAccounts,
  IRegion,
  AccountService,
  FirewallLabels,
  MapEditor,
} from '@spinnaker/core';

import { DockerImageAndTagSelector, IDockerImageAndTagChanges } from '@spinnaker/docker';

import { TitusSecurityGroupPicker } from './TitusSecurityGroupPicker';

export interface ITitusRunJobStageConfigState {
  credentials: string[];
  regions: IRegion[];
  loaded: boolean;
}

export class TitusRunJobStageConfig extends React.Component<IStageConfigProps, ITitusRunJobStageConfigState> {
  private credentialsKeyedByAccount: IAggregatedAccounts = {};

  public state: ITitusRunJobStageConfigState = {
    credentials: [],
    regions: [],
    loaded: false,
  };

  public constructor(props: IStageConfigProps) {
    super(props);
    const { application, stage } = props;
    stage.cluster = stage.cluster || {};
    stage.waitForCompletion = stage.waitForCompletion === undefined ? true : stage.waitForCompletion;

    if (stage.cluster.imageId) {
      Object.assign(stage, this.splitImageId(stage.cluster.imageId));
    }

    if (!stage.credentials && application.defaultCredentials.titus) {
      stage.credentials = application.defaultCredentials.titus;
    }

    if (!stage.cluster.capacity) {
      stage.cluster.capacity = {
        min: 1,
        max: 1,
        desired: 1,
      };
    }

    const clusterDefaults = {
      application: application.name,
      env: {},
      resources: {
        cpu: 1,
        disk: 10000,
        gpu: 0,
        memory: 512,
        networkMbps: 128,
      },
      retries: 0,
      runtimeLimitSecs: 3600,
      securityGroups: [] as string[],
    };
    defaultsDeep(stage.cluster, clusterDefaults);

    stage.cloudProvider = stage.cloudProvider || 'titus';
    stage.deferredInitialization = true;
  }

  private setRegistry(account: string) {
    if (account) {
      this.props.stage.registry = this.credentialsKeyedByAccount[account].registry;
    }
  }

  private updateRegions(account: string) {
    let regions: IRegion[];
    if (account) {
      regions = this.credentialsKeyedByAccount[account].regions;
      if (regions.map(r => r.name).every(r => r !== this.props.stage.cluster.region)) {
        delete this.props.stage.cluster.region;
        this.props.stageFieldUpdated();
      }
    } else {
      regions = [];
    }
    this.setState({ regions });
  }

  private accountChanged = (account: string) => {
    this.stageFieldChanged('credentials', account);
    this.setRegistry(account);
    this.updateRegions(account);
  };

  private updateImageId() {
    const { stage } = this.props;
    if (stage.repository && stage.tag) {
      stage.cluster.imageId = `${stage.repository}:${stage.tag}`;
    } else {
      delete stage.cluster.imageId;
    }
  }

  private dockerChanged = (changes: IDockerImageAndTagChanges) => {
    // Temporary until stage config section is no longer angular
    Object.assign(this.props.stage, changes);
    this.updateImageId();
    this.props.stageFieldUpdated();
    this.forceUpdate();
  };

  private stageFieldChanged = (fieldIndex: string, value: any) => {
    set(this.props.stage, fieldIndex, value);
    this.props.stageFieldUpdated();
    this.forceUpdate();
  };

  // Split the image id up into the selectable parts to feed the UI
  private splitImageId(image: string): { organization: string; repository: string; tag: string } {
    const parts = image.split('/');
    const organization = parts.length > 1 ? parts.shift() : '';
    const rest = parts.shift().split(':');
    const repository = organization.length > 0 ? `${organization}/${rest.shift()}` : rest.shift();
    const tag = rest.shift();

    return { organization, repository, tag };
  }

  public componentDidMount() {
    const { stage } = this.props;
    AccountService.getCredentialsKeyedByAccount('titus').then(credentialsKeyedByAccount => {
      this.credentialsKeyedByAccount = credentialsKeyedByAccount;
      const credentials = Object.keys(credentialsKeyedByAccount);
      stage.credentials = stage.credentials || credentials[0];

      this.setRegistry(stage.credentials);
      this.updateRegions(stage.credentials);
      this.setState({ credentials, loaded: true });
    });
  }

  private mapChanged = (key: string, values: { [key: string]: string }) => {
    this.stageFieldChanged(key, values);
  };

  private groupsChanged = (groups: string[]) => {
    this.stageFieldChanged('cluster.securityGroups', groups);
    this.forceUpdate();
  };

  public render() {
    const { stage } = this.props;
    const { credentials, loaded, regions } = this.state;
    const { AccountSelectField } = NgReact;
    const awsAccount = (this.credentialsKeyedByAccount[stage.credentials] || { awsAccount: '' }).awsAccount;

    return (
      <div className="form-horizontal">
        <div className="form-group">
          <label className="col-md-3 sm-label-right">
            <span className="label-text">Account</span>
          </label>
          <div className="col-md-5">
            <AccountSelectField
              component={stage}
              field="credentials"
              accounts={credentials}
              onChange={this.accountChanged}
              provider="titus"
            />
            {stage.credentials !== undefined && (
              <div className="small">
                Uses resources from the Amazon account <AccountTag account={awsAccount} />
              </div>
            )}
          </div>
        </div>

        <RegionSelectField<commit_msg>fix(titus/runJob): Fix account selector from incorrectly changing account<commit_after>import * as React from 'react';
import { defaultsDeep, set } from 'lodash';

import {
  AccountTag,
  IStageConfigProps,
  RegionSelectField,
  StageConfigField,
  HelpField,
  IAggregatedAccounts,
  IRegion,
  AccountService,
  FirewallLabels,
  MapEditor,
  AccountSelectField,
} from '@spinnaker/core';

import { DockerImageAndTagSelector, IDockerImageAndTagChanges } from '@spinnaker/docker';

import { TitusSecurityGroupPicker } from './TitusSecurityGroupPicker';

export interface ITitusRunJobStageConfigState {
  credentials: string[];
  regions: IRegion[];
  loaded: boolean;
}

export class TitusRunJobStageConfig extends React.Component<IStageConfigProps, ITitusRunJobStageConfigState> {
  private credentialsKeyedByAccount: IAggregatedAccounts = {};

  public state: ITitusRunJobStageConfigState = {
    credentials: [],
    regions: [],
    loaded: false,
  };

  public constructor(props: IStageConfigProps) {
    super(props);
    const { application, stage } = props;
    stage.cluster = stage.cluster || {};
    stage.waitForCompletion = stage.waitForCompletion === undefined ? true : stage.waitForCompletion;

    if (stage.cluster.imageId) {
      Object.assign(stage, this.splitImageId(stage.cluster.imageId));
    }

    if (!stage.credentials && application.defaultCredentials.titus) {
      stage.credentials = application.defaultCredentials.titus;
    }

    if (!stage.cluster.capacity) {
      stage.cluster.capacity = {
        min: 1,
        max: 1,
        desired: 1,
      };
    }

    const clusterDefaults = {
      application: application.name,
      env: {},
      resources: {
        cpu: 1,
        disk: 10000,
        gpu: 0,
        memory: 512,
        networkMbps: 128,
      },
      retries: 0,
      runtimeLimitSecs: 3600,
      securityGroups: [] as string[],
    };
    defaultsDeep(stage.cluster, clusterDefaults);

    stage.cloudProvider = stage.cloudProvider || 'titus';
    stage.deferredInitialization = true;
  }

  private setRegistry(account: string) {
    if (account) {
      this.props.stage.registry = this.credentialsKeyedByAccount[account].registry;
    }
  }

  private updateRegions(account: string) {
    let regions: IRegion[];
    if (account) {
      regions = this.credentialsKeyedByAccount[account].regions;
      if (regions.map(r => r.name).every(r => r !== this.props.stage.cluster.region)) {
        delete this.props.stage.cluster.region;
        this.props.stageFieldUpdated();
      }
    } else {
      regions = [];
    }
    this.setState({ regions });
  }

  private accountChanged = (account: string) => {
    this.stageFieldChanged('credentials', account);
    this.setRegistry(account);
    this.updateRegions(account);
  };

  private updateImageId() {
    const { stage } = this.props;
    if (stage.repository && stage.tag) {
      stage.cluster.imageId = `${stage.repository}:${stage.tag}`;
    } else {
      delete stage.cluster.imageId;
    }
  }

  private dockerChanged = (changes: IDockerImageAndTagChanges) => {
    // Temporary until stage config section is no longer angular
    Object.assign(this.props.stage, changes);
    this.updateImageId();
    this.props.stageFieldUpdated();
    this.forceUpdate();
  };

  private stageFieldChanged = (fieldIndex: string, value: any) => {
    set(this.props.stage, fieldIndex, value);
    this.props.stageFieldUpdated();
    this.forceUpdate();
  };

  // Split the image id up into the selectable parts to feed the UI
  private splitImageId(image: string): { organization: string; repository: string; tag: string } {
    const parts = image.split('/');
    const organization = parts.length > 1 ? parts.shift() : '';
    const rest = parts.shift().split(':');
    const repository = organization.length > 0 ? `${organization}/${rest.shift()}` : rest.shift();
    const tag = rest.shift();

    return { organization, repository, tag };
  }

  public componentDidMount() {
    const { stage } = this.props;
    AccountService.getCredentialsKeyedByAccount('titus').then(credentialsKeyedByAccount => {
      this.credentialsKeyedByAccount = credentialsKeyedByAccount;
      const credentials = Object.keys(credentialsKeyedByAccount);
      stage.credentials = stage.credentials || credentials[0];

      this.setRegistry(stage.credentials);
      this.updateRegions(stage.credentials);
      this.setState({ credentials, loaded: true });
    });
  }

  private mapChanged = (key: string, values: { [key: string]: string }) => {
    this.stageFieldChanged(key, values);
  };

  private groupsChanged = (groups: string[]) => {
    this.stageFieldChanged('cluster.securityGroups', groups);
    this.forceUpdate();
  };

  public render() {
    const { stage } = this.props;
    const { credentials, loaded, regions } = this.state;
    const awsAccount = (this.credentialsKeyedByAccount[stage.credentials] || { awsAccount: '' }).awsAccount;

    return (
      <div className="form-horizontal">
        <div className="form-group">
          <label className="col-md-3 sm-label-right">
            <span className="label-text">Account</span>
          </label>
          <div className="col-md-5">
            <AccountSelectField
              component={stage}
              field="credentials"
              accounts={credentials}
              onChange={this.accountChanged}
              provider="titus"
            />
            {stage.credentials !== undefined && (
              <div className="small">
                Uses resources from the Amazon account <AccountTag account={awsAccount} />
              </div>
            )}
          </div>
        </div>

        <RegionSelectField
{'fraction_non_alphanumeric': 0.12577734956643602, 'fraction_numerical': 0.004554611544188491, 'mean_word_length': 2.9964998249912496, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 51, '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': '1222439', 'n_tokens_mistral': 3301, 'n_tokens_neox': 3224, 'n_words': 675}