diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 3475b6771..48b143948 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -357,7 +357,7 @@
}
},
"appirio-tech-react-components": {
- "version": "github:appirio-tech/react-components#923908dbb7ae84b1dabd7d9fe47994e5459e1af5",
+ "version": "github:appirio-tech/react-components#ac2f6c5474d0334f5bdc0b84ad37f939ba8d7cbf",
"requires": {
"appirio-tech-api-schemas": "5.0.70",
"appirio-tech-client-app-layer": "0.1.3",
diff --git a/src/components/Dropdown/Dropdown.jsx b/src/components/Dropdown/Dropdown.jsx
deleted file mode 100644
index dc7391841..000000000
--- a/src/components/Dropdown/Dropdown.jsx
+++ /dev/null
@@ -1,106 +0,0 @@
-require('./Dropdown.scss')
-
-import React, { Component, PropTypes } from 'react'
-import classNames from 'classnames'
-
-class Dropdown extends Component {
- constructor(props) {
- super(props)
-
- this.state = { isHidden: true }
-
- this.onClickOutside = this.onClickOutside.bind(this)
- this.onClick = this.onClick.bind(this)
- this.onClickOtherDropdown = this.onClickOtherDropdown.bind(this)
- }
-
- onClickOutside(evt) {
- let currNode = evt.target
- let isDropdown = false
-
- do {
- if(currNode.className
- && currNode.className.indexOf
- && currNode.className.indexOf('dropdown-wrap') > -1) {
- isDropdown = true
- break
- }
-
- currNode = currNode.parentNode
-
- if(!currNode)
- break
- } while(currNode.tagName)
-
- if(!isDropdown) {
- this.setState({ isHidden: true })
- }
- }
-
- onClick(evt) {
- const dropdownClicked = document.createEvent('Event')
- dropdownClicked.initEvent('dropdownClicked', true, false)
-
- document.dispatchEvent(dropdownClicked)
-
- this.setState({ isHidden: !this.state.isHidden })
- evt.stopPropagation()
- }
-
- onClickOtherDropdown() {
- this.setState({ isHidden: true })
- }
-
- componentDidMount() {
- document.removeEventListener('click', this.onClickOutside)
- document.removeEventListener('dropdownClicked', this.onClickOtherDropdown)
-
- document.addEventListener('click', this.onClickOutside)
- document.addEventListener('dropdownClicked', this.onClickOtherDropdown)
- }
-
- componentWillUnmount() {
- document.removeEventListener('click', this.onClickOutside)
- document.removeEventListener('dropdownClicked', this.onClickOtherDropdown)
- }
-
- render() {
- const { className, pointerShadow, noPointer, pointerLeft } = this.props
- const ddClasses = classNames('dropdown-wrap', {
- [`${className}`] : true,
- [`${ this.props.theme }`] : true
- })
- const ndClasses = classNames('Dropdown', {
- 'pointer-shadow' : pointerShadow,
- 'pointer-hide' : noPointer,
- 'pointer-left' : pointerLeft,
- hide : this.state.isHidden
- })
-
- return (
-
- {
- this.props.children.map((child) => {
- if (child.props.className.indexOf('dropdown-menu-header') > -1)
- return child
- })
- }
-
-
- {
- this.props.children.map((child) => {
- if (child.props.className.indexOf('dropdown-menu-list') > -1)
- return child
- })
- }
-
-
- )
- }
-}
-
-Dropdown.propTypes = {
- children: PropTypes.array.isRequired
-}
-
-export default Dropdown
diff --git a/src/components/Dropdown/Dropdown.scss b/src/components/Dropdown/Dropdown.scss
deleted file mode 100644
index 980735e63..000000000
--- a/src/components/Dropdown/Dropdown.scss
+++ /dev/null
@@ -1,158 +0,0 @@
-@import 'tc-includes';
-
-
-.dropdown-wrap {
- cursor: pointer;
- position: relative;
-}
-
-.Dropdown {
- background-color: #fff;
- box-shadow: 0 2px 7px rgba(0, 0, 0, 0.17);
- border-radius: 5px;
- display: inline-block;
- position: absolute;
- left: 0;
- top: 5px;
- width: 100%;
- z-index: 2;
-
- ul {
- height: 100%;
- width: 100%;
- position: relative;
- z-index: 10;
- background-color: #fff;
- padding: 11px 20px;
- border-radius: 5px;
-
- li {
- list-style: none;
- }
-
- li a {
- color: #394146;
- font-family: "Roboto", Arial, Helvetica, sans-serif;
- font-size: 12px;
- display: block;
- line-height: 26px;
- }
- }
-}
-
-.dropdown-wrap.default {
- border: 1px solid $tc-gray-20;
- display: flex;
- align-items: center;
- padding: calc(2 * #{$base_unit});
- position: relative;
-
- .Dropdown {
- ul.dropdown-menu-list {
- padding: 10px 0px;
- li {
- padding: 0 20px;
- @include ellipsis;
- }
-
- li:hover {
- background-color: $tc-gray-neutral-dark;
- }
- }
- }
-}
-
-.dropdown-wrap.default::after {
- content: " ";
- width: 10px;
- height: 10px;
- display: block;
- right: 10px;
- top: 50%;
- position: absolute;
- transform: translateY(-50%) rotate(45deg);
- border-bottom: 2px solid $tc-gray-20;
- border-right: 2px solid $tc-gray-20;
-}
-
-.Dropdown.hide {
- display: none;
-}
-
-.Dropdown.pointer-left:before {
- right: initial;
- left: 15px;
-}
-
-.UserDropdownMenu .Dropdown.pointer-shadow {
- margin-top: 35px;
-
- &:before {
- content: '';
- display: block;
- position: absolute;
- top: -6px;
- right: 24px;
- width: 12px;
- height: 12px;
- background: #FFFFFF;
- border-right: 1px solid $tc-gray-20;;
- border-bottom: 1px solid $tc-gray-20;;
- transform: rotate(-135deg);
- z-index:999;
- }
-}
-
-.Dropdown.pointer-hide:before {
- display: none;
-}
-
-.new-theme {
- text-align: left;
- height: 30px;
- color: $tc-black;
- background: $tc-gray-neutral-light;
- border: 1px solid $tc-gray-20;
- @include roboto;
- font-size: 13px;
- line-height: 20px;
- width: 100%;
- border-radius: 2px;
- position: relative;
-
- .dropdown-menu-header {
- width: 100%;
- border: 0;
- height: 28px;
- line-height: 28px;
- margin: 0;
- padding: 0 0 0 10px;
- color: $tc-gray-50;
- font-size: 13px;
- }
- &:after{
- display: block;
- content: '';
- position: absolute;
- width: 10px;
- height: 14px;
- right: 11px;
- top: 50%;
- margin-top: -7px;
- background: url("./icon-select.png") left top no-repeat;
- background-size: 10px 14px;
- z-index:2;
- }
- .Dropdown {
- ul.dropdown-menu-list {
- padding: 10px 0px;
- li {
- padding: 0 20px;
- @include ellipsis;
- }
- li:hover {
- background-color: $tc-gray-neutral-dark;
- }
- }
- }
-}
diff --git a/src/components/Dropdown/arrow-dropdown.png b/src/components/Dropdown/arrow-dropdown.png
deleted file mode 100644
index 2aa5059e9..000000000
Binary files a/src/components/Dropdown/arrow-dropdown.png and /dev/null differ
diff --git a/src/components/Dropdown/icon-select.png b/src/components/Dropdown/icon-select.png
deleted file mode 100644
index 8b58102b3..000000000
Binary files a/src/components/Dropdown/icon-select.png and /dev/null differ
diff --git a/src/components/ProjectStatus/ProjectStatus.jsx b/src/components/ProjectStatus/ProjectStatus.jsx
index df842fdd7..6317df082 100644
--- a/src/components/ProjectStatus/ProjectStatus.jsx
+++ b/src/components/ProjectStatus/ProjectStatus.jsx
@@ -1,149 +1,44 @@
-import React, { Component, PropTypes } from 'react'
+import React, { PropTypes } from 'react'
import cn from 'classnames'
-import { PROJECT_STATUS } from '../../config/constants'
-import SVGIconImage from '../SVGIconImage'
import './ProjectStatus.scss'
-export const enhanceDropdown = (CompositeComponent) => class extends Component {
- constructor(props) {
- super(props)
- this.state = { isOpen: false }
- this.handleClick = this.handleClick.bind(this)
- this.onSelect = this.onSelect.bind(this)
- this.onClickOutside = this.onClickOutside.bind(this)
- this.onClickOtherDropdown = this.onClickOtherDropdown.bind(this)
- this.refreshEventHandlers = this.refreshEventHandlers.bind(this)
- }
-
- refreshEventHandlers() {
- if (this.state.isOpen) {
- document.addEventListener('click', this.onClickOutside)
- document.addEventListener('dropdownClicked', this.onClickOtherDropdown)
- } else {
- document.removeEventListener('click', this.onClickOutside)
- document.removeEventListener('dropdownClicked', this.onClickOtherDropdown)
- }
- }
-
- handleClick() {
- const dropdownClicked = document.createEvent('Event')
- dropdownClicked.initEvent('dropdownClicked', true, false)
-
- document.dispatchEvent(dropdownClicked)
-
- this.setState({ isOpen: !this.state.isOpen }, () => {
- this.refreshEventHandlers()
- })
- }
-
- onSelect(value) {
- this.handleClick()
- if (this.props.onSelect) this.props.onSelect(value)
- }
-
- onClickOutside(evt) {
- let currNode = evt.target
- let isDropdown = false
- console.log('onClickOutside')
-
- do {
- if (currNode.className
- && currNode.className.indexOf
- && currNode.className.indexOf('dropdown-wrap') > -1) {
- isDropdown = true
- break
- }
-
- currNode = currNode.parentNode
-
- if (!currNode)
- break
- } while (currNode.tagName)
-
- if (!isDropdown) {
- this.setState({ isOpen: false }, () => {
- this.refreshEventHandlers()
- })
- }
- }
-
- onClickOtherDropdown() {
- this.setState({ isOpen: false }, () => {
- this.refreshEventHandlers()
- })
- }
-
- componentDidMount() {
- document.removeEventListener('click', this.onClickOutside)
- document.removeEventListener('dropdownClicked', this.onClickOtherDropdown)
-
- if (this.state.isOpen) {
- document.addEventListener('click', this.onClickOutside)
- document.addEventListener('dropdownClicked', this.onClickOtherDropdown)
- }
- }
-
- componentWillUnmount() {
- document.removeEventListener('click', this.onClickOutside)
- document.removeEventListener('dropdownClicked', this.onClickOtherDropdown)
- }
-
- render() {
- const { isOpen } = this.state
- return (
- e.stopPropagation()} className="dropdown-wrap">
-
-
- )
- }
-}
-
-
/*eslint-enable camelcase */
-const ProjectStatus = ({ canEdit, isOpen, status, handleClick, onSelect, showText, withoutLabel, unifiedHeader = true }) => {
- const selected = PROJECT_STATUS.filter((opt) => opt.value === status)[0]
+const ProjectStatus = ({ status, showText, withoutLabel, unifiedHeader = true }) => {
return (
-
-
-
- {showText && (
{withoutLabel ? selected.fullName : selected.name})}
-
- {isOpen && canEdit &&
- }
+
+
+ {showText && (
{withoutLabel ? status.fullName : status.name})}
)
}
ProjectStatus.propTypes = {
- status: PropTypes.oneOf(['draft', 'active', 'in_review', 'reviewed', 'completed', 'paused', 'cancelled']).isRequired
+ // status: PropTypes.oneOf(['draft', 'active', 'in_review', 'reviewed', 'completed', 'paused', 'cancelled']).isRequired
+ /**
+ * Status object, containing name, fullName and value fields
+ */
+ status : PropTypes.arrayOf(PropTypes.object).isRequired,
+ /**
+ * Boolean flag to render the status text
+ */
+ showText : PropTypes.bool,
+ /**
+ * Boolean flag to render the more detailed status text (fullName field form the status object).
+ * Its main use case is the place where we don't show a label like `Project Status` before rendering
+ * this component.
+ */
+ withoutLabel : PropTypes.bool,
+ /**
+ * Boolean flag to render a unified(with common background color) project status. It is added for backward
+ * compaitability only. We are not rendering this type of view of project status anymore.
+ */
+ unifiedHeader : PropTypes.bool
}
ProjectStatus.defaultProps = {
+ showText : true,
+ withoutLabel : false,
+ unifiedHeader : false
}
export default ProjectStatus
diff --git a/src/components/ProjectStatus/ProjectStatus.scss b/src/components/ProjectStatus/ProjectStatus.scss
index c0f4debb4..6cc53a69d 100644
--- a/src/components/ProjectStatus/ProjectStatus.scss
+++ b/src/components/ProjectStatus/ProjectStatus.scss
@@ -19,7 +19,7 @@ $status-height : 20px;
}
}
- .ps-draft {
+ &.ps-draft {
.status-icon {
i {
background: url('../../assets/images/ps-draft.svg') no-repeat -7px -4px;
@@ -28,7 +28,7 @@ $status-height : 20px;
}
}
- .ps-in_review {
+ &.ps-in_review {
.status-icon {
i {
background: url('../../assets/images/ps-in_review.svg') no-repeat -7px -4px;
@@ -37,7 +37,7 @@ $status-height : 20px;
}
}
- .ps-reviewed {
+ &.ps-reviewed {
.status-icon {
i {
background: url('../../assets/images/ps-reviewed.svg') no-repeat -7px -4px;
@@ -46,7 +46,7 @@ $status-height : 20px;
}
}
- .ps-active {
+ &.ps-active {
.status-icon {
i {
background: url('../../assets/images/ps-active.svg') no-repeat;
@@ -55,7 +55,7 @@ $status-height : 20px;
}
}
- .ps-cancelled {
+ &.ps-cancelled {
.status-icon {
i {
background: url('../../assets/images/ps-cancelled.svg') no-repeat -7px -4px;
@@ -64,7 +64,7 @@ $status-height : 20px;
}
}
- .ps-completed {
+ &.ps-completed {
.status-icon {
i {
background: url('../../assets/images/ps-completed.svg') no-repeat -7px -4px;
@@ -73,7 +73,7 @@ $status-height : 20px;
}
}
- .ps-paused {
+ &.ps-paused {
.status-icon {
i {
background: url('../../assets/images/ps-paused.svg') no-repeat -7px -4px;
@@ -82,6 +82,21 @@ $status-height : 20px;
}
}
+ .status-label {
+ position: relative;
+ @include tc-label-xs;
+ line-height: $base-unit*4;
+ height: $base-unit*4;
+ padding-right: 4 * $base-unit;
+ margin-left: 10px;
+ }
+}
+
+.EditableProjectStatus {
+
+ .status-label {
+ vertical-align: top;
+ }
.status-header {
display: flex;
// position: absolute;
diff --git a/src/components/ProjectStatus/editableProjectStatus.js b/src/components/ProjectStatus/editableProjectStatus.js
index 2ea599e1a..a20d2b1e9 100644
--- a/src/components/ProjectStatus/editableProjectStatus.js
+++ b/src/components/ProjectStatus/editableProjectStatus.js
@@ -1,9 +1,12 @@
-import React, { Component} from 'react'
+import React, { Component, PropTypes } from 'react'
import ProjectStatusChangeConfirmation from './ProjectStatusChangeConfirmation'
+import ProjectStatus from './ProjectStatus'
import cn from 'classnames'
import _ from 'lodash'
-import { enhanceDropdown} from './ProjectStatus'
+import { enhanceDropdown } from 'appirio-tech-react-components'
+import SVGIconImage from '../SVGIconImage'
import {
+ PROJECT_STATUS,
PROJECT_STATUS_COMPLETED,
PROJECT_STATUS_CANCELLED
} from '../../config/constants'
@@ -50,16 +53,54 @@ const editableProjectStatus = (CompositeComponent) => class extends Component {
this.setState({ statusChangeReason : _.get(reason, 'value') })
}
+ renderDropdown(props) {
+ const { canEdit, isOpen, handleClick, onItemSelect, showText, withoutLabel, unifiedHeader, status } = props
+ const selected = PROJECT_STATUS.filter((opt) => opt.value === status)[0]
+ return (
+
+
+
+ { canEdit && }
+
+ { isOpen && canEdit &&
+
+ }
+
+ )
+ }
+
render() {
const { showStatusChangeDialog, newStatus, statusChangeReason } = this.state
- const EnhancedProjectStatus = enhanceDropdown(CompositeComponent)
+ const { canEdit } = this.props
+ const ProjectStatusDropdown = canEdit ? enhanceDropdown(this.renderDropdown) : this.renderDropdown
return (
-
+
-
+
{ showStatusChangeDialog &&
class extends Component {
}
}
+editableProjectStatus.propTypes = {
+ /**
+ * Boolean flag to control editability of the project status. It does not render the dropdown if it is not editable.
+ */
+ canEdit: PropTypes.bool
+}
+
export default editableProjectStatus
\ No newline at end of file
diff --git a/src/components/SelectDropdown/SelectDropdown.jsx b/src/components/SelectDropdown/SelectDropdown.jsx
index b80914316..5c30a8a2e 100644
--- a/src/components/SelectDropdown/SelectDropdown.jsx
+++ b/src/components/SelectDropdown/SelectDropdown.jsx
@@ -3,7 +3,7 @@ require('./SelectDropdown.scss')
import _ from 'lodash'
import React, { Component, PropTypes } from 'react'
import { HOC as hoc } from 'formsy-react'
-import Dropdown from '../Dropdown/Dropdown'
+import { Dropdown } from 'appirio-tech-react-components'
class SelectDropdown extends Component {
constructor(props) {
diff --git a/src/components/SliderInput/SliderInput.js b/src/components/SliderInput/SliderInput.js
deleted file mode 100644
index 030f78610..000000000
--- a/src/components/SliderInput/SliderInput.js
+++ /dev/null
@@ -1,67 +0,0 @@
-'use strict'
-
-import React, { Component, PropTypes } from 'react'
-import Slider from 'rc-slider'
-import 'rc-slider/assets/index.css'
-import cn from 'classnames'
-import _ from 'lodash'
-import { HOC as hoc } from 'formsy-react'
-import './SliderInput.scss'
-
-class SliderInput extends Component {
- constructor(props) {
- super(props)
- this.onChange = this.onChange.bind(this)
- }
-
- onChange(value) {
- const {name, options} = this.props
- const newValue = options[value].value
- this.props.setValue(newValue)
- this.props.onChange(name, newValue)
- }
-
- noOp() {}
-
- getIndexFromValue(val) {
- return _.findIndex(this.props.options, (t) => t.value === val)
- }
-
- render() {
- const { options, min, max, step} = this.props
- const value = this.props.getValue()
- const valueIdx = this.getIndexFromValue(value)
- const marks = {}
- for(let i=0; i < options.length; i++) {
- marks[i] = options[i].title
- }
- return (
-
-
-
- )
- }
-}
-
-SliderInput.propTypes = {
- options: PropTypes.arrayOf(PropTypes.object.isRequired).isRequired,
- min: PropTypes.number.isRequired,
- max: PropTypes.number.isRequired,
- step: PropTypes.number.isRequired
-}
-SliderInput.defaultProps = {
- onChange: () => {}
-}
-export default hoc(SliderInput)
diff --git a/src/components/SliderInput/SliderInput.scss b/src/components/SliderInput/SliderInput.scss
deleted file mode 100644
index 95944cd53..000000000
--- a/src/components/SliderInput/SliderInput.scss
+++ /dev/null
@@ -1,43 +0,0 @@
-@import 'tc-includes';
-
-.SliderInput {
- margin: 25px auto 0px auto;
- .rc-slider-dot,
- .rc-slider-handle {
- background: $tc-white;
- border: 4px solid $tc-gray-10;
- border-radius: 18px;
- width: 20px;
- height: 20px;
- bottom: -7px;
- }
-
- .rc-slider-handle {
- border-color: $tc-dark-blue-90;
- margin-left: -4px;
- bottom: -2px;
- display: none;
- }
-
- &:not(.null-value) .rc-slider-dot-active {
- border: none;
- background: $tc-dark-blue-90 url('../../../assets/images/check-white.svg') no-repeat 6px 7px;
- // bottom: -2px;
- // margin-left: -5px;
- }
-
- .rc-slider-track,
- .rc-slider-rail {
- background-color: $tc-gray-10;
- }
-
- .rc-slider-mark {
- top: -30px;
- .rc-slider-mark-text {
- @include tc-label-lg;
- line-height: 5 * $base_unit;
- color: $tc-gray-80;
- letter-spacing: 0;
- }
- }
-}
\ No newline at end of file
diff --git a/src/projects/detail/components/SpecQuestionList/SpecQuestionList.scss b/src/projects/detail/components/SpecQuestionList/SpecQuestionList.scss
index 6413d7a60..54d0b9ca0 100644
--- a/src/projects/detail/components/SpecQuestionList/SpecQuestionList.scss
+++ b/src/projects/detail/components/SpecQuestionList/SpecQuestionList.scss
@@ -106,7 +106,7 @@
margin: 15px 30px 15px 0;
}
- .SliderInput {
+ .SliderRadioGroup {
margin: 40px auto 15px auto;
width: 80%;
}
diff --git a/src/projects/detail/components/SpecQuestions.jsx b/src/projects/detail/components/SpecQuestions.jsx
index b9a56d0bf..b6406f1f7 100644
--- a/src/projects/detail/components/SpecQuestions.jsx
+++ b/src/projects/detail/components/SpecQuestions.jsx
@@ -8,7 +8,6 @@ import SpecQuestionIcons from './SpecQuestionList/SpecQuestionIcons'
import SpecFeatureQuestion from './SpecFeatureQuestion'
import ColorSelector from './../../../components/ColorSelector/ColorSelector'
import SelectDropdown from './../../../components/SelectDropdown/SelectDropdown'
-import SliderInput from './../../../components/SliderInput/SliderInput'
// HOC for TextareaInput
const SeeAttachedTextareaInput = seeAttachedWrapperField(TCFormFields.Textarea)
@@ -142,7 +141,7 @@ const SpecQuestions = ({questions, project, dirtyProject, resetFeatures, showFea
})
break
case 'slide-radiogroup':
- ChildElem = SliderInput
+ ChildElem = TCFormFields.SliderRadioGroup
_.assign(elemProps, {
options: q.options,
min: 0,
diff --git a/src/projects/list/components/Projects/ProjectCardBody.jsx b/src/projects/list/components/Projects/ProjectCardBody.jsx
index 0e7fcca0d..2687e7b77 100644
--- a/src/projects/list/components/Projects/ProjectCardBody.jsx
+++ b/src/projects/list/components/Projects/ProjectCardBody.jsx
@@ -8,6 +8,8 @@ import { PROJECT_STATUS_ACTIVE, PROJECT_ROLE_COPILOT, PROJECT_ROLE_MANAGER } fro
import './ProjectCardBody.scss'
import _ from 'lodash'
+const EnhancedProjectStatus = editableProjectStatus(ProjectStatus)
+
function ProjectCardBody({ project, duration, currentMemberRole, descLinesCount = 8,
onChangeStatus, isSuperUser }) {
if (!project) return null
@@ -17,8 +19,6 @@ function ProjectCardBody({ project, duration, currentMemberRole, descLinesCount
const progress = _.get(process, 'percent', 0)
- const EnhancedProjectStatus = canEdit ? editableProjectStatus(ProjectStatus) : ProjectStatus
-
return (