Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ workflows:
- build-dev
filters:
branches:
only: ['dev', 'feature/add_msg_for_taas_projects']
only: ['dev', 'feature/project-plan-simplification-0']

- deployTest01:
context : org-global
Expand Down
35 changes: 35 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion src/config/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ export const CREATE_TIMELINE_MILESTONE_SUCCESS = 'CREATE_TIMELINE_MILESTONE_SUCC
export const CREATE_TIMELINE_MILESTONE_FAILURE = 'CREATE_TIMELINE_MILESTONE_FAILURE'
export const CREATE_TIMELINE_MILESTONE_PENDING = 'CREATE_TIMELINE_MILESTONE_PENDING'

// project phases
export const CREATE_PROJECT_PHASE = 'CREATE_PROJECT_PHASE'
export const CREATE_PROJECT_PHASE_FAILURE = 'CREATE_PROJECT_PHASE_FAILURE'
export const CREATE_PROJECT_PHASE_SUCCESS = 'CREATE_PROJECT_PHASE_SUCCESS'
export const CREATE_PROJECT_PHASE_PENDING = 'CREATE_PROJECT_PHASE_PENDING'

// project phases and timeline and milestones
export const CREATE_PROJECT_PHASE_TIMELINE_MILESTONES = 'CREATE_PROJECT_PHASE_TIMELINE_MILESTONES'
export const CREATE_PROJECT_PHASE_TIMELINE_MILESTONES_FAILURE = 'CREATE_PROJECT_PHASE_TIMELINE_MILESTONES_FAILURE'
Expand Down Expand Up @@ -613,7 +619,7 @@ export const PHASE_STATUS = [
{color: 'gray', name: 'Draft', fullName: 'Phase is in draft', value: PHASE_STATUS_DRAFT, order: 2, dropDownOrder: 1 },
// {color: 'gray', name: 'In review', fullName: 'Phase is in review', value: PHASE_STATUS_IN_REVIEW, order: 3, dropDownOrder: 2 },
{color: 'gray', name: 'Planned', fullName: 'Phase is reviewed', value: PHASE_STATUS_REVIEWED, order: 4, dropDownOrder: 3 },
{color: 'green', name: 'Active', fullName: 'Phase is active', value: PHASE_STATUS_ACTIVE, order: 1, dropDownOrder: 4 },
{color: 'green', name: 'Published', fullName: 'Phase is active', value: PHASE_STATUS_ACTIVE, order: 1, dropDownOrder: 4 },
{color: 'black', name: 'Completed', fullName: 'Phase is completed', value: PHASE_STATUS_COMPLETED, order: 5, dropDownOrder: 5 },
// {color: 'black', name: 'Cancelled', fullName: 'Phase is canceled', value: PHASE_STATUS_CANCELLED, order: 6, dropDownOrder: 6 },
// {color: 'red', name: 'Paused', fullName: 'Phase is paused', value: PHASE_STATUS_PAUSED, order: 7, dropDownOrder: 7 }
Expand Down
14 changes: 14 additions & 0 deletions src/config/permissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,20 @@ export const PERMISSIONS = {
],
},

SHOW_PHASE_STATUS: {
meta: {
group: 'Project Plan',
title: 'Show project phase status',
},
projectRoles: [
..._.difference(PROJECT_ALL, [PROJECT_ROLE_CUSTOMER])
],
topcoderRoles: [
ROLE_CONNECT_MANAGER,
...TOPCODER_ADMINS,
],
},

