<commit_before>import React from 'react'
import PropTypes from 'prop-types'

import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'

import style from './style.css'
import { withMsg } from '_/intl'
import { RouterPropTypeShapes } from '_/propTypeShapes'

import {
  canRestart,
  canShutdown,
  canStart,
  canConsole,
  canSuspend,
  canRemove,
  canExternalService,
} from '../../vm-status'

import {
  shutdownVm,
  restartVm,
  suspendVm,
  startPool,
  startVm,
  removeVm,
  getRDP,
} from '_/actions'

import { isWindows } from '_/helpers'

import { SplitButton, Icon, Checkbox, DropdownKebab } from 'patternfly-react'
import ConfirmationModal from './ConfirmationModal'
import ConsoleConfirmationModal from './ConsoleConfirmationModal'
import Action, { ActionButtonWraper, MenuItemAction, ActionMenuItemWrapper } from './Action'
import { VNC, RDP, BROWSER_VNC, NATIVE } from '_/constants/console'
import { toUiConsole } from '_/utils'

const EmptyAction = ({ state, isOnCard }) => {
  if (!canConsole(state) && !canShutdown(state) && !canRestart(state) && !canStart(state)) {
    return (
      <div className={isOnCard ? 'card-pf-item' : undefined} />
    )
  }
  return null
}

EmptyAction.propTypes = {
  state: PropTypes.string,
  isOnCard: PropTypes.bool.isRequired,
}

const VmDropdownActions = ({ actions, id }) => {
  if (actions.length === 0) {
    return null
  }

  if (actions.length === 1) {
    return <ActionButtonWraper {...actions[0]} className='btn btn-default' />
  }
  const secondaryActions = []
  for (const action of actions) {
    if (action.items) {
      secondaryActions.push(...action.items.filter(item => item && !item.actionDisabled))
    } else {
      secondaryActions.push(action)
    }
  }
  const primaryAction = secondaryActions.shift()

  return (
    <Action confirmation={primaryAction.confirmation}>
      <SplitButton
        bsStyle='default'
        title={primaryAction.shortTitle}
        onClick={primaryAction.onClick}
        id={id}
      >
        {secondaryActions.map(action =>
          <MenuItemAction key={action.shortTitle}
            id={action.id}
            confirmation={action.confirmation}
            shortTitle={action.shortTitle}
            icon={action.icon}
            onClick={action.onClick}
            className=''
          />
        )}
      </SplitButton>
    </Action>
  )
}
VmDropdownActions.propTypes = {
  actions: PropTypes.array.isRequired,
  id: PropTypes.string.isRequired,
}

/**
 * Set of actions for a single VM or Pool, either on a single VM card or on the VM
 * edit page.  The availability of actions depends on the VM state and the `isOnCard`
 * location of the VmActions component.
 */
class VmActions extends React.Component {
  constructor (props) {
    super(props)

    this.state = {
      removePreserveDisks: false,
    }

    this.getDefaultActions = this.getDefaultActions.bind(this)
  }

