<commit_before>import classNames from 'classnames';
import React, {Component} from 'react';
import {Tooltip} from 'reactjs-components';

import {FormReducer as ContainerReducer} from '../../reducers/serviceForm/Container';
import {FormReducer as ContainersReducer} from '../../reducers/serviceForm/Containers';
import {findNestedPropertyInObject} from '../../../../../../src/js/utils/Util';
import AdvancedSection from '../../../../../../src/js/components/form/AdvancedSection';
import AdvancedSectionContent from '../../../../../../src/js/components/form/AdvancedSectionContent';
import AdvancedSectionLabel from '../../../../../../src/js/components/form/AdvancedSectionLabel';
import ContainerConstants from '../../constants/ContainerConstants';
import DeleteRowButton from '../../../../../../src/js/components/form/DeleteRowButton';
import FieldError from '../../../../../../src/js/components/form/FieldError';
import FieldHelp from '../../../../../../src/js/components/form/FieldHelp';
import FieldInput from '../../../../../../src/js/components/form/FieldInput';
import FieldLabel from '../../../../../../src/js/components/form/FieldLabel';
import FieldTextarea from '../../../../../../src/js/components/form/FieldTextarea';
import FormGroup from '../../../../../../src/js/components/form/FormGroup';
import FormRow from '../../../../../../src/js/components/form/FormRow';
import Icon from '../../../../../../src/js/components/Icon';
import MetadataStore from '../../../../../../src/js/stores/MetadataStore';
import PodSpec from '../../structs/PodSpec';

const {DOCKER, NONE, MESOS} = ContainerConstants.type;

const containerSettings = {
  privileged: {
    label: 'Grant Runtime Privileges',
    helpText: 'By default, containers are “unprivileged” and cannot, for example, run a Docker daemon inside a Docker container.',
    dockerOnly: 'Grant runtime privileges is only supported in Docker Runtime.'
  },
  forcePullImage: {
    label: 'Force Pull Image On Launch',
    helpText: 'Force Docker to pull the image before launching each instance.',
    dockerOnly: 'Force pull image on launch is only supported in Docker Runtime.'
  }
};

const appPaths = {
  artifacts: 'fetch',
  cmd: 'cmd',
  containerName: '',
  cpus: 'cpus',
  disk: 'disk',
  forcePullImage: '{basePath}.docker.forcePullImage',
  gpus: 'gpus',
  image: '{basePath}.docker.image',
  mem: 'mem',
  privileged: '{basePath}.docker.privileged',
  type: '{basePath}.type'
};

const podPaths = {
  artifacts: '{basePath}.artifacts',
  cmd: '{basePath}.exec.command.shell',
  containerName: '{basePath}.name',
  cpus: '{basePath}.resources.cpus',
  disk: '{basePath}.resources.disk',
  forcePullImage: '',
  gpus: '',
  image: '{basePath}.image.id',
  mem: '{basePath}.resources.mem',
  privileged: '',
  type: '{basePath}.type'
};

class ContainerServiceFormSection extends Component {
  getFieldPath(basePath, fieldName) {
    if (this.props.service instanceof PodSpec) {
      return podPaths[fieldName].replace('{basePath}', basePath);
    }

    return appPaths[fieldName].replace('{basePath}', basePath);
  }

  getArtifactsLabel() {
    const tooltipContent = (
      <span>
        {'If your service requires additional files and/or archives of files, enter their URIs to download and, if necessary, extract these resources. '}
        <a
          href="https://mesosphere.github.io/marathon/docs/application-basics.html"
          target="_blank">
          More information
        </a>.
      </span>
    );

    return (
      <FieldLabel>
        {'Artifact URI '}
        <Tooltip
          content={tooltipContent}
          interactive={true}
          maxWidth={300}
          scrollContainer=".gm-scroll-view"
          wrapText={true}>
          <Icon color="grey" id="circle-question" size="mini" />
        </Tooltip>
      </FieldLabel>
    );
  }

  getArtifactsInputs() {
    const {data, errors, path} = this.props;
    const artifactsPath = this.getFieldPath(path, 'artifacts');
    const artifacts = findNestedPropertyInObject(data, artifactsPath) || [];
    const artifactErrors = findNestedPropertyInObject(
      errors,
      artifactsPath
    ) || [];

    if (artifacts.length === 0) {
      return (
        <FormRow>
          <FormGroup className="column-10">
            {this.getArtifactsLabel()}
          </FormGroup>
        </FormRow>
      );
    }

    return artifacts.map((item, index) => {
      const error = findNestedPropertyInObject(artifactErrors, `${index}.uri`);
      let label = null;
      if (index === 0) {
        label = this.getArtifactsLabel();
      }

      return (
        <FormRow key={`${artifactsPath}.${index}`}>
          <FormGroup
            className="column-10"
            showError={Boolean(error)}>
            {label}
            <FieldInput
              name={`${artifactsPath}.${index}.uri`}
              placeholder="http://example.com"
              value={item.uri}/>
            <FieldError>{error}</FieldError>
          </FormGroup>
          <FormGroup className="flex flex-item-align-end column-2 flush-left">
            <DeleteRowButton
              onClick={this.props.onRemoveItem.bind(
                this,
                {value: index, path: artifactsPath}
              )} />
          </FormGroup>
        </FormRow>
      );
    });
  }

