<commit_before>/*
Copyright (C) 2017  Cloudbase Solutions SRL
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

// @flow

import React from 'react'
import { observer } from 'mobx-react'
import styled, { css } from 'styled-components'
import { Collapse } from 'react-collapse'

import type { Task } from '../../../types/Task'
import StatusIcon from '../../atoms/StatusIcon'
import Arrow from '../../atoms/Arrow'
import StatusPill from '../../atoms/StatusPill'
import CopyValue from '../../atoms/CopyValue'
import ProgressBar from '../../atoms/ProgressBar'
import CopyButton from '../../atoms/CopyButton'
import notificationStore from '../../../stores/NotificationStore'
import DomUtils from '../../../utils/DomUtils'
import Palette from '../../styleUtils/Palette'
import StyleProps from '../../styleUtils/StyleProps'
import DateUtils from '../../../utils/DateUtils'

const Wrapper = styled.div`
  cursor: pointer;
  border-bottom: 1px solid white;
  transition: all ${StyleProps.animations.swift};
  ${props => props.open ? `background: ${Palette.grayscale[0]};` : ''}
  &:hover {
    background: ${Palette.grayscale[0]};
  }
`
const ArrowStyled = styled(Arrow)`
  position: absolute;
  left: -24px;
`
const Header = styled.div`
  display: flex;
  padding: 8px;
  position: relative;
  &:hover ${ArrowStyled} {
    opacity: 1;
  }
`
const HeaderData = styled.div`
  display: block;
  ${props => props.capitalize ? 'text-transform: capitalize;' : ''}
  width: ${props => props.width};
  color: ${props => props.black ? Palette.black : Palette.grayscale[4]};
  padding-right: 8px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  position: relative;
`
const Title = styled.div`
  display: flex;
`
const TitleText = styled.div`
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
`
const Body = styled.div`
  display: flex;
  flex-direction: column;
  padding: 24px 8px;
`
const Columns = styled.div`
  display: flex;
`
const Column = styled.div`
  display: flex;
  flex-direction: column;
`
const Row = styled.div`
  display: flex;
  margin-bottom: 24px;
`
const RowData = styled.div`
  ${props => props.width ? css`min-width: ${props.width};` : ''}
  ${props => !props.skipPaddingLeft ? css`
    &:first-child {
      padding-left: 24px;
      ${props => css`min-width: calc(${props.width} + 21px);`}
    }
  ` : ''}
`
const Label = styled.div`
  text-transform: uppercase;
  font-size: 10px;
  font-weight: ${StyleProps.fontWeights.medium};
  color: ${Palette.grayscale[5]};
  margin-bottom: 4px;
`
const Value = styled.div`
  ${props => props.width ? css`width: ${props.width};` : ''}
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  ${props => props.primary ? css`color: ${Palette.primary};` : ''}
  &:hover {
    ${props => props.primaryOnHover ? css`color: ${Palette.primary};` : ''}
  }
`
const DependsOnIds = styled.div`
  display: flex;
  flex-direction: column;
`
const ExceptionText = styled.div`
  cursor: pointer;
  text-overflow: ellipsis;
  overflow: hidden;
  &:hover > span {
    opacity: 1;
  }
  > span {
    background-position-y: 4px;
    margin-left: 4px;
  }
`
const ProgressUpdates = styled.div`
  color: ${Palette.black};
`
const ProgressUpdate = styled.div`
  display: flex;
  color: ${props => props.secondary ? Palette.grayscale[5] : 'inherit'};
`
const ProgressUpdateDate = styled.div`
  min-width: ${props => props.width || 'auto'};
  & > span {margin-left: 24px;}
`
const ProgressUpdateValue = styled.div`
  width: 100%;
  margin-right: 32px;
`

type Props = {
  columnWidths: string[],
  item: Task,
  open: boolean,
  onDependsOnClick: (id: string) => void,
}
@observer
class TaskItem extends React.Component<Props> {
  getLastMessage() {
    let message
    if (this.props.item.progress_updates.length) {
      message = this.props.item.progress_updates[0].message
    } else {
      message = '-'
    }

    return message
  }

  getMessageProgress(message: string) {
    let match = message.match(/.*progress.*?(100|\d{1,2})%/)
    return match && match[1]
  }

  handleExceptionTextClick(exceptionText: string) {
    let succesful = DomUtils.copyTextToClipboard(exceptionText)

    if (succesful) {
      notificationStore.alert('The message has been copied to clipboard.')
    }
  }

  renderHeader() {
    let date = this.props.item.updated_at ? this.props.item.updated_at : this.props.item.created_at

    return (
      <Header>
        <HeaderData capitalize width={this.props.columnWidths[0]} black>
          <Title>
            <StatusIcon status={this.props.item.status} style={{ marginRight: '8px' }} />
            <TitleText>{this.props.item.task_type.replace(/_/g, ' ').toLowerCase()}</TitleText>
          </Title>
        </HeaderData><commit_msg>Fix text-overflow CSS issue in task info<commit_after>/*
Copyright (C) 2017  Cloudbase Solutions SRL
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

// @flow

import React from 'react'
import { observer } from 'mobx-react'
import styled, { css } from 'styled-components'
import { Collapse } from 'react-collapse'

import type { Task } from '../../../types/Task'
import StatusIcon from '../../atoms/StatusIcon'
import Arrow from '../../atoms/Arrow'
import StatusPill from '../../atoms/StatusPill'
import CopyValue from '../../atoms/CopyValue'
import ProgressBar from '../../atoms/ProgressBar'
import CopyButton from '../../atoms/CopyButton'
import notificationStore from '../../../stores/NotificationStore'
import DomUtils from '../../../utils/DomUtils'
import Palette from '../../styleUtils/Palette'
import StyleProps from '../../styleUtils/StyleProps'
import DateUtils from '../../../utils/DateUtils'

const Wrapper = styled.div`
  cursor: pointer;
  border-bottom: 1px solid white;
  transition: all ${StyleProps.animations.swift};
  ${props => props.open ? `background: ${Palette.grayscale[0]};` : ''}
  &:hover {
    background: ${Palette.grayscale[0]};
  }
`
const ArrowStyled = styled(Arrow)`
  position: absolute;
  left: -24px;
`
const Header = styled.div`
  display: flex;
  padding: 8px;
  position: relative;
  &:hover ${ArrowStyled} {
    opacity: 1;
  }
`
const HeaderData = styled.div`
  display: block;
  ${props => props.capitalize ? 'text-transform: capitalize;' : ''}
  width: ${props => props.width};
  color: ${props => props.black ? Palette.black : Palette.grayscale[4]};
  padding-right: 8px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  position: relative;
`
const Title = styled.div`
  display: flex;
`
const TitleText = styled.div`
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
`
const Body = styled.div`
  display: flex;
  flex-direction: column;
  padding: 24px 8px;
`
const Columns = styled.div`
  display: flex;
`
const Column = styled.div`
  display: flex;
  flex-direction: column;
`
const Row = styled.div`
  display: flex;
  margin-bottom: 24px;
`
const RowData = styled.div`
  ${props => props.width ? css`min-width: ${props.width};` : ''}
  ${props => !props.skipPaddingLeft ? css`
    &:first-child {
      padding-left: 24px;
      ${props => css`min-width: calc(${props.width} + 21px);`}
    }
  ` : ''}
`
const Label = styled.div`
  text-transform: uppercase;
  font-size: 10px;
  font-weight: ${StyleProps.fontWeights.medium};
  color: ${Palette.grayscale[5]};
  margin-bottom: 4px;
`
const Value = styled.div`
  ${props => props.width ? css`width: ${props.width};` : ''}
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  ${props => props.primary ? css`color: ${Palette.primary};` : ''}
  &:hover {
    ${props => props.primaryOnHover ? css`color: ${Palette.primary};` : ''}
  }
`
const DependsOnIds = styled.div`
  display: flex;
  flex-direction: column;
`
const ExceptionText = styled.div`
  cursor: pointer;
  text-overflow: ellipsis;
  overflow: hidden;
  &:hover > span {
    opacity: 1;
  }
  > span {
    background-position-y: 4px;
    margin-left: 4px;
  }
`
const ProgressUpdates = styled.div`
  color: ${Palette.black};
`
const ProgressUpdate = styled.div`
  display: flex;
  color: ${props => props.secondary ? Palette.grayscale[5] : 'inherit'};
`
const ProgressUpdateDate = styled.div`
  min-width: ${props => props.width || 'auto'};
  & > span {margin-left: 24px;}
`
const ProgressUpdateValue = styled.div`
  width: 100%;
  margin-right: 32px;
  word-break: break-word;
`

type Props = {
  columnWidths: string[],
  item: Task,
  open: boolean,
  onDependsOnClick: (id: string) => void,
}
@observer
class TaskItem extends React.Component<Props> {
  getLastMessage() {
    let message
    let progressUpdates = this.props.item.progress_updates
    if (progressUpdates.length) {
      message = progressUpdates[progressUpdates.length - 1].message
    } else {
      message = '-'
    }

    return message
  }

  getMessageProgress(message: string) {
    let match = message.match(/.*progress.*?(100|\d{1,2})%/)
    return match && match[1]
  }

  handleExceptionTextClick(exceptionText: string) {
    let succesful = DomUtils.copyTextToClipboard(exceptionText)

    if (succesful) {
      notificationStore.alert('The message has been copied to clipboard.')
    }
  }

  renderHeader() {
    let date = this.props.item.updated_at ? this.props.item.updated_at : this.props.item.created_at

    return (
      <Header>
        <HeaderData capitalize width={this.props.columnWidths[0]} black>
          <Title>
            <StatusIcon status={this.props.item.status} style={{ marginRight: '8px' }} />
            <TitleText>{this.props.item.task_type.replace(/_/g, ' ').toLowerCase()}</TitleText>
          </Title>
        </HeaderData>
{'fraction_non_alphanumeric': 0.14703974798480496, 'fraction_numerical': 0.008709348651904012, 'mean_word_length': 3.5486725663716814, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '969990', 'n_tokens_mistral': 3542, 'n_tokens_neox': 3468, 'n_words': 943}