  /**
   * Compose main actions that appear in Card and Toolbar
   */
  getDefaultActions () {
    const {
      vm,
      pool,
      idPrefix = `vmaction-${vm.get('name')}`,
      config,
      onStartVm,
      onStartPool,
      onShutdown,
      onRestart,
      onForceShutdown,
      onSuspend,
      onRDP,
      msg,
    } = this.props
    const isPoolVm = !!vm.getIn(['pool', 'id'], false)
    const isPool = !!pool && !isPoolVm
    const status = vm.get('status')
    const onStart = (isPool ? onStartPool : onStartVm)

    const vncConsole = vm.get('consoles').find(c => c.get('protocol') === VNC)
    const hasRdp = isWindows(vm.getIn(['os', 'type']))
    const defaultUiConsole = config.get('defaultUiConsole')
    let consoles = []

    consoles = vm.get('consoles').map((c) => ({
      priority: 0,
      protocol: c.get('protocol'),
      uiConsole: toUiConsole(NATIVE, c.get('protocol')),
      shortTitle: msg[c.get('protocol') + 'Console'](),
      icon: <Icon name='external-link' />,
      id: `${idPrefix}-button-console-${c.get('protocol')}`,
      confirmation: (
        <ConsoleConfirmationModal consoleId={c.get('id')} vm={vm} />
      ),
    })).toJS()

    if (vncConsole) {
      consoles.push({
        priority: 0,
        uiConsole: BROWSER_VNC,
        shortTitle: msg.vncConsoleBrowser(),
        actionDisabled: config.get('websocket') === null,
        id: `${idPrefix}-button-console-browser`,
        confirmation: (
          <ConsoleConfirmationModal isNoVNC consoleId={vncConsole.get('id')} vm={vm} />
        ),
      })
    }

    if (hasRdp) {
      const domain = config.get('domain')
      const username = config.getIn([ 'user', 'name' ])
      consoles.push({
        priority: 0,
        uiConsole: RDP,
        shortTitle: msg.remoteDesktop(),
        icon: <Icon name='external-link' />,
        id: `${idPrefix}-button-console-rdp`,
        onClick: (e) => { e.preventDefault(); onRDP({ domain, username }) },
      })
    }

    consoles = consoles
      .map(({ uiConsole, ...props }) => ({ ...props, priority: uiConsole === defaultUiConsole ? 1 : 0 }))
      .sort((a, b) => b.priority - a.priority)

    const actions = [
      {
        priority: 0,
        actionDisabled: (!isPool && !canStart(status)) || vm.getIn(['actionInProgress', 'start']) || (isPool && pool.get('maxUserVms') <= pool.get('vmsCount')),<commit_msg>Sort VNC consoles based on ClientModeVncDefault<commit_after>import React from 'react'
import PropTypes from 'prop-types'

import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'

import style from './style.css'
import { withMsg } from '_/intl'
import { RouterPropTypeShapes } from '_/propTypeShapes'

import {
  canRestart,
  canShutdown,
  canStart,
  canConsole,
  canSuspend,
  canRemove,
  canExternalService,
} from '../../vm-status'

import {
  shutdownVm,
  restartVm,
  suspendVm,
  startPool,
  startVm,
  removeVm,
  getRDP,
} from '_/actions'

import { isWindows } from '_/helpers'

import { SplitButton, Icon, Checkbox, DropdownKebab } from 'patternfly-react'
import ConfirmationModal from './ConfirmationModal'
import ConsoleConfirmationModal from './ConsoleConfirmationModal'
import Action, { ActionButtonWraper, MenuItemAction, ActionMenuItemWrapper } from './Action'
import { VNC, RDP, BROWSER_VNC, SPICE, NATIVE_VNC, NO_VNC } from '_/constants/console'

const EmptyAction = ({ state, isOnCard }) => {
  if (!canConsole(state) && !canShutdown(state) && !canRestart(state) && !canStart(state)) {
    return (
      <div className={isOnCard ? 'card-pf-item' : undefined} />
    )
  }
  return null
}

EmptyAction.propTypes = {
  state: PropTypes.string,
  isOnCard: PropTypes.bool.isRequired,
}

const VmDropdownActions = ({ actions, id }) => {
  if (actions.length === 0) {
    return null
  }

  if (actions.length === 1) {
    return <ActionButtonWraper {...actions[0]} className='btn btn-default' />
  }
  const secondaryActions = []
  for (const action of actions) {
    if (action.items) {
      secondaryActions.push(...action.items.filter(item => item && !item.actionDisabled))
    } else {
      secondaryActions.push(action)
    }
  }
  const primaryAction = secondaryActions.shift()

  return (
    <Action confirmation={primaryAction.confirmation}>
      <SplitButton
        bsStyle='default'
        title={primaryAction.shortTitle}
        onClick={primaryAction.onClick}
        id={id}
      >
        {secondaryActions.map(action =>
          <MenuItemAction key={action.shortTitle}
            id={action.id}
            confirmation={action.confirmation}
            shortTitle={action.shortTitle}
            icon={action.icon}
            onClick={action.onClick}
            className=''
          />
        )}
      </SplitButton>
    </Action>
  )
}
VmDropdownActions.propTypes = {
  actions: PropTypes.array.isRequired,
  id: PropTypes.string.isRequired,
}

/**
 * Set of actions for a single VM or Pool, either on a single VM card or on the VM
 * edit page.  The availability of actions depends on the VM state and the `isOnCard`
 * location of the VmActions component.
 */
class VmActions extends React.Component {
  constructor (props) {
    super(props)

    this.state = {
      removePreserveDisks: false,
    }

    this.getDefaultActions = this.getDefaultActions.bind(this)
  }

  /**
   * Compose main actions that appear in Card and Toolbar
   */
  getDefaultActions () {
    const {
      vm,
      pool,
      idPrefix = `vmaction-${vm.get('name')}`,
      config,
      onStartVm,
      onStartPool,
      onShutdown,
      onRestart,
      onForceShutdown,
      onSuspend,
      onRDP,
      msg,
    } = this.props
    const isPoolVm = !!vm.getIn(['pool', 'id'], false)
    const isPool = !!pool && !isPoolVm
    const status = vm.get('status')
    const onStart = (isPool ? onStartPool : onStartVm)

    const vncConsole = vm.get('consoles').find(c => c.get('protocol') === VNC)
    const spiceConsole = vm.get('consoles').find(c => c.get('protocol') === SPICE)
    const hasRdp = isWindows(vm.getIn(['os', 'type']))
    const defaultUiConsole = config.get('defaultUiConsole')
    let consoles = []

    if (vncConsole) {
      const vncModes = [ {
        priority: 0,
        protocol: VNC,
        uiConsole: NATIVE_VNC,
        shortTitle: msg.vncConsole(),
        icon: <Icon name='external-link' />,
        id: `${idPrefix}-button-console-vnc`,
        confirmation: (
          <ConsoleConfirmationModal consoleId={vncConsole.get('id')} vm={vm} />
        ),
      },
      {
        priority: 0,
        uiConsole: BROWSER_VNC,
        shortTitle: msg.vncConsoleBrowser(),
        actionDisabled: config.get('websocket') === null,
        id: `${idPrefix}-button-console-browser`,
        confirmation: (
          <ConsoleConfirmationModal isNoVNC consoleId={vncConsole.get('id')} vm={vm} />
        ),
      }]

      if (config.get('defaultVncMode') === NO_VNC) {
        vncModes.reverse()
      }
      consoles = [...consoles, ...vncModes]
    }

    if (spiceConsole) {
      consoles.push({
        priority: 0,
        protocol: SPICE,
        uiConsole: SPICE,
        shortTitle: msg.spiceConsole(),
        icon: <Icon name='external-link' />,
        id: `${idPrefix}-button-console-spice`,
        confirmation: (
          <ConsoleConfirmationModal consoleId={spiceConsole.get('id')} vm={vm} />
        ),
      })
    }

    if (hasRdp) {
      const domain = config.get('domain')
      const username = config.getIn([ 'user', 'name' ])
      consoles.push({
        priority: 0,
        uiConsole: RDP,
        shortTitle: msg.remoteDesktop(),
        icon: <Icon name='external-link' />,
        id: `${idPrefix}-button-console-rdp`,
        onClick: (e) => { e.preventDefault(); onRDP({ domain, username }) },
      })
    }

    consoles = consoles
      .map(({ uiConsole, ...props }) => ({ ...props, priority: uiConsole === defaultUiConsole ? 1 : 0 }))
      .sort((a, b) => b.priority - a.priority)

    const actions = [
      {
        priority: 0,
        actionDisabled: (!isPool && !canStart(status)) || vm.getIn(['actionInProgress', 'start']) || (isPool && pool.get('maxUserVms') <= pool.get('vmsCount')),
{'fraction_non_alphanumeric': 0.14316488645543488, 'fraction_numerical': 0.001705412440534961, 'mean_word_length': 2.771834800270819, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 45, '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': '2956260', 'n_tokens_mistral': 3521, 'n_tokens_neox': 3514, 'n_words': 762}