<commit_before>import _ from 'intl'
import BaseComponent from 'base-component'
import Copiable from 'copiable'
import Icon from 'icon'
import Link from 'link'
import { NavLink, NavTabs } from 'nav'
import Page from '../page'
import React, { cloneElement } from 'react'
import VmActionBar from './action-bar'
import { Select, Text } from 'editable'
import { assign, isEmpty, map, pick } from 'lodash'
import { editVm, fetchVmStats, isVmRunning, migrateVm } from 'xo'
import { Container, Row, Col } from 'grid'
import { connectStore, routes } from 'utils'
import {
  createGetObject,
  createGetObjectsOfType,
  createGetVmDisks,
  createSelector,
  createSumBy,
  getCheckPermissions,
  isAdmin,
} from 'selectors'

import TabGeneral from './tab-general'
import TabStats from './tab-stats'
import TabConsole from './tab-console'
import TabContainers from './tab-containers'
import TabDisks from './tab-disks'
import TabNetwork from './tab-network'
import TabSnapshots from './tab-snapshots'
import TabLogs from './tab-logs'
import TabAdvanced from './tab-advanced'

// ===================================================================

@routes('general', {
  advanced: TabAdvanced,
  console: TabConsole,
  containers: TabContainers,
  disks: TabDisks,
  general: TabGeneral,
  logs: TabLogs,
  network: TabNetwork,
  snapshots: TabSnapshots,
  stats: TabStats,
})
@connectStore(() => {
  const getVm = createGetObject()

  const getContainer = createGetObject(
    (state, props) => getVm(state, props).$container
  )

  const getPool = createGetObject((state, props) => getVm(state, props).$pool)

  const getVbds = createGetObjectsOfType('VBD')
    .pick((state, props) => getVm(state, props).$VBDs)
    .sort()
  const getVdis = createGetVmDisks(getVm)
  const getSrs = createGetObjectsOfType('SR').pick(
    createSelector(getVdis, vdis => map(vdis, '$SR'))
  )

  const getVmTotalDiskSpace = createSumBy(createGetVmDisks(getVm), 'size')

  const getHosts = createGetObjectsOfType('host')

  return (state, props) => {
    const vm = getVm(state, props)
    if (!vm) {
      return {}
    }

    return {
      checkPermissions: getCheckPermissions(state, props),
      container: getContainer(state, props),
      hosts: getHosts(state, props),
      isAdmin: isAdmin(state, props),
      pool: getPool(state, props),
      srs: getSrs(state, props),
      vbds: getVbds(state, props),
      vdis: getVdis(state, props),
      vm,
      vmTotalDiskSpace: getVmTotalDiskSpace(state, props),
    }
  }
})
export default class Vm extends BaseComponent {
  static contextTypes = {
    router: React.PropTypes.object,
  }

  loop (vm = this.props.vm) {
    if (this.cancel) {
      this.cancel()
    }

    if (!isVmRunning(vm)) {
      return
    }

    let cancelled = false
    this.cancel = () => {
      cancelled = true
    }

    fetchVmStats(vm).then(stats => {
      if (cancelled) {
        return
      }
      this.cancel = null

      clearTimeout(this.timeout)
      this.setState(
        {
          statsOverview: stats,
        },
        () => {
          this.timeout = setTimeout(this.loop, stats.interval * 1000)
        }
      )
    })
  }
  loop = ::this.loop

  componentWillMount () {
    this.loop()
  }

  componentWillUnmount () {
    clearTimeout(this.timeout)
  }

  componentWillReceiveProps (props) {
    const vmCur = this.props.vm
    const vmNext = props.vm

    if (vmCur && !vmNext) {
      this.context.router.push('/')
    }

    if (!isVmRunning(vmCur) && isVmRunning(vmNext)) {
      this.loop(vmNext)
    } else if (isVmRunning(vmCur) && !isVmRunning(vmNext)) {
      this.setState({
        statsOverview: undefined,
      })
    }
  }

  _getCanSnapshot = createSelector(
    () => this.props.checkPermissions,
    () => this.props.vm,
    () => this.props.srs,
    (checkPermissions, vm, srs) =>
      checkPermissions([
        [vm.id, 'administrate'],
        ...map(srs, sr => [sr.id, 'operate']),
      ])
  )

  _setNameDescription = nameDescription =>
    editVm(this.props.vm, { name_description: nameDescription })
  _setNameLabel = nameLabel => editVm(this.props.vm, { name_label: nameLabel })
  _migrateVm = host => migrateVm(this.props.vm, host)

  _selectOptionRenderer = option => option.name_label