/*
Project Members
*/
Expand Down
12 changes: 9 additions & 3 deletions src/helpers/projectHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,20 @@ export function getPhaseActualData(phase, timeline) {
duration = phase.duration ? phase.duration : 0
progress = phase.progress ? phase.progress : 0

if (startDate) {
// if start date and duration are set, use them to calculate endDate
if (!endDate && startDate && duration > 0) {
endDate = startDate.clone().add(duration, 'days')
} else {
}
// default to today if start date not set
if (!startDate) {
startDate = moment().hours(0).minutes(0).seconds(0).milliseconds(0)
}
// default to today if end date not set
if (!endDate) {
endDate = moment().hours(0).minutes(0).seconds(0).milliseconds(0)
}
// re-caclulate the duration of the phase
duration = endDate.diff(startDate, 'days') + 1

// if phase's product has timeline get data from timeline
} else {
Expand Down Expand Up @@ -264,7 +270,7 @@ export function getProjectNavLinks(project, projectId, renderFAQs) {
messagesTab = { label: 'Messages', to: `/projects/${projectId}/messages`, Icon: MessagesIcon, iconClassName: 'stroke', exact: false }
}
// choose set of menu links based on the project version
const navLinks = project.version === 'v3' ? [
const navLinks = ['v3', 'v4'].includes(project.version) ? [
{ label: 'Dashboard', to: `/projects/${projectId}`, Icon: DashboardIcon, iconClassName: 'stroke' },
messagesTab,
{ label: 'Scope', to: `/projects/${projectId}/scope`, Icon: ScopeIcon, iconClassName: 'fill' },
Expand Down
63 changes: 47 additions & 16 deletions src/projects/actions/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ import {
LOAD_PROJECT_MEMBER_INVITES,
CREATE_PROJECT_PHASE_TIMELINE_MILESTONES,
LOAD_PROJECT_MEMBER,
ES_REINDEX_DELAY
ES_REINDEX_DELAY,
CREATE_PROJECT_PHASE
} from '../../config/constants'
import {
updateProductMilestone,
Expand Down Expand Up @@ -178,6 +179,7 @@ function getProjectPhasesWithProducts(projectId) {
'endDate',
'id',
'name',
'description',
'progress',
'projectId',
'spentBudget',
Expand Down Expand Up @@ -273,16 +275,20 @@ function createProductsTimelineAndMilestone(project) {
/**
* Create phase and product for the project
*
* @param {Object} project project
* @param {Object} productTemplate product template
* @param {String} status (optional) project/phase status
* @param {Object} project project
* @param {Object} productTemplate product template
* @param {String} status (optional) project/phase status
* @param {Date} startDate start date of the phase
* @param {Date} endDate end date of the phase
* @param {Boolean} createTimeline flag to indicate if we need to create timeline for the phase
*
* @return {Promise} project
*/
export function createProjectPhaseAndProduct(project, productTemplate, status = PHASE_STATUS_DRAFT, startDate, endDate) {
export function createProjectPhaseAndProduct(project, productTemplate, status = PHASE_STATUS_DRAFT, startDate, endDate, createTimeline = true) {
const param = {
status,
name: productTemplate.name,
description: productTemplate.description,
productTemplateId: productTemplate.id
}
if (startDate) {
Expand All @@ -293,13 +299,21 @@ export function createProjectPhaseAndProduct(project, productTemplate, status =
}

return createProjectPhase(project.id, param).then((phase) => {
// we also wait until timeline is created as we will load it for the phase after creation
return createTimelineAndMilestoneForProduct(phase.products[0], phase).then((timeline) => ({
project,
phase,
product:phase.products[0],
timeline,
}))
if (createTimeline) {
// we also wait until timeline is created as we will load it for the phase after creation
return createTimelineAndMilestoneForProduct(phase.products[0], phase).then((timeline) => ({
project,
phase,
product:phase.products[0],
timeline,
}))
} else {
return Promise.resolve({
project,
phase,
product:phase.products[0]
})
}
})
}

Expand Down Expand Up @@ -331,6 +345,25 @@ function createPhaseAndMilestonesRequest(project, productTemplate, status = PHAS
})
}

/**
* Creates phase and product only, without timeline and milestone. Introduced with project plan simplification
* work where we removed timeline and milestones for projects with version v4
* @param {*} project
* @param {*} productTemplate
* @param {*} status
* @param {*} startDate
* @param {*} endDate
*/
export function createPhaseWithoutTimeline(project, productTemplate, status, startDate, endDate) {
return (dispatch) => {
console.log(CREATE_PROJECT_PHASE)
return dispatch({
type: CREATE_PROJECT_PHASE,
payload: createProjectPhaseAndProduct(project, productTemplate, status, startDate, endDate, false)
})
}
}

export function createPhaseAndMilestones(project, productTemplate, status, startDate, endDate, milestones) {
return (dispatch, getState) => {
return dispatch({
Expand All @@ -340,9 +373,6 @@ export function createPhaseAndMilestones(project, productTemplate, status, start
const state = getState()
const project = state.projectState.project

console.log('project.status', project.status)
console.log('status', status)

// if phase is created as ACTIVE, move project to ACTIVE too
if (
_.includes([PROJECT_STATUS_DRAFT, PROJECT_STATUS_IN_REVIEW, PROJECT_STATUS_REVIEWED], project.status) &&
Expand Down Expand Up @@ -464,6 +494,7 @@ export function updatePhase(projectId, phaseId, updatedProps, phaseIndex) {
const phaseStartDate = timeline ? timeline.startDate : phase.startDate
const startDateChanged = updatedProps.startDate ? updatedProps.startDate.diff(phaseStartDate) : null
const phaseActivated = phaseStatusChanged && updatedProps.status === PHASE_STATUS_ACTIVE
const projectVersion = state.projectState.project.version

if (updatedProps.startDate) {
updatedProps.startDate = moment(updatedProps.startDate).format('YYYY-MM-DD')
Expand Down Expand Up @@ -494,7 +525,7 @@ export function updatePhase(projectId, phaseId, updatedProps, phaseIndex) {
// - phase's status is changed to active
// - there is not active milestone alreay (this can happen when phase is made active more than once
// e.g. Active => Paused => Active)
if (timeline && !activeMilestone && phaseActivated ) {
if (projectVersion !== 'v4' && timeline && !activeMilestone && phaseActivated ) {
dispatch(
updateProductMilestone(
productId,
Expand Down
2 changes: 1 addition & 1 deletion src/projects/actions/projectDashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const getDashboardData = (dispatch, getState, projectId, isOnlyLoadProjectInfo)
}

// for new projects load phases, products, project template and product templates
if (project.version === 'v3') {
if (['v3', 'v4'].indexOf(project.version) !== -1) {
promises.push(
dispatch(loadProjectPlan(projectId, userIds))
)
Expand Down
2 changes: 1 addition & 1 deletion src/projects/components/projectsCard/ProjectCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function ProjectCard({ project, disabled, currentUser, history, onChangeStatus,
const isMember = _.some(project.members, m => (m.userId === currentUser.userId && m.deletedAt === null))
// check whether has pending invition
const isInvited = _.some(project.invites, m => ((m.userId === currentUser.userId || m.email === currentUser.email) && !m.deletedAt && m.status === 'pending'))
const projectDetailsURL = project.version === 'v3'
const projectDetailsURL = ['v3', 'v4'].includes(project.version)
? `/projects/${project.id}/scope`
: `/projects/${project.id}/specification`

Expand Down
2 changes: 1 addition & 1 deletion src/projects/components/projectsCard/ProjectCardBody.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function ProjectCardBody({ project, descLinesCount = 8,

const progress = _.get(process, 'percent', 0)

const projectDetailsURL = project.version === 'v3'
const projectDetailsURL = ['v3', 'v4'].includes(project.version)
? `/projects/${project.id}/scope`
: `/projects/${project.id}/specification`

Expand Down
4 changes: 3 additions & 1 deletion src/projects/create/containers/CreateContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,10 @@ class CreateContainer extends React.Component {
}
_.set(project, 'details.utm.google', googleAnalytics)
}
const searchParams = new URLSearchParams(window.location.search)
const isBetaMode = searchParams.get('beta') === 'true'
if (projectTemplate) {
project.version = 'v3'
project.version = isBetaMode ? 'v4' : 'v3'
project.templateId = projectTemplate.id
project.type = projectTemplate.category
}
Expand Down
2 changes: 1 addition & 1 deletion src/projects/detail/ProjectDetail.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ class ProjectDetail extends Component {
// if project version not v3 , URL /scope redirect to /specification
if(project
&& project.version
&& project.version !== 'v3'
&& !['v3', 'v4'].includes(project.version)
&& project.id === parseInt(match.params.projectId)
&& this.props.history.location.pathname.indexOf('/scope') !== -1 ){
this.props.history.push(this.props.history.location.pathname.replace('/scope', '/specification'))
Expand Down
Loading