From 9adc5876a217254cee1f8130ab12e1813ce1d90c Mon Sep 17 00:00:00 2001 From: maxceem Date: Sat, 12 Dec 2020 16:50:11 +0200 Subject: [PATCH 01/23] chore: deploy 'feature/taas-jobs-2' --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 897301638..e9b9fb9e5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -128,7 +128,7 @@ workflows: - build-dev filters: branches: - only: ['dev'] + only: ['dev', 'feature/taas-jobs-2'] - deployTest01: context : org-global From 478debac3cd87db98a56ee51ada9f23ea09c8839 Mon Sep 17 00:00:00 2001 From: Vigneshkumar Chinnachamy M Date: Sun, 13 Dec 2020 02:36:22 +0530 Subject: [PATCH 02/23] load and cache all skills for skills question --- src/api/skills.js | 48 +++++++++++++++++++ .../SkillsQuestion/SkillsQuestionBase.jsx | 28 ++++------- 2 files changed, 57 insertions(+), 19 deletions(-) create mode 100644 src/api/skills.js diff --git a/src/api/skills.js b/src/api/skills.js new file mode 100644 index 000000000..d912a1572 --- /dev/null +++ b/src/api/skills.js @@ -0,0 +1,48 @@ +import { TC_API_URL, SKILL_PROVIDER_ID } from '../config/constants' +import { axiosInstance as axios } from './requestInterceptor' + +const skillPageSize = 100 +let cachedSkillsAsPromise + +/** + * Loads and caches all the skills the first time. Returns the skills list from the cache from the second time. + */ +export function getSkills() { + cachedSkillsAsPromise = cachedSkillsAsPromise || getAllSkills().catch(ex => { + console.error('Error loading skills', ex) + cachedSkillsAsPromise = null + }) + + return cachedSkillsAsPromise +} + +/** + * Recursively loads all the pages from skills api. + */ +function getAllSkills() { + let skills = [] + + return new Promise((resolve, reject) => { + const loop = (page) => getSkillsPage(page) + .then((skillResponse) => { + skills = skills.concat(skillResponse.data) + if (skillResponse.data.length === skillPageSize) { + page++ + loop(page) + } else { + resolve(skills) + } + }) + .catch(ex => reject(ex)) + + loop(1) + }) +} + +/** + * Loads the skills in the given page. + * @param {number} page The page number to load + */ +function getSkillsPage(page) { + return axios.get(`${TC_API_URL}/v5/skills?skillProviderId=${SKILL_PROVIDER_ID}&perPage=${skillPageSize}&orderBy=name&page=${page}`) +} \ No newline at end of file diff --git a/src/projects/detail/components/SkillsQuestion/SkillsQuestionBase.jsx b/src/projects/detail/components/SkillsQuestion/SkillsQuestionBase.jsx index 684f11c0a..2c99acac5 100644 --- a/src/projects/detail/components/SkillsQuestion/SkillsQuestionBase.jsx +++ b/src/projects/detail/components/SkillsQuestion/SkillsQuestionBase.jsx @@ -3,11 +3,8 @@ import _ from 'lodash' import SkillsCheckboxGroup from './SkillsCheckboxGroup' import Select from '../../../../components/Select/Select' import './SkillsQuestion.scss' -import { axiosInstance as axios } from '../../../../api/requestInterceptor' -import { TC_API_URL, SKILL_PROVIDER_ID } from '../../../../config/constants' import { createFilter } from 'react-select' - -let cachedOptions +import { getSkills } from '../../../../api/skills' /** * If `categoriesMapping` is defined - filter options using selected categories. @@ -42,7 +39,7 @@ class SkillsQuestion extends React.PureComponent { constructor(props) { super(props) this.state = { - options: cachedOptions || [], + options: [], availableOptions: [], customOptionValue: '', } @@ -51,20 +48,13 @@ class SkillsQuestion extends React.PureComponent { } componentWillMount() { - if (!cachedOptions) { - axios.get(`${TC_API_URL}/v5/skills?skillProviderId=${SKILL_PROVIDER_ID}&perPage=100&orderBy=name`) - .then(resp => { - const options = _.get(resp, 'data', []) - - cachedOptions = options.map((option) => ({ - skillId: option.id, - name: option.name - })) - this.updateOptions(cachedOptions) - }) - } else { - this.updateOptions(cachedOptions) - } + getSkills().then(skills => { + const options = skills.map(skill => ({ + skillId: skill.id, + name: skill.name + })) + this.updateOptions(options) + }) } componentWillReceiveProps(nextProps) { From ad04c7bd8e40dab496f6a685539fd4a90fd688d5 Mon Sep 17 00:00:00 2001 From: Vigneshkumar Chinnachamy M Date: Sun, 13 Dec 2020 02:38:34 +0530 Subject: [PATCH 03/23] add new line at the end of the file - skills.js --- src/api/skills.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/skills.js b/src/api/skills.js index d912a1572..892c3716a 100644 --- a/src/api/skills.js +++ b/src/api/skills.js @@ -45,4 +45,4 @@ function getAllSkills() { */ function getSkillsPage(page) { return axios.get(`${TC_API_URL}/v5/skills?skillProviderId=${SKILL_PROVIDER_ID}&perPage=${skillPageSize}&orderBy=name&page=${page}`) -} \ No newline at end of file +} From 89359de54cee8708a16147388b970a7dff5cf58c Mon Sep 17 00:00:00 2001 From: Vigneshkumar Chinnachamy M Date: Sun, 13 Dec 2020 18:57:18 +0530 Subject: [PATCH 04/23] handle error while loading skills --- src/api/skills.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/skills.js b/src/api/skills.js index 892c3716a..aa5cc4529 100644 --- a/src/api/skills.js +++ b/src/api/skills.js @@ -11,6 +11,7 @@ export function getSkills() { cachedSkillsAsPromise = cachedSkillsAsPromise || getAllSkills().catch(ex => { console.error('Error loading skills', ex) cachedSkillsAsPromise = null + return []; }) return cachedSkillsAsPromise From 5779223ed10d7150267779dc6502ad0c7d3e822b Mon Sep 17 00:00:00 2001 From: maxceem Date: Mon, 14 Dec 2020 11:00:56 +0200 Subject: [PATCH 05/23] fix: lint --- src/api/skills.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/skills.js b/src/api/skills.js index aa5cc4529..5f4ce55f8 100644 --- a/src/api/skills.js +++ b/src/api/skills.js @@ -11,7 +11,7 @@ export function getSkills() { cachedSkillsAsPromise = cachedSkillsAsPromise || getAllSkills().catch(ex => { console.error('Error loading skills', ex) cachedSkillsAsPromise = null - return []; + return [] }) return cachedSkillsAsPromise From 5ae825c62dccb1c782671ef87e79b660fedaf42a Mon Sep 17 00:00:00 2001 From: maxceem Date: Mon, 14 Dec 2020 11:01:43 +0200 Subject: [PATCH 06/23] chore: deploy 'feature/taas-jobs-2' to TEST01 --- .circleci/config.yml | 4 ++-- config/constants/dev.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e9b9fb9e5..a32f2f31f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -128,7 +128,7 @@ workflows: - build-dev filters: branches: - only: ['dev', 'feature/taas-jobs-2'] + only: ['dev'] - deployTest01: context : org-global @@ -136,7 +136,7 @@ workflows: - build-dev filters: branches: - only: ['feature/unified-permissions', 'feature/accept-reject-terms-in-profile'] + only: ['feature/taas-jobs-2'] - deployProd: context : org-global diff --git a/config/constants/dev.js b/config/constants/dev.js index 77511f506..17bb03fbc 100644 --- a/config/constants/dev.js +++ b/config/constants/dev.js @@ -30,8 +30,8 @@ module.exports = { TCO17_URL : 'https://tco17.topcoder-dev.com', TCO_HOME_URL : 'https://www.topcoder-dev.com/tco', - ACCOUNTS_APP_URL : 'https://accounts-auth0.topcoder-dev.com', - ACCOUNTS_APP_CONNECTOR_URL : 'https://accounts-auth0.topcoder-dev.com', + ACCOUNTS_APP_URL : 'http://localhost:5000', + ACCOUNTS_APP_CONNECTOR_URL : 'http://localhost:5000', FILE_PICKER_API_KEY: process.env.FILE_PICKER_API_KEY_DEV, FILE_PICKER_SUBMISSION_CONTAINER_NAME: 'submission-staging-dev', From 68aebd6ee6c0eef4a0f5195636bedd7a00b52eb0 Mon Sep 17 00:00:00 2001 From: maxceem Date: Tue, 15 Dec 2020 18:43:47 +0200 Subject: [PATCH 07/23] fix: update TaaS URL --- config/constants/dev.js | 2 +- config/constants/master.js | 2 +- config/constants/qa.js | 2 +- src/config/constants.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/constants/dev.js b/config/constants/dev.js index 17bb03fbc..cd777e241 100644 --- a/config/constants/dev.js +++ b/config/constants/dev.js @@ -56,5 +56,5 @@ module.exports = { CONTENTFUL_SPACE_ID : process.env.CONTENTFUL_SPACE_ID, SKILL_PROVIDER_ID: '9cc0795a-6e12-4c84-9744-15858dba1861', - TAAS_APP_URL: 'https://mfe.topcoder-dev.com/taas' + TAAS_APP_URL: 'https://platform.topcoder-dev.com/taas' } diff --git a/config/constants/master.js b/config/constants/master.js index 96b9f8a47..5301b61ad 100644 --- a/config/constants/master.js +++ b/config/constants/master.js @@ -56,5 +56,5 @@ module.exports = { CONTENTFUL_SPACE_ID : process.env.CONTENTFUL_SPACE_ID, SKILL_PROVIDER_ID: 'e8467a61-7e20-4ed2-a839-c6340d90f408', - TAAS_APP_URL: 'https://mfe.topcoder.com/taas' + TAAS_APP_URL: 'https://platform.topcoder.com/taas' } diff --git a/config/constants/qa.js b/config/constants/qa.js index b46a3ca89..13b16c3e9 100644 --- a/config/constants/qa.js +++ b/config/constants/qa.js @@ -51,5 +51,5 @@ module.exports = { TC_CDN_URL: process.env.TC_CDN_URL, SKILL_PROVIDER_ID: '9cc0795a-6e12-4c84-9744-15858dba1861', - TAAS_APP_URL: 'https://mfe.topcoder-dev.com/taas' + TAAS_APP_URL: 'https://platform.topcoder-dev.com/taas' } diff --git a/src/config/constants.js b/src/config/constants.js index 54a553bba..3a534d4cb 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -1103,4 +1103,4 @@ export const PROJECT_TYPE_TALENT_AS_A_SERVICE = 'talent-as-a-service' /** * URL to the Topcoder TaaS App */ -export const TAAS_APP_URL = process.env.TAAS_APP_URL || 'https://mfe.topcoder-dev.com/taas' +export const TAAS_APP_URL = process.env.TAAS_APP_URL || 'https://platform.topcoder-dev.com/taas' From 75ffc0ac146fee30543b837d31a3e98437728703 Mon Sep 17 00:00:00 2001 From: maxceem Date: Wed, 6 Jan 2021 18:57:33 +0200 Subject: [PATCH 08/23] fix use DEV auth instead of local --- config/constants/dev.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/constants/dev.js b/config/constants/dev.js index eaf37c6e4..495577f40 100644 --- a/config/constants/dev.js +++ b/config/constants/dev.js @@ -30,8 +30,8 @@ module.exports = { TCO17_URL : 'https://tco17.topcoder-dev.com', TCO_HOME_URL : 'https://www.topcoder-dev.com/tco', - ACCOUNTS_APP_URL : 'http://localhost:5000', - ACCOUNTS_APP_CONNECTOR_URL : 'http://localhost:5000', + ACCOUNTS_APP_URL : 'https://accounts-auth0.topcoder-dev.com', + ACCOUNTS_APP_CONNECTOR_URL : 'https://accounts-auth0.topcoder-dev.com', FILE_PICKER_API_KEY: process.env.FILE_PICKER_API_KEY_DEV, FILE_PICKER_SUBMISSION_CONTAINER_NAME: 'submission-staging-dev', From 3051ef4c250bca7c42c209d648a259fae35a46a0 Mon Sep 17 00:00:00 2001 From: maxceem Date: Wed, 6 Jan 2021 22:47:46 +0200 Subject: [PATCH 09/23] fix: showing all the skills --- config/constants/dev.js | 1 - config/constants/master.js | 1 - config/constants/qa.js | 1 - src/api/skills.js | 4 ++-- .../detail/components/SkillsQuestion/SkillsQuestionBase.jsx | 4 ++++ 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/config/constants/dev.js b/config/constants/dev.js index 495577f40..4c84dad0a 100644 --- a/config/constants/dev.js +++ b/config/constants/dev.js @@ -56,6 +56,5 @@ module.exports = { CONTENTFUL_DELIVERY_KEY : process.env.CONTENTFUL_DELIVERY_KEY, CONTENTFUL_SPACE_ID : process.env.CONTENTFUL_SPACE_ID, - SKILL_PROVIDER_ID: '9cc0795a-6e12-4c84-9744-15858dba1861', TAAS_APP_URL: 'https://platform.topcoder-dev.com/taas' } diff --git a/config/constants/master.js b/config/constants/master.js index e11157537..12d635aa3 100644 --- a/config/constants/master.js +++ b/config/constants/master.js @@ -56,6 +56,5 @@ module.exports = { CONTENTFUL_DELIVERY_KEY : process.env.CONTENTFUL_DELIVERY_KEY, CONTENTFUL_SPACE_ID : process.env.CONTENTFUL_SPACE_ID, - SKILL_PROVIDER_ID: 'e8467a61-7e20-4ed2-a839-c6340d90f408', TAAS_APP_URL: 'https://platform.topcoder.com/taas' } diff --git a/config/constants/qa.js b/config/constants/qa.js index 40b0e6062..5cf3c2ea9 100644 --- a/config/constants/qa.js +++ b/config/constants/qa.js @@ -51,6 +51,5 @@ module.exports = { TC_CDN_URL: process.env.TC_CDN_URL, - SKILL_PROVIDER_ID: '9cc0795a-6e12-4c84-9744-15858dba1861', TAAS_APP_URL: 'https://platform.topcoder-dev.com/taas' } diff --git a/src/api/skills.js b/src/api/skills.js index 5f4ce55f8..cdb90e2ef 100644 --- a/src/api/skills.js +++ b/src/api/skills.js @@ -1,4 +1,4 @@ -import { TC_API_URL, SKILL_PROVIDER_ID } from '../config/constants' +import { TC_API_URL } from '../config/constants' import { axiosInstance as axios } from './requestInterceptor' const skillPageSize = 100 @@ -45,5 +45,5 @@ function getAllSkills() { * @param {number} page The page number to load */ function getSkillsPage(page) { - return axios.get(`${TC_API_URL}/v5/skills?skillProviderId=${SKILL_PROVIDER_ID}&perPage=${skillPageSize}&orderBy=name&page=${page}`) + return axios.get(`${TC_API_URL}/v5/taas-teams/skills?perPage=${skillPageSize}&orderBy=name&page=${page}`) } diff --git a/src/projects/detail/components/SkillsQuestion/SkillsQuestionBase.jsx b/src/projects/detail/components/SkillsQuestion/SkillsQuestionBase.jsx index 69ddb48e1..96cf1acc6 100644 --- a/src/projects/detail/components/SkillsQuestion/SkillsQuestionBase.jsx +++ b/src/projects/detail/components/SkillsQuestion/SkillsQuestionBase.jsx @@ -18,6 +18,9 @@ import { getSkills } from '../../../../api/skills' * @returns {Array} available options */ const getAvailableOptions = (categoriesMapping, selectedCategories, skillsCategories, options) => { + // NOTE: + // Disable filtering skills by categories for now, because V5 Skills API doesn't have categories for now. + /* let mappedCategories if (categoriesMapping) { mappedCategories = _.map(selectedCategories, (category) => categoriesMapping[category] ? categoriesMapping[category].toLowerCase() : null) @@ -28,6 +31,7 @@ const getAvailableOptions = (categoriesMapping, selectedCategories, skillsCatego if (mappedCategories) { return options.filter(option => _.intersection((option.categories || []).map(c => c.toLowerCase()), mappedCategories).length > 0) } + */ return options } From 8e883e28eeb8169cf993d72512737dfaeceb0c64 Mon Sep 17 00:00:00 2001 From: maxceem Date: Wed, 6 Jan 2021 23:24:26 +0200 Subject: [PATCH 10/23] Revert "Revert "Merge pull request #4204 from appirio-tech/feature/taas-jobs"" This reverts commit 676ac05dae20eb2a430c43621ff68cdf4b7cadb5. # Conflicts: # config/constants/dev.js # config/constants/master.js # config/constants/qa.js # src/config/constants.js # src/projects/detail/components/SkillsQuestion/SkillsQuestionBase.jsx # src/projects/detail/containers/DashboardContainer.jsx --- src/config/constants.js | 2 +- .../create/components/ProjectSubmitted.jsx | 34 +++-- .../create/components/ProjectWizard.jsx | 3 - .../create/containers/CreateContainer.jsx | 3 +- .../SkillsQuestion/SkillsQuestionBase.jsx | 13 +- .../TaasProjectWelcome/TaasProjectWelcome.jsx | 14 +++ .../TaasProjectWelcome.scss | 15 +++ .../components/TaasProjectWelcome/index.js | 2 + .../TalentPickerQuestionV2.jsx | 6 +- .../detail/containers/DashboardContainer.jsx | 118 ++++++++++-------- 10 files changed, 134 insertions(+), 76 deletions(-) create mode 100644 src/projects/detail/components/TaasProjectWelcome/TaasProjectWelcome.jsx create mode 100644 src/projects/detail/components/TaasProjectWelcome/TaasProjectWelcome.scss create mode 100644 src/projects/detail/components/TaasProjectWelcome/index.js diff --git a/src/config/constants.js b/src/config/constants.js index 9eb69d37a..490ac76f1 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -729,7 +729,7 @@ export const SEGMENT_KEY = process.env.CONNECT_SEGMENT_KEY */ export const DOMAIN = process.env.domain || 'topcoder.com' export const CONNECT_DOMAIN = `connect.${DOMAIN}` -export const CONNECT_MAIN_PAGE_URL = `http://connect.${DOMAIN}` +export const CONNECT_MAIN_PAGE_URL = `https://connect.${DOMAIN}` export const ACCOUNTS_APP_CONNECTOR_URL = process.env.ACCOUNTS_APP_CONNECTOR_URL export const ACCOUNTS_APP_LOGIN_URL = process.env.ACCOUNTS_APP_LOGIN_URL || `https://accounts-auth0.${DOMAIN}` export const ACCOUNTS_APP_REGISTER_URL = process.env.ACCOUNTS_APP_REGISTER_URL || `https://accounts-auth0.${DOMAIN}` diff --git a/src/projects/create/components/ProjectSubmitted.jsx b/src/projects/create/components/ProjectSubmitted.jsx index 130007de3..9bde26a51 100644 --- a/src/projects/create/components/ProjectSubmitted.jsx +++ b/src/projects/create/components/ProjectSubmitted.jsx @@ -1,25 +1,40 @@ import React from 'react' import PT from 'prop-types' +import qs from 'query-string' require('./ProjectSubmitted.scss') import { - CONNECT_DOMAIN + CONNECT_MAIN_PAGE_URL, PROJECT_TYPE_TALENT_AS_A_SERVICE, TAAS_APP_URL } from '../../../config/constants' +/** + * Build project URL based on the `type` query param in URL. + * + * @param {String} projectId project id + */ +const formatProjectURL = (projectId) => { + const { type } = qs.parse(window.location.search) + + const url = type === PROJECT_TYPE_TALENT_AS_A_SERVICE + // if the project type is TaaS, then use link to TaaS App + ? `${TAAS_APP_URL}/myteams/${projectId}` + // otherwise use link inside Connect App + : `${CONNECT_MAIN_PAGE_URL}/projects/${projectId}` + + return url +} + class ProjectSubmitted extends React.Component { constructor(props) { super(props) this.copyToClipboard = this.copyToClipboard.bind(this) - this.state = { - domain: `${CONNECT_DOMAIN}/`, - url: `projects/${props.params.status || props.projectId}` - } } copyToClipboard() { + const url = formatProjectURL(this.props.params.status || this.props.projectId) const textField = document.createElement('textarea') - textField.innerText = `${this.state.domain}${this.state.url}` + textField.innerText = url document.body.appendChild(textField) textField.select() document.execCommand('copy') @@ -27,6 +42,8 @@ class ProjectSubmitted extends React.Component { } render() { + const url = formatProjectURL(this.props.params.status || this.props.projectId) + return (
@@ -39,11 +56,11 @@ class ProjectSubmitted extends React.Component { Use the link below to share your project with members of your team. You can also access all your Topcoder projects in one place from your Connect project dashboard.
- { `${this.state.domain}${this.state.url}` } + {url.replace('https://', '')}
@@ -52,7 +69,6 @@ class ProjectSubmitted extends React.Component { } ProjectSubmitted.defaultProps = { - vm: {}, params: {}, } diff --git a/src/projects/create/components/ProjectWizard.jsx b/src/projects/create/components/ProjectWizard.jsx index 0ca419fdc..b05edf01a 100644 --- a/src/projects/create/components/ProjectWizard.jsx +++ b/src/projects/create/components/ProjectWizard.jsx @@ -605,9 +605,6 @@ class ProjectWizard extends Component { />
diff --git a/src/projects/create/containers/CreateContainer.jsx b/src/projects/create/containers/CreateContainer.jsx index 0ee63d074..5e687c758 100644 --- a/src/projects/create/containers/CreateContainer.jsx +++ b/src/projects/create/containers/CreateContainer.jsx @@ -124,11 +124,12 @@ class CreateContainer extends React.Component { projectId: nextProjectId, isProjectDirty: false }, () => { + const type = _.get(this.state, 'updatedProject.type') // go to submitted state console.log('go to submitted state') window.localStorage.removeItem(LS_INCOMPLETE_PROJECT) window.localStorage.removeItem(LS_INCOMPLETE_WIZARD) - this.props.history.push('/new-project/submitted/' + nextProjectId) + this.props.history.push('/new-project/submitted/' + nextProjectId + (type ? `?type=${type}` : '')) }) } else if (this.state.creatingProject !== nextProps.processing) { diff --git a/src/projects/detail/components/SkillsQuestion/SkillsQuestionBase.jsx b/src/projects/detail/components/SkillsQuestion/SkillsQuestionBase.jsx index 96cf1acc6..9ed46d17f 100644 --- a/src/projects/detail/components/SkillsQuestion/SkillsQuestionBase.jsx +++ b/src/projects/detail/components/SkillsQuestion/SkillsQuestionBase.jsx @@ -74,7 +74,7 @@ class SkillsQuestion extends React.PureComponent { this.setState({ options }) this.updateAvailableOptions(this.props, options) if (onSkillsLoaded) { - onSkillsLoaded(options.map((option) => _.pick(option, ['id', 'name']))) + onSkillsLoaded(options) } } @@ -90,7 +90,6 @@ class SkillsQuestion extends React.PureComponent { // if have a mapping for categories, then filter options, otherwise use all options const availableOptions = getAvailableOptions(categoriesMapping, selectedCategories, skillsCategories, options) - .map(option => _.pick(option, ['id', 'name'])) this.setState({ availableOptions }) } @@ -179,17 +178,17 @@ class SkillsQuestion extends React.PureComponent { const selectedCategories = _.get(currentProjectData, categoriesField, []) let currentValues = getValue() || [] - // remove from currentValues not available options but still keep created custom options without id - currentValues = currentValues.filter(skill => _.some(availableOptions, skill) || !skill.id) + // remove from currentValues not available options but still keep created custom options without skillId + currentValues = currentValues.filter(skill => _.some(availableOptions, skill) || !skill.skillId) const questionDisabled = isFormDisabled() || disabled || (selectedCategories.length === 0 && _.isUndefined(skillsCategories)) const hasError = !isPristine() && !isValid() const errorMessage = getErrorMessage() || validationError - const checkboxGroupOptions = availableOptions.filter(option => frequentSkills.indexOf(option.id) > -1) - const checkboxGroupValues = currentValues.filter(val => _.some(checkboxGroupOptions, option => option.id === val.id )) + const checkboxGroupOptions = availableOptions.filter(option => frequentSkills.indexOf(option.skillId) > -1) + const checkboxGroupValues = currentValues.filter(val => _.some(checkboxGroupOptions, option => option.skillId === val.skillId )) - const selectGroupOptions = availableOptions.filter(option => frequentSkills.indexOf(option.id) === -1) + const selectGroupOptions = availableOptions.filter(option => frequentSkills.indexOf(option.skillId) === -1) if (customOptionValue) { selectGroupOptions.unshift({ name: customOptionValue }) } diff --git a/src/projects/detail/components/TaasProjectWelcome/TaasProjectWelcome.jsx b/src/projects/detail/components/TaasProjectWelcome/TaasProjectWelcome.jsx new file mode 100644 index 000000000..28217e0f3 --- /dev/null +++ b/src/projects/detail/components/TaasProjectWelcome/TaasProjectWelcome.jsx @@ -0,0 +1,14 @@ +import React from 'react' +import { TAAS_APP_URL } from '../../../../../config/constants/dev' +import './TaasProjectWelcome.scss' + +const TaasProjectWelcome = ({ projectId }) => { + const url = `${TAAS_APP_URL}/myteams/${projectId}` + return ( + + ) +} + +export default TaasProjectWelcome diff --git a/src/projects/detail/components/TaasProjectWelcome/TaasProjectWelcome.scss b/src/projects/detail/components/TaasProjectWelcome/TaasProjectWelcome.scss new file mode 100644 index 000000000..e0ed62c21 --- /dev/null +++ b/src/projects/detail/components/TaasProjectWelcome/TaasProjectWelcome.scss @@ -0,0 +1,15 @@ +@import '~tc-ui/src/styles/tc-includes'; +@import '../../../../styles/includes'; + +.container { + align-items: center; + display: flex; + justify-content: center; + height: 400px; + + :global(.tc-btn-lg) { + height: 70px; + line-height: 68px; + font-size: 30px; + } +} diff --git a/src/projects/detail/components/TaasProjectWelcome/index.js b/src/projects/detail/components/TaasProjectWelcome/index.js new file mode 100644 index 000000000..96117cea1 --- /dev/null +++ b/src/projects/detail/components/TaasProjectWelcome/index.js @@ -0,0 +1,2 @@ +import TaasProjectWelcome from './TaasProjectWelcome' +export default TaasProjectWelcome diff --git a/src/projects/detail/components/TalentPickerQuestion/TalentPickerQuestionV2.jsx b/src/projects/detail/components/TalentPickerQuestion/TalentPickerQuestionV2.jsx index 5a65a60c9..a37755209 100644 --- a/src/projects/detail/components/TalentPickerQuestion/TalentPickerQuestionV2.jsx +++ b/src/projects/detail/components/TalentPickerQuestion/TalentPickerQuestionV2.jsx @@ -70,6 +70,7 @@ class TalentPickerQuestionV2 extends Component { getDefaultValue() { const { options } = this.props return options.map((o) => ({ + roleTitle: o.roleTitle, role: o.role, people: '0', duration: '0', @@ -96,13 +97,16 @@ class TalentPickerQuestionV2 extends Component { } insertRole(index, role) { - const { getValue } = this.props + const { getValue, options } = this.props let values = getValue() || this.getDefaultValue() + const roleOption = _.find(options, { role }) + values = [ ...values.slice(0, index), { role, + roleTitle: roleOption.roleTitle, people: '0', duration: '0', skills: [], diff --git a/src/projects/detail/containers/DashboardContainer.jsx b/src/projects/detail/containers/DashboardContainer.jsx index 4555b96f7..693fee77d 100644 --- a/src/projects/detail/containers/DashboardContainer.jsx +++ b/src/projects/detail/containers/DashboardContainer.jsx @@ -40,6 +40,7 @@ import SystemFeed from '../../../components/Feed/SystemFeed' import ProjectScopeDrawer from '../components/ProjectScopeDrawer' import ProjectStages from '../components/ProjectStages' import ProjectPlanEmpty from '../components/ProjectPlanEmpty' +import TaasProjectWelcome from '../components/TaasProjectWelcome' import NotificationsReader from '../../../components/NotificationsReader' import { hasPermission } from '../../../helpers/permissions' import { getProjectTemplateById } from '../../../helpers/templates' @@ -60,6 +61,7 @@ import { PHASE_STATUS_DRAFT, SCREEN_BREAKPOINT_MD, CODER_BOT_USERID, + PROJECT_TYPE_TALENT_AS_A_SERVICE, PHASE_PRODUCT_TEMPLATE_ID } from '../../../config/constants' @@ -179,6 +181,8 @@ class DashboardContainer extends React.Component { const isProjectLive = project.status !== PROJECT_STATUS_COMPLETED && project.status !== PROJECT_STATUS_CANCELLED + const isTaasProject = project.type === PROJECT_TYPE_TALENT_AS_A_SERVICE + const leftArea = ( - {unreadProjectUpdate.length > 0 && - - } - {/* */} - {!!estimationQuestion && - - } - {/* The following containerStyle and overlayStyle are needed for shrink drawer and overlay size for not - covering sidebar and topbar - */} - this.setState({open})} - project={project} - template={template} - updateProject={updateProject} - processing={isProcessing} - fireProjectDirty={fireProjectDirty} - fireProjectDirtyUndo= {fireProjectDirtyUndo} - addProjectAttachment={addProjectAttachment} - updateProjectAttachment={updateProjectAttachment} - removeProjectAttachment={removeProjectAttachment} - productTemplates={productTemplates} - productCategories={productCategories} - /> - - {visiblePhases && visiblePhases.length > 0 ? ( - + {isTaasProject ? ( + ) : ( - - )} - {isCreatingPhase? : null} - {isProjectLive && !isCreatingPhase && hasPermission(PERMISSIONS.MANAGE_PROJECT_PLAN) && !isLoadingPhases && ( - +
+ {unreadProjectUpdate.length > 0 && + + } + {/* */} + {!!estimationQuestion && + + } + {/* The following containerStyle and overlayStyle are needed for shrink drawer and overlay size for not + covering sidebar and topbar + */} + this.setState({open})} + project={project} + template={template} + updateProject={updateProject} + processing={isProcessing} + fireProjectDirty={fireProjectDirty} + fireProjectDirtyUndo= {fireProjectDirtyUndo} + addProjectAttachment={addProjectAttachment} + updateProjectAttachment={updateProjectAttachment} + removeProjectAttachment={removeProjectAttachment} + productTemplates={productTemplates} + productCategories={productCategories} + /> + + {visiblePhases && visiblePhases.length > 0 ? ( + + ) : ( + + )} + {isCreatingPhase? : null} + {isProjectLive && !isCreatingPhase && hasPermission(PERMISSIONS.MANAGE_PROJECT_PLAN) && !isLoadingPhases && ( + + )} +
)}
From dd7b0f715ce210e6b368b0a3aa7b7313c62ab4b2 Mon Sep 17 00:00:00 2001 From: maxceem Date: Wed, 6 Jan 2021 23:34:16 +0200 Subject: [PATCH 11/23] fix: lint --- .../detail/containers/DashboardContainer.jsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/projects/detail/containers/DashboardContainer.jsx b/src/projects/detail/containers/DashboardContainer.jsx index 693fee77d..43420918e 100644 --- a/src/projects/detail/containers/DashboardContainer.jsx +++ b/src/projects/detail/containers/DashboardContainer.jsx @@ -270,17 +270,17 @@ class DashboardContainer extends React.Component { productCategories={productCategories} /> - {visiblePhases && visiblePhases.length > 0 ? ( - - ) : ( - - )} + {visiblePhases && visiblePhases.length > 0 ? ( + + ) : ( + + )} {isCreatingPhase? : null} {isProjectLive && !isCreatingPhase && hasPermission(PERMISSIONS.MANAGE_PROJECT_PLAN) && !isLoadingPhases && ( Date: Wed, 6 Jan 2021 09:39:33 +0800 Subject: [PATCH 12/23] fix: #4206 --- .../components/JobPickerRow/JobPickerRow.jsx | 285 ++++++++++++++++++ .../components/JobPickerRow/JobPickerRow.scss | 146 +++++++++ .../JobsPickerQuestion/JobsPickerQuestion.jsx | 146 +++++++++ .../JobsPickerQuestion.scss | 8 + .../detail/components/SpecQuestions.jsx | 6 +- 5 files changed, 590 insertions(+), 1 deletion(-) create mode 100644 src/projects/detail/components/JobPickerRow/JobPickerRow.jsx create mode 100644 src/projects/detail/components/JobPickerRow/JobPickerRow.scss create mode 100644 src/projects/detail/components/JobsPickerQuestion/JobsPickerQuestion.jsx create mode 100644 src/projects/detail/components/JobsPickerQuestion/JobsPickerQuestion.scss diff --git a/src/projects/detail/components/JobPickerRow/JobPickerRow.jsx b/src/projects/detail/components/JobPickerRow/JobPickerRow.jsx new file mode 100644 index 000000000..0d8b1b324 --- /dev/null +++ b/src/projects/detail/components/JobPickerRow/JobPickerRow.jsx @@ -0,0 +1,285 @@ +import React from 'react' +import PT from 'prop-types' +import cn from 'classnames' + +import IconX from '../../../../assets/icons/ui-16px-1_bold-remove.svg' +import IconAdd from '../../../../assets/icons/ui-16px-1_bold-add.svg' +import SkillsQuestion from '../SkillsQuestion/SkillsQuestionBase' +import PositiveNumberInput from '../../../../components/PositiveNumberInput/PositiveNumberInput' +import SelectDropdown from 'appirio-tech-react-components/components/SelectDropdown/SelectDropdown' + +import styles from './JobPickerRow.scss' + +const always = () => true +const never = () => false +const emptyError = () => '' + +class JobPickerRow extends React.PureComponent { + constructor(props) { + super(props) + + this.handlePeopleChange = this.handlePeopleChange.bind(this) + this.handleDurationChange = this.handleDurationChange.bind(this) + this.handleSkillChange = this.handleSkillChange.bind(this) + this.handleJobNameChange = this.handleJobNameChange.bind(this) + this.handleRoleChange = this.handleRoleChange.bind(this) + this.handleWorkloadChange = this.handleWorkloadChange.bind(this) + this.handleJobDescriptionChange = this.handleJobDescriptionChange.bind(this) + + this.resetPeople = this.resetPeople.bind(this) + this.resetDuration = this.resetDuration.bind(this) + + this.onAddRow = this.onAddRow.bind(this) + this.onDeleteRow = this.onDeleteRow.bind(this) + + this.workloadOptions = [ + { value: null, title: 'Select Workload'}, + { value: 'fulltime', title: 'Full-Time'}, + { value: 'fractional', title: 'Fractional'} + ] + + this.roleOptions = [ + { value: null, title: 'Select Role'}, + { value: 'designer', title: 'Designer'}, + { value: 'software-developer', title: 'Software Developer'}, + { value: 'data-scientist', title: 'Data Scientist'}, + { value: 'data-engineer', title: 'Data Engineer'}, + { value: 'qa', title: 'QA Tester'}, + { value: 'qa-engineer', title: 'QA Engineer'} + ] + } + handleJobNameChange(evt) { + this.props.onChange(this.props.rowIndex, 'name', evt.target.value) + } + handlePeopleChange(evt) { + this.props.onChange(this.props.rowIndex, 'people', evt.target.value) + } + + handleDurationChange(evt) { + this.props.onChange(this.props.rowIndex, 'duration', evt.target.value) + } + + handleSkillChange(value) { + this.props.onChange(this.props.rowIndex, 'skills', value) + } + + handleWorkloadChange(evt) { + this.props.onChange(this.props.rowIndex, 'workLoad', evt) + } + + handleRoleChange(evt) { + this.props.onChange(this.props.rowIndex, 'role', evt) + } + + handleJobDescriptionChange(evt) { + this.props.onChange(this.props.rowIndex, 'jobDescription', evt.target.value) + } + + resetDuration() { + const { rowIndex, onChange, value } = this.props + if (!value.duration) { + onChange(rowIndex, 'duration', '0') + } + } + + resetPeople() { + const { rowIndex, onChange, value } = this.props + if (!value.people) { + onChange(rowIndex, 'people', '0') + } + } + + onAddRow() { + const { rowIndex, value, onAddRow: addRowHandler } = this.props + addRowHandler(rowIndex + 1, value.role) + } + + onDeleteRow() { + const { rowIndex, onDeleteRow: deleteRowHandler } = this.props + deleteRowHandler(rowIndex) + } + + render() { + const { value, rowIndex } = this.props + const isRowIncomplete = value.name.length > 0 || value.people > 0 || value.duration > 0 || (value.skills && value.skills.length) + ||(value.role && value.role.value !== null) ||(value.workLoad && value.workLoad.value !== null) || (value.jobDescription.length > 0) + + /* Different columns are defined here and used in componsing mobile/desktop views below */ + const titleColumn = ( +
+
+ + +
+
+ ) + + const actionsColumn = ( +
+
+
+ +
+ { rowIndex > 0 && ( +
+ +
+ )} +
+
+ ) + + const peopleColumn = ( +
+ + +
+ ) + + const durationColumn = ( +
+ + +
+ ) + + const skillSelectionColumn = ( +
+ + {/* + Please do not refactor getValue prop's value to a binded function with constant reference. + SkillsQuestion is a pure component. If all the props are constant across renders, SkillsQuestion cannot detect the change in value.skills. + So, it'll break the functionality of the component. + "getValue" prop is left as inline arrow function to trigger re rendering of the SkillsQuestion component whenever the parent rerenders. + */} + value.skills} + onChange={_.noop} + selectWrapperClass={cn(styles.noMargin, {[styles.skillHasError]: isRowIncomplete && !(value.skills && value.skills.length)})} + /> +
+ ) + + const workLoadColumn = ( +
+ + +
+ ) + + const roleColumn = ( +
+ + +
+ ) + const jobDescriptionColumn = ( +
+ +
+