Skip to content

Commit 852e283

Browse files
committed
Fixes for issues 4427, 4460 and 4415
1 parent db728d9 commit 852e283

File tree

7 files changed

+141
-95
lines changed

7 files changed

+141
-95
lines changed

src/projects/detail/components/SimplePlan/ManageMilestones/ManageMilestones.jsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -191,21 +191,21 @@ class ManageMilestones extends React.Component {
191191
if (!challengeIds.length) {
192192
return [
193193
<MilestoneChallengeHeader key="header" isUpdatable={isUpdatable}/>,
194-
<MilestoneChallengeRow isEmpty key="row" isUpdatable={isUpdatable}/>
194+
<MilestoneChallengeRow milestone={milestone} isEmpty key="row" isUpdatable={isUpdatable}/>
195195
]
196196
}
197197

198198
// loading challenges
199199
if (milestone.isLoadingChallenges) {
200200
return [
201201
<MilestoneChallengeHeader key="header" isUpdatable={isUpdatable}/>,
202-
<MilestoneChallengeRow isLoading key="row" isUpdatable={isUpdatable}/>,
202+
<MilestoneChallengeRow milestone={milestone} isLoading key="row" isUpdatable={isUpdatable}/>,
203203
<MilestoneChallengeFooter isLoading key="footer" onLoadChallengesByPage={this.onLoadChallengesByPage} isUpdatable={isUpdatable}/>
204204
]
205205
}
206206

207207
const rows = _.map(milestone.challenges, (c) => {
208-
return <MilestoneChallengeRow key={c.id} challenge={c} isUpdatable={isUpdatable}/>
208+
return <MilestoneChallengeRow milestone={milestone} key={c.id} challenge={c} isUpdatable={isUpdatable}/>
209209
})
210210
return [
211211
<MilestoneChallengeHeader key="header" isUpdatable={isUpdatable}/>,
@@ -248,6 +248,7 @@ class ManageMilestones extends React.Component {
248248
} = this.props
249249

250250
const canEdit = isUpdatable && this.getSelectCount() > 0
251+
const disableDeleteAction = this.getSelectCount() > 1
251252
return (
252253
<div>
253254
<div styleName="toolbar">
@@ -309,6 +310,7 @@ class ManageMilestones extends React.Component {
309310
allMilestones={milestones}
310311
isCreatingRow={`${milestone.id}`.startsWith('new-milestone')}
311312
isUpdatable={isUpdatable}
313+
disableDeleteAction={disableDeleteAction}
312314
phaseMembers={milestone.members}
313315
/>,
314316
...this.renderChallengeTable(milestone)

src/projects/detail/components/SimplePlan/components/AddCopilotsSidebar/AddCopilotsSidebar.jsx

+114-85
Original file line numberDiff line numberDiff line change
@@ -11,95 +11,124 @@ import IconXMark from '../../../../../../assets/icons/x-mark-thin.svg'
1111

1212
import './AddCopilotsSidebar.scss'
1313

14-
function AddCopilotsSidebar({
15-
memberToAdd,
16-
setMemberToAdd,
17-
copilots,
18-
projectMembers,
19-
onClose,
20-
onAdd,
21-
onRemove
22-
}) {
23-
const canManageCopilots = hasPermission(PERMISSIONS.MANAGE_COPILOTS)
24-
const canRemoveCopilots = hasPermission(PERMISSIONS.REMOVE_COPILOTS)
14+
class AddCopilotsSidebar extends React.Component {
15+
constructor(props) {
16+
super(props)
2517

26-
const projectMemberOptions = projectMembers.map(projectMember => ({
27-
label: projectMember.handle,
28-
value: projectMember
29-
})).filter(
30-
// check if project member was not added
31-
option => copilots.findIndex(copilot => copilot.userId === option.value.userId) === -1 &&
32-
// check if project member role is copilot
33-
option.value.role === PROJECT_ROLE_COPILOT
34-
)
18+
this.state = {
19+
}
3520

36-
return (
37-
<aside styleName="add-copilots-sidebar">
38-
<h2 styleName="title">
39-
Copilot
40-
<button type="button" className="tc-btn tc-btn-link" styleName="button-close" onClick={onClose}>
41-
<IconXMark />
42-
</button>
43-
</h2>
44-
<div styleName="select-copilot">
45-
<span styleName="label">Add New Copilot</span>
46-
<Select
47-
options={projectMemberOptions}
48-
onChange={(selectedOption) => {
49-
if (!selectedOption) {
50-
return
51-
}
21+
this.onClickOutside = this.onClickOutside.bind(this)
22+
}
5223

53-
setMemberToAdd(selectedOption.value)
54-
}}
55-
value={projectMemberOptions.find(option => option.value === memberToAdd) || null}
56-
placeholder="- Select -"
57-
isClearable={false}
58-
/>
59-
<button
60-
className="tc-btn tc-btn-primary tc-btn-sm"
61-
onClick={() => {
62-
onAdd(memberToAdd)
63-
setMemberToAdd(null)
64-
}}
65-
disabled={!memberToAdd}
66-
styleName="add-button"
67-
>
68-
ADD
69-
</button>
70-
</div>
71-
<ul styleName="copilot-list">
72-
{copilots.map((member, index) => (
73-
<li key={`${member.handle}-${index}`}>
74-
<div styleName="member-details">
75-
<Avatar
76-
userName={getFullNameWithFallback(member)}
77-
avatarUrl={getAvatarResized(_.get(member, 'photoURL') || '', 80)}
78-
size={40}
79-
/>
80-
<div styleName="name-and-handle">
81-
<span styleName="fullname">{getFullNameWithFallback(member)}</span>
82-
<span styleName="handle">
83-
@{member.handle || 'ConnectUser'}
84-
</span>
24+
onClickOutside(event) {
25+
const {onClose} = this.props
26+
if(this.ref.contains(event.target)) {
27+
return
28+
}
29+
30+
onClose()
31+
}
32+
33+
componentDidMount() {
34+
document.addEventListener('click', this.onClickOutside)
35+
}
36+
37+
componentWillUnmount() {
38+
document.removeEventListener('click', this.onClickOutside)
39+
}
40+
41+
render() {
42+
const {
43+
memberToAdd,
44+
setMemberToAdd,
45+
copilots,
46+
projectMembers,
47+
onClose,
48+
onAdd,
49+
onRemove
50+
} = this.props
51+
const canManageCopilots = hasPermission(PERMISSIONS.MANAGE_COPILOTS)
52+
const canRemoveCopilots = hasPermission(PERMISSIONS.REMOVE_COPILOTS)
53+
54+
const projectMemberOptions = projectMembers.map(projectMember => ({
55+
label: projectMember.handle,
56+
value: projectMember
57+
})).filter(
58+
// check if project member was not added
59+
option => copilots.findIndex(copilot => copilot.userId === option.value.userId) === -1 &&
60+
// check if project member role is copilot
61+
option.value.role === PROJECT_ROLE_COPILOT
62+
)
63+
64+
return (
65+
<aside styleName="add-copilots-sidebar" ref={ ref => this.ref = ref}>
66+
<h2 styleName="title">
67+
Copilot
68+
<button type="button" className="tc-btn tc-btn-link" styleName="button-close" onClick={onClose}>
69+
<IconXMark />
70+
</button>
71+
</h2>
72+
<div styleName="select-copilot">
73+
<span styleName="label">Add New Copilot</span>
74+
<Select
75+
options={projectMemberOptions}
76+
onChange={(selectedOption) => {
77+
if (!selectedOption) {
78+
return
79+
}
80+
81+
setMemberToAdd(selectedOption.value)
82+
}}
83+
value={projectMemberOptions.find(option => option.value === memberToAdd) || null}
84+
placeholder="- Select -"
85+
isClearable={false}
86+
/>
87+
<button
88+
className="tc-btn tc-btn-primary tc-btn-sm"
89+
onClick={() => {
90+
onAdd(memberToAdd)
91+
setMemberToAdd(null)
92+
}}
93+
disabled={!memberToAdd}
94+
styleName="add-button"
95+
>
96+
ADD
97+
</button>
98+
</div>
99+
<ul styleName="copilot-list">
100+
{copilots.map((member, index) => (
101+
<li key={`${member.handle}-${index}`}>
102+
<div styleName="member-details">
103+
<Avatar
104+
userName={getFullNameWithFallback(member)}
105+
avatarUrl={getAvatarResized(_.get(member, 'photoURL') || '', 80)}
106+
size={40}
107+
/>
108+
<div styleName="name-and-handle">
109+
<span styleName="fullname">{getFullNameWithFallback(member)}</span>
110+
<span styleName="handle">
111+
@{member.handle || 'ConnectUser'}
112+
</span>
113+
</div>
114+
{(canManageCopilots || canRemoveCopilots) && (
115+
<button
116+
className="tc-btn tc-btn-link"
117+
styleName="close-button"
118+
onClick={() => {
119+
onRemove(member)
120+
}}
121+
>
122+
&times;
123+
</button>
124+
)}
85125
</div>
86-
{(canManageCopilots || canRemoveCopilots) && (
87-
<button
88-
className="tc-btn tc-btn-link"
89-
styleName="close-button"
90-
onClick={() => {
91-
onRemove(member)
92-
}}
93-
>
94-
&times;
95-
</button>
96-
)}
97-
</div>
98-
</li>
99-
))}
100-
</ul>
101-
</aside>
102-
)
126+
</li>
127+
))}
128+
</ul>
129+
</aside>
130+
)
131+
}
103132
}
104133

105134
AddCopilotsSidebar.propTypes = {

src/projects/detail/components/SimplePlan/components/MilestoneChallengeFooter/MilestoneChallengeFooter.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class MilestoneChallengeFooter extends React.Component {
7575
<td colSpan={isUpdatable? '9': '8'}>
7676
<div styleName="challenge-table-row">
7777
<div styleName="view-button">
78-
<a href={url}>
78+
<a href={url} target="_blank">
7979
VIEW CHALLENGES
8080
</a>
8181
</div>

src/projects/detail/components/SimplePlan/components/MilestoneChallengeRow/MilestoneChallengeRow.jsx

+7-5
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import React from 'react'
55
import PT from 'prop-types'
66
import moment from 'moment'
77
import {
8-
CHALLENGE_DETAIL_APP
8+
WORK_MANAGER_APP
99
} from '../../../../../../../src/config/constants'
1010

1111
import './MilestoneChallengeRow.scss'
1212

13-
function MilestoneChallengeRow({challenge, isEmpty, isLoading, isUpdatable}) {
13+
function MilestoneChallengeRow({challenge, milestone, isEmpty, isLoading, isUpdatable}) {
1414

1515
if (isEmpty) {
1616
return (
@@ -41,16 +41,17 @@ function MilestoneChallengeRow({challenge, isEmpty, isLoading, isUpdatable}) {
4141
status,
4242
track,
4343
startDate,
44-
endDate
44+
endDate,
4545
} = challenge
4646

4747
const statusLabel = status.indexOf('Cancelled') === 0 ? 'Cancelled': status
48+
const url = `${WORK_MANAGER_APP}/${milestone.projectId}/challenges/${id}/view`
4849

4950
return (
5051
<tr styleName="challenge-table-row-wrap">
5152
<td colSpan={isUpdatable? '9': '8'}>
5253
<div styleName="challenge-table-row">
53-
<div styleName="title"><a href={`${CHALLENGE_DETAIL_APP}/${id}`}>{name}</a></div>
54+
<div styleName="title"><a href={`${url}`} target="_blank">{name}</a></div>
5455
<div styleName="status"><div styleName={statusLabel}>{statusLabel}</div></div>
5556
<div styleName="type"><div styleName={track.split(' ').join('')}>{track}</div></div>
5657
<div styleName="start-date">{moment(startDate).format('MM-DD-YYYY')}</div>
@@ -65,7 +66,8 @@ MilestoneChallengeRow.propTypes = {
6566
challenge: PT.shape(),
6667
isUpdatable: PT.bool,
6768
isEmpty: PT.bool,
68-
isLoading: PT.bool
69+
isLoading: PT.bool,
70+
milestone: PT.shape()
6971
}
7072

7173
export default MilestoneChallengeRow

src/projects/detail/components/SimplePlan/components/MilestoneDeleteButton/MilestoneDeleteButton.jsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class MilestoneDeleteButton extends React.Component {
3636
}
3737

3838
render() {
39-
const { onDelete } = this.props
39+
const { onDelete, disabled } = this.props
4040
const { open } = this.state
4141

4242
return (
@@ -45,6 +45,7 @@ class MilestoneDeleteButton extends React.Component {
4545
type="button"
4646
className="tc-btn tc-btn-link"
4747
styleName="icon-button"
48+
disabled={disabled}
4849
onClick={(event) => {
4950
event.stopPropagation()
5051

@@ -84,6 +85,7 @@ class MilestoneDeleteButton extends React.Component {
8485

8586
MilestoneDeleteButton.propTypes = {
8687
onDelete: PT.func,
88+
disabled: PT.bool
8789
}
8890

8991
export default MilestoneDeleteButton

src/projects/detail/components/SimplePlan/components/MilestoneRow/MilestoneRow.jsx

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ function MilestoneRow({
3939
isCreatingRow,
4040
isUpdatable,
4141
phaseMembers,
42+
disableDeleteAction
4243
}) {
4344
const phaseStatusOptions = PHASE_STATUS_OPTIONS
4445
const edit = milestone.edit
@@ -294,6 +295,7 @@ function MilestoneRow({
294295
<IconPencil />
295296
</button>
296297
<MilestoneDeleteButton
298+
disabled={disableDeleteAction}
297299
onDelete={() => {
298300
onRemove(milestone.id)
299301
}}
@@ -322,6 +324,7 @@ MilestoneRow.propTypes = {
322324
allMilestones: PT.arrayOf(PT.shape()),
323325
isCreatingRow: PT.bool,
324326
isUpdatable: PT.bool,
327+
disableDeleteAction: PT.bool,
325328
members: PT.object,
326329
}
327330

src/projects/detail/components/SimplePlan/components/MilestoneRow/MilestoneRow.scss

+8
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,17 @@
153153
> *:not(:last-child) {
154154
margin-right: 10px;
155155
}
156+
157+
button {
158+
color: black;
159+
}
156160
svg {
157161
width: 14px;
158162
height: 14px;
163+
164+
path {
165+
fill: currentColor
166+
}
159167
}
160168
}
161169
}

0 commit comments

Comments
 (0)