  header () {
    const { vm, container, pool, hosts } = this.props
    if (!vm) {
      return <Icon icon='loading' />
    }
    return (
      <Container>
        <Row>
          <Col mediumSize={6} className='header-title'>
            <Copiable tagName='div'>
              <h2 style={{ display: 'inline' }}>
                {isEmpty(vm.current_operations) ? (
                  <Icon icon={`vm-${vm.power_state.toLowerCase()}`} />
                ) : (
                  <Icon icon='vm-busy' />
                )}{' '}
                <Text value={vm.name_label} onChange={this._setNameLabel} />
              </h2>{' '}
              (<strong>{_('uuid')}</strong>: {vm.uuid})
            </Copiable>
            <span>
              <Text
                value={vm.name_description}<commit_msg>fix(xo-web/VM): missing data prop on Copiable (#3282)<commit_after>import _ from 'intl'
import BaseComponent from 'base-component'
import Copiable from 'copiable'
import Icon from 'icon'
import Link from 'link'
import { NavLink, NavTabs } from 'nav'
import Page from '../page'
import React, { cloneElement } from 'react'
import VmActionBar from './action-bar'
import { Select, Text } from 'editable'
import { assign, isEmpty, map, pick } from 'lodash'
import { editVm, fetchVmStats, isVmRunning, migrateVm } from 'xo'
import { Container, Row, Col } from 'grid'
import { connectStore, routes } from 'utils'
import {
  createGetObject,
  createGetObjectsOfType,
  createGetVmDisks,
  createSelector,
  createSumBy,
  getCheckPermissions,
  isAdmin,
} from 'selectors'

import TabGeneral from './tab-general'
import TabStats from './tab-stats'
import TabConsole from './tab-console'
import TabContainers from './tab-containers'
import TabDisks from './tab-disks'
import TabNetwork from './tab-network'
import TabSnapshots from './tab-snapshots'
import TabLogs from './tab-logs'
import TabAdvanced from './tab-advanced'

// ===================================================================

@routes('general', {
  advanced: TabAdvanced,
  console: TabConsole,
  containers: TabContainers,
  disks: TabDisks,
  general: TabGeneral,
  logs: TabLogs,
  network: TabNetwork,
  snapshots: TabSnapshots,
  stats: TabStats,
})
@connectStore(() => {
  const getVm = createGetObject()

  const getContainer = createGetObject(
    (state, props) => getVm(state, props).$container
  )

  const getPool = createGetObject((state, props) => getVm(state, props).$pool)

  const getVbds = createGetObjectsOfType('VBD')
    .pick((state, props) => getVm(state, props).$VBDs)
    .sort()
  const getVdis = createGetVmDisks(getVm)
  const getSrs = createGetObjectsOfType('SR').pick(
    createSelector(getVdis, vdis => map(vdis, '$SR'))
  )

  const getVmTotalDiskSpace = createSumBy(createGetVmDisks(getVm), 'size')

  const getHosts = createGetObjectsOfType('host')

  return (state, props) => {
    const vm = getVm(state, props)
    if (!vm) {
      return {}
    }

    return {
      checkPermissions: getCheckPermissions(state, props),
      container: getContainer(state, props),
      hosts: getHosts(state, props),
      isAdmin: isAdmin(state, props),
      pool: getPool(state, props),
      srs: getSrs(state, props),
      vbds: getVbds(state, props),
      vdis: getVdis(state, props),
      vm,
      vmTotalDiskSpace: getVmTotalDiskSpace(state, props),
    }
  }
})
export default class Vm extends BaseComponent {
  static contextTypes = {
    router: React.PropTypes.object,
  }

  loop (vm = this.props.vm) {
    if (this.cancel) {
      this.cancel()
    }

    if (!isVmRunning(vm)) {
      return
    }

    let cancelled = false
    this.cancel = () => {
      cancelled = true
    }

    fetchVmStats(vm).then(stats => {
      if (cancelled) {
        return
      }
      this.cancel = null

      clearTimeout(this.timeout)
      this.setState(
        {
          statsOverview: stats,
        },
        () => {
          this.timeout = setTimeout(this.loop, stats.interval * 1000)
        }
      )
    })
  }
  loop = ::this.loop

  componentWillMount () {
    this.loop()
  }

  componentWillUnmount () {
    clearTimeout(this.timeout)
  }

  componentWillReceiveProps (props) {
    const vmCur = this.props.vm
    const vmNext = props.vm

    if (vmCur && !vmNext) {
      this.context.router.push('/')
    }

    if (!isVmRunning(vmCur) && isVmRunning(vmNext)) {
      this.loop(vmNext)
    } else if (isVmRunning(vmCur) && !isVmRunning(vmNext)) {
      this.setState({
        statsOverview: undefined,
      })
    }
  }

  _getCanSnapshot = createSelector(
    () => this.props.checkPermissions,
    () => this.props.vm,
    () => this.props.srs,
    (checkPermissions, vm, srs) =>
      checkPermissions([
        [vm.id, 'administrate'],
        ...map(srs, sr => [sr.id, 'operate']),
      ])
  )

  _setNameDescription = nameDescription =>
    editVm(this.props.vm, { name_description: nameDescription })
  _setNameLabel = nameLabel => editVm(this.props.vm, { name_label: nameLabel })
  _migrateVm = host => migrateVm(this.props.vm, host)

  _selectOptionRenderer = option => option.name_label

  header () {
    const { vm, container, pool, hosts } = this.props
    if (!vm) {
      return <Icon icon='loading' />
    }
    return (
      <Container>
        <Row>
          <Col mediumSize={6} className='header-title'>
            <Copiable tagName='div' data={vm.uuid}>
              <h2 style={{ display: 'inline' }}>
                {isEmpty(vm.current_operations) ? (
                  <Icon icon={`vm-${vm.power_state.toLowerCase()}`} />
                ) : (
                  <Icon icon='vm-busy' />
                )}{' '}
                <Text value={vm.name_label} onChange={this._setNameLabel} />
              </h2>{' '}
              (<strong>{_('uuid')}</strong>: {vm.uuid})
            </Copiable>
            <span>
              <Text
                value={vm.name_description}
{'fraction_non_alphanumeric': 0.14893407996856273, 'fraction_numerical': 0.0017683465959328027, 'mean_word_length': 2.777365491651206, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 67, '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': '3504486', 'n_tokens_mistral': 3318, 'n_tokens_neox': 3248, 'n_words': 710}