  getGPUSLabel() {
    const {data, path} = this.props;
    const typePath = this.getFieldPath(path, 'type');
    const disabled = findNestedPropertyInObject(data, typePath) !== MESOS;

    if (disabled) {
      return (
        <FieldLabel className="text-no-transform">
          {'GPUs '}
          <Tooltip
            content="Docker Engine does not support GPU resources, please select Universal Container Runtime if you want to use GPU resources."
            interactive={true}
            maxWidth={300}
            scrollContainer=".gm-scroll-view"
            wrapText={true}>
            <Icon color="grey" id="lock" size="mini" />
          </Tooltip>
        </FieldLabel>
      );
    }

    return (
      <FieldLabel className="text-no-transform">
        GPUs
      </FieldLabel>
    );
  }

  getGPUSField() {
    const {data, errors, path, service} = this.props;
    if (service instanceof PodSpec) {
      return null;
    }

    const typePath = this.getFieldPath(path, 'type');
    const containerType = findNestedPropertyInObject(data, typePath);
    const gpusPath = this.getFieldPath(path, 'gpus');
    const gpusErrors = findNestedPropertyInObject(errors, gpusPath);
    const gpusDisabled = containerType !== MESOS;

    return (
      <FormGroup
        className="column-4"
        showError={Boolean(!gpusDisabled && gpusErrors)}>
        {this.getGPUSLabel()}
        <FieldInput
          disabled={gpusDisabled}
          min="0"
          name={gpusPath}
          step="any"
          type="number"
          value={findNestedPropertyInObject(data, gpusPath)} />
        <FieldError>{gpusErrors}</FieldError>
      </FormGroup>
    );<commit_msg>Feature (service form): allow GPUs for Mesos runtime<commit_after>import classNames from 'classnames';
import React, {Component} from 'react';
import {Tooltip} from 'reactjs-components';

import {FormReducer as ContainerReducer} from '../../reducers/serviceForm/Container';
import {FormReducer as ContainersReducer} from '../../reducers/serviceForm/Containers';
import {findNestedPropertyInObject} from '../../../../../../src/js/utils/Util';
import AdvancedSection from '../../../../../../src/js/components/form/AdvancedSection';
import AdvancedSectionContent from '../../../../../../src/js/components/form/AdvancedSectionContent';
import AdvancedSectionLabel from '../../../../../../src/js/components/form/AdvancedSectionLabel';
import ContainerConstants from '../../constants/ContainerConstants';
import DeleteRowButton from '../../../../../../src/js/components/form/DeleteRowButton';
import FieldError from '../../../../../../src/js/components/form/FieldError';
import FieldHelp from '../../../../../../src/js/components/form/FieldHelp';
import FieldInput from '../../../../../../src/js/components/form/FieldInput';
import FieldLabel from '../../../../../../src/js/components/form/FieldLabel';
import FieldTextarea from '../../../../../../src/js/components/form/FieldTextarea';
import FormGroup from '../../../../../../src/js/components/form/FormGroup';
import FormRow from '../../../../../../src/js/components/form/FormRow';
import Icon from '../../../../../../src/js/components/Icon';
import MetadataStore from '../../../../../../src/js/stores/MetadataStore';
import PodSpec from '../../structs/PodSpec';

const {DOCKER, NONE} = ContainerConstants.type;

const containerSettings = {
  privileged: {
    label: 'Grant Runtime Privileges',
    helpText: 'By default, containers are “unprivileged” and cannot, for example, run a Docker daemon inside a Docker container.',
    dockerOnly: 'Grant runtime privileges is only supported in Docker Runtime.'
  },
  forcePullImage: {
    label: 'Force Pull Image On Launch',
    helpText: 'Force Docker to pull the image before launching each instance.',
    dockerOnly: 'Force pull image on launch is only supported in Docker Runtime.'
  }
};

const appPaths = {
  artifacts: 'fetch',
  cmd: 'cmd',
  containerName: '',
  cpus: 'cpus',
  disk: 'disk',
  forcePullImage: '{basePath}.docker.forcePullImage',
  gpus: 'gpus',
  image: '{basePath}.docker.image',
  mem: 'mem',
  privileged: '{basePath}.docker.privileged',
  type: '{basePath}.type'
};

const podPaths = {
  artifacts: '{basePath}.artifacts',
  cmd: '{basePath}.exec.command.shell',
  containerName: '{basePath}.name',
  cpus: '{basePath}.resources.cpus',
  disk: '{basePath}.resources.disk',
  forcePullImage: '',
  gpus: '',
  image: '{basePath}.image.id',
  mem: '{basePath}.resources.mem',
  privileged: '',
  type: '{basePath}.type'
};

class ContainerServiceFormSection extends Component {
  getFieldPath(basePath, fieldName) {
    if (this.props.service instanceof PodSpec) {
      return podPaths[fieldName].replace('{basePath}', basePath);
    }

    return appPaths[fieldName].replace('{basePath}', basePath);
  }

  isGpusDisabled() {
    const {data, path} = this.props;
    const typePath = this.getFieldPath(path, 'type');

    return findNestedPropertyInObject(data, typePath) === DOCKER;
  }

  getArtifactsLabel() {
    const tooltipContent = (
      <span>
        {'If your service requires additional files and/or archives of files, enter their URIs to download and, if necessary, extract these resources. '}
        <a
          href="https://mesosphere.github.io/marathon/docs/application-basics.html"
          target="_blank">
          More information
        </a>.
      </span>
    );

    return (
      <FieldLabel>
        {'Artifact URI '}
        <Tooltip
          content={tooltipContent}
          interactive={true}
          maxWidth={300}
          scrollContainer=".gm-scroll-view"
          wrapText={true}>
          <Icon color="grey" id="circle-question" size="mini" />
        </Tooltip>
      </FieldLabel>
    );
  }

  getArtifactsInputs() {
    const {data, errors, path} = this.props;
    const artifactsPath = this.getFieldPath(path, 'artifacts');
    const artifacts = findNestedPropertyInObject(data, artifactsPath) || [];
    const artifactErrors = findNestedPropertyInObject(
      errors,
      artifactsPath
    ) || [];

    if (artifacts.length === 0) {
      return (
        <FormRow>
          <FormGroup className="column-10">
            {this.getArtifactsLabel()}
          </FormGroup>
        </FormRow>
      );
    }

    return artifacts.map((item, index) => {
      const error = findNestedPropertyInObject(artifactErrors, `${index}.uri`);
      let label = null;
      if (index === 0) {
        label = this.getArtifactsLabel();
      }

      return (
        <FormRow key={`${artifactsPath}.${index}`}>
          <FormGroup
            className="column-10"
            showError={Boolean(error)}>
            {label}
            <FieldInput
              name={`${artifactsPath}.${index}.uri`}
              placeholder="http://example.com"
              value={item.uri}/>
            <FieldError>{error}</FieldError>
          </FormGroup>
          <FormGroup className="flex flex-item-align-end column-2 flush-left">
            <DeleteRowButton
              onClick={this.props.onRemoveItem.bind(
                this,
                {value: index, path: artifactsPath}
              )} />
          </FormGroup>
        </FormRow>
      );
    });
  }

  getGPUSLabel() {
    if (this.isGpusDisabled()) {
      return (
        <FieldLabel className="text-no-transform">
          {'GPUs '}
          <Tooltip
            content="Docker Engine does not support GPU resources, please select Universal Container Runtime if you want to use GPU resources."
            interactive={true}
            maxWidth={300}
            scrollContainer=".gm-scroll-view"
            wrapText={true}>
            <Icon color="grey" id="lock" size="mini" />
          </Tooltip>
        </FieldLabel>
      );
    }

    return (
      <FieldLabel className="text-no-transform">
        GPUs
      </FieldLabel>
    );
  }

  getGPUSField() {
    const {data, errors, path, service} = this.props;
    if (service instanceof PodSpec) {
      return null;
    }

    const gpusPath = this.getFieldPath(path, 'gpus');
    const gpusErrors = findNestedPropertyInObject(errors, gpusPath);
    const gpusDisabled = this.isGpusDisabled();

    return (
      <FormGroup
        className="column-4"
        showError={Boolean(!gpusDisabled && gpusErrors)}>
        {this.getGPUSLabel()}
        <FieldInput
          disabled={gpusDisabled}
          min="0"
          name={gpusPath}
          step="any"
          type="number"
          value={findNestedPropertyInObject(data, gpusPath)} />
        <FieldError>{gpusErrors}</FieldError>
      </FormGroup>
    );
{'fraction_non_alphanumeric': 0.16185759402813665, 'fraction_numerical': 0.002153316106804479, 'mean_word_length': 2.4902304609218437, 'pattern_counts': {'":': 0, '<': 73, '<?xml version=': 0, '>': 75, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1919943', 'n_tokens_mistral': 3984, 'n_tokens_neox': 3921, 'n_words': 883}