Skip to content

[PROD RELEASE] - WorkManager Changes - Connect Decommission #1631

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 34 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ff855cf
Allow hyphen in url - asset library
Mar 26, 2025
a70e1a5
git copilot suggestion
Mar 26, 2025
4d24155
Redo the fix with minimal change
Mar 26, 2025
6a43f63
Codeql test
Mar 26, 2025
619b5c0
re-iterate with codeql
Mar 26, 2025
1dee45f
Retest performance
Mar 26, 2025
a0fe205
Potential fix for code scanning alert no. 27: Inefficient regular exp…
himaniraghav3 Mar 26, 2025
374be0c
revert codeql suggestion
Mar 26, 2025
c7d59d7
Merge pull request #1621 from topcoder-platform/PM-971
himaniraghav3 Mar 26, 2025
1b719fb
feat: added show only my projects for project managers
hentrymartin Mar 27, 2025
441e6d7
fix: removed console log
hentrymartin Mar 27, 2025
592a0f3
fix: lint
hentrymartin Mar 27, 2025
4fd1543
PM-973 - move add user to own component
vas3a Mar 28, 2025
81a1173
PM-973 - invite user modal
vas3a Mar 28, 2025
06ab559
PM-973 - invite by email
vas3a Mar 30, 2025
90f0395
Merge pull request #1622 from topcoder-platform/pm-974_1
hentrymartin Mar 31, 2025
41329e1
feat: allow PM to view users and delete users from project
hentrymartin Apr 2, 2025
7eccfe3
fix: all projects challenges
hentrymartin Apr 3, 2025
18768fd
Merge pull request #1624 from topcoder-platform/pm-974_2
hentrymartin Apr 3, 2025
592b787
PM-973 - add invitation dialog after user accepts invitation through …
vas3a Apr 7, 2025
5823808
Merge remote-tracking branch 'origin/develop' into PM-973_invite-by-mail
vas3a Apr 7, 2025
b184e86
fix: projects list in challenges tab
hentrymartin Apr 7, 2025
125cf7d
Merge pull request #1625 from topcoder-platform/pm-974_3
hentrymartin Apr 7, 2025
8af3cf0
Merge pull request #1623 from topcoder-platform/PM-973_invite-by-mail
vas3a Apr 8, 2025
9605fa2
add AI PR Reviewer action
kkartunov Apr 8, 2025
530c136
rename job
kkartunov Apr 8, 2025
3ddfca7
adds clear cache step
kkartunov Apr 8, 2025
cf7491a
workflow update
kkartunov Apr 8, 2025
eedc3ff
add @master ref
kkartunov Apr 8, 2025
ac1de1a
job rename
kkartunov Apr 8, 2025
cf73dbc
restore name
kkartunov Apr 8, 2025
392e5f4
add missing assets
vas3a Apr 8, 2025
de59094
Merge pull request #1629 from topcoder-platform/PM-973_invite-by-mail
vas3a Apr 8, 2025
52fb0ab
code review permissions
kkartunov Apr 8, 2025
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
22 changes: 22 additions & 0 deletions .github/workflows/code_reviewer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: AI PR Reviewer

on:
pull_request:
types:
- opened
- synchronize
permissions:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change from permissions: write-all to specifying pull-requests: write is more restrictive, which is generally a good practice for security. However, ensure that this change does not inadvertently remove necessary permissions for other actions that might be required by the workflow. Double-check if additional permissions are needed for other parts of the workflow.

pull-requests: write
jobs:
tc-ai-pr-review:
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v3

- name: TC AI PR Reviewer
uses: topcoder-platform/tc-ai-pr-reviewer@master
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # The GITHUB_TOKEN is there by default so you just need to keep it like it is and not necessarily need to add it as secret as it will throw an error. [More Details](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#about-the-github_token-secret)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment about the GITHUB_TOKEN is informative but might be better placed in documentation or a README file rather than in the workflow file itself. Consider removing it from here to keep the workflow file clean.

LAB45_API_KEY: ${{ secrets.LAB45_API_KEY }}
exclude: "**/*.json, **/*.md" # Optional: exclude patterns separated by commas
Binary file added public/static/comment.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/static/logo.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 6 additions & 2 deletions src/actions/challenges.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import {
} from '../config/constants'
import { loadProject } from './projects'
import { removeChallengeFromPhaseProduct, saveChallengeAsPhaseProduct } from '../services/projects'
import { checkAdmin } from '../util/tc'
import { checkAdmin, checkManager } from '../util/tc'

/**
* Member challenges related redux actions
Expand Down Expand Up @@ -159,7 +159,11 @@ export function loadChallengesByPage (
filters['projectId'] = projectId
} else if (_.isObject(projectId) && projectId.value > 0) {
filters['projectId'] = projectId.value
} else if (!checkAdmin(getState().auth.token) && userId) {
} else if (
!checkAdmin(getState().auth.token) &&
!checkManager(getState().auth.token) &&
userId
) {
// Note that we only add the memberId field if *no* project ID is given,
// so that the list of *all challenges shows only those that the member is on
filters['memberId'] = userId
Expand Down
4 changes: 2 additions & 2 deletions src/actions/projects.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
fetchMemberProjects,
updateProjectApi
} from '../services/projects'
import { checkAdmin } from '../util/tc'
import { checkAdmin, checkManager } from '../util/tc'

function _loadProjects (projectNameOrIdFilter = '', paramFilters = {}) {
return (dispatch, getState) => {
Expand All @@ -54,7 +54,7 @@ function _loadProjects (projectNameOrIdFilter = '', paramFilters = {}) {
}
}

if (!checkAdmin(getState().auth.token)) {
if (!checkAdmin(getState().auth.token) && !checkManager(getState().auth.token)) {
filters['memberOnly'] = true
}

Expand Down
4 changes: 2 additions & 2 deletions src/actions/sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
UNLOAD_PROJECTS_SUCCESS,
PROJECTS_PAGE_SIZE
} from '../config/constants'
import { checkAdmin } from '../util/tc'
import { checkAdmin, checkManager } from '../util/tc'
import _ from 'lodash'

/**
Expand Down Expand Up @@ -50,7 +50,7 @@ export function loadProjects (filterProjectName = '', paramFilters = {}) {
}
}

if (!checkAdmin(getState().auth.token)) {
if (!checkAdmin(getState().auth.token) && !checkManager(getState().auth.token)) {
filters['memberOnly'] = true
}

Expand Down
34 changes: 28 additions & 6 deletions src/actions/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,55 @@ import {
SEARCH_USER_PROJECTS_SUCCESS,
SEARCH_USER_PROJECTS_FAILURE
} from '../config/constants'
import _ from 'lodash'

/**
* Loads projects of the authenticated user
*/
export function loadAllUserProjects (isAdmin = true) {
return (dispatch) => {
export function loadAllUserProjects (params, isAdmin = true, isManager = true) {
return (dispatch, getState) => {
dispatch({
type: LOAD_ALL_USER_PROJECTS_PENDING
})

const state = getState().users

const filters = {
status: 'active',
sort: 'lastActivityAt desc'
sort: 'lastActivityAt desc',
perPage: 20,
...params
}
if (!isAdmin) {

if (!isAdmin && !isManager) {
filters['memberOnly'] = true
}

fetchMemberProjects(filters).then(({ projects }) => dispatch({
fetchMemberProjects(filters).then(({ projects, pagination }) => dispatch({
type: LOAD_ALL_USER_PROJECTS_SUCCESS,
projects
projects: _.uniqBy((filters.page ? state.allUserProjects || [] : []).concat(projects), 'id'),
total: pagination.xTotal,
page: pagination.xPage
})).catch(() => dispatch({
type: LOAD_ALL_USER_PROJECTS_FAILURE
}))
}
}

export function loadNextProjects (isAdmin = true, isManager = true) {
return (dispatch, getState) => {
const { page, total, allUserProjects } = getState().users
if (allUserProjects.length >= total) {
return
}

loadAllUserProjects(_.assign({}, {
perPage: 20,
page: page + 1
}), isAdmin, isManager)(dispatch, getState)
}
}

/**
* Filter projects of the authenticated user
*
Expand Down
158 changes: 87 additions & 71 deletions src/components/UserCard/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import _ from 'lodash'
import moment from 'moment'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import cn from 'classnames'
Expand All @@ -6,7 +8,6 @@ import { PROJECT_ROLES } from '../../config/constants'
import PrimaryButton from '../Buttons/PrimaryButton'
import AlertModal from '../Modal/AlertModal'
import { updateProjectMemberRole } from '../../services/projects'
import _ from 'lodash'

const theme = {
container: styles.modalContainer
Expand Down Expand Up @@ -58,7 +59,7 @@ class UserCard extends Component {
}

render () {
const { user, onRemoveClick, isEditable } = this.props
const { isInvite, user, onRemoveClick, isEditable } = this.props
const showRadioButtons = _.includes(_.values(PROJECT_ROLES), user.role)
return (
<div>
Expand Down Expand Up @@ -90,76 +91,90 @@ class UserCard extends Component {
)}
<div className={styles.item}>
<div className={cn(styles.col5)}>
{user.handle}
</div>
<div className={cn(styles.col5)}>
{showRadioButtons && (<div className={styles.tcRadioButton}>
<input
name={`user-${user.id}`}
type='radio'
id={`read-${user.id}`}
checked={user.role === PROJECT_ROLES.READ}
onChange={(e) => e.target.checked && this.updatePermission(PROJECT_ROLES.READ)}
/>
<label className={cn({ [styles.isDisabled]: !isEditable })} htmlFor={`read-${user.id}`}>
<div>
Read
</div>
<input type='hidden' />
</label>
</div>)}
</div>
<div className={cn(styles.col5)}>
{showRadioButtons && (<div className={styles.tcRadioButton}>
<input
name={`user-${user.id}`}
type='radio'
id={`write-${user.id}`}
checked={user.role === PROJECT_ROLES.WRITE}
onChange={(e) => e.target.checked && this.updatePermission(PROJECT_ROLES.WRITE)}
/>
<label className={cn({ [styles.isDisabled]: !isEditable })} htmlFor={`write-${user.id}`}>
<div>
Write
</div>
<input type='hidden' />
</label>
</div>)}
</div>
<div className={cn(styles.col5)}>
{showRadioButtons && (<div className={styles.tcRadioButton}>
<input
name={`user-${user.id}`}
type='radio'
id={`full-access-${user.id}`}
checked={user.role === PROJECT_ROLES.MANAGER}
onChange={(e) => e.target.checked && this.updatePermission(PROJECT_ROLES.MANAGER)}
/>
<label className={cn({ [styles.isDisabled]: !isEditable })} htmlFor={`full-access-${user.id}`}>
<div>
Full Access
</div>
<input type='hidden' />
</label>
</div>)}
</div>
<div className={cn(styles.col5)}>
{showRadioButtons && (<div className={styles.tcRadioButton}>
<input
name={`user-${user.id}`}
type='radio'
id={`copilot-${user.id}`}
checked={user.role === PROJECT_ROLES.COPILOT}
onChange={(e) => e.target.checked && this.updatePermission(PROJECT_ROLES.COPILOT)}
/>
<label className={cn({ [styles.isDisabled]: !isEditable })} htmlFor={`copilot-${user.id}`}>
<div>
Copilot
</div>
<input type='hidden' />
</label>
</div>)}
{isInvite ? user.email : user.handle}
</div>
{!isInvite && (
<>
<div className={cn(styles.col5)}>
{showRadioButtons && (<div className={styles.tcRadioButton}>
<input
name={`user-${user.id}`}
type='radio'
id={`read-${user.id}`}
checked={user.role === PROJECT_ROLES.READ}
onChange={(e) => e.target.checked && this.updatePermission(PROJECT_ROLES.READ)}
/>
<label className={cn({ [styles.isDisabled]: !isEditable })} htmlFor={`read-${user.id}`}>
<div>
Read
</div>
<input type='hidden' />
</label>
</div>)}
</div>
<div className={cn(styles.col5)}>
{showRadioButtons && (<div className={styles.tcRadioButton}>
<input
name={`user-${user.id}`}
type='radio'
id={`write-${user.id}`}
checked={user.role === PROJECT_ROLES.WRITE}
onChange={(e) => e.target.checked && this.updatePermission(PROJECT_ROLES.WRITE)}
/>
<label className={cn({ [styles.isDisabled]: !isEditable })} htmlFor={`write-${user.id}`}>
<div>
Write
</div>
<input type='hidden' />
</label>
</div>)}
</div>
<div className={cn(styles.col5)}>
{showRadioButtons && (<div className={styles.tcRadioButton}>
<input
name={`user-${user.id}`}
type='radio'
id={`full-access-${user.id}`}
checked={user.role === PROJECT_ROLES.MANAGER}
onChange={(e) => e.target.checked && this.updatePermission(PROJECT_ROLES.MANAGER)}
/>
<label className={cn({ [styles.isDisabled]: !isEditable })} htmlFor={`full-access-${user.id}`}>
<div>
Full Access
</div>
<input type='hidden' />
</label>
</div>)}
</div>
<div className={cn(styles.col5)}>
{showRadioButtons && (<div className={styles.tcRadioButton}>
<input
name={`user-${user.id}`}
type='radio'
id={`copilot-${user.id}`}
checked={user.role === PROJECT_ROLES.COPILOT}
onChange={(e) => e.target.checked && this.updatePermission(PROJECT_ROLES.COPILOT)}
/>
<label className={cn({ [styles.isDisabled]: !isEditable })} htmlFor={`copilot-${user.id}`}>
<div>
Copilot
</div>
<input type='hidden' />
</label>
</div>)}
</div>
</>
)}
{isInvite && (
<>
<div className={cn(styles.col5)} />
<div className={cn(styles.col5)}>
Invited {moment(user.createdAt).format('MMM D, YY')}
</div>
<div className={cn(styles.col5)} />
<div className={cn(styles.col5)} />
</>
)}
{isEditable ? (<div className={cn(styles.col5)}>
<PrimaryButton
text={'Remove'}
Expand All @@ -173,6 +188,7 @@ class UserCard extends Component {
}

UserCard.propTypes = {
isInvite: PropTypes.bool,
user: PropTypes.object,
updateProjectNember: PropTypes.func.isRequired,
onRemoveClick: PropTypes.func.isRequired,
Expand Down
13 changes: 12 additions & 1 deletion src/components/Users/Users.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@
text-decoration: none;
font-size: 12px;
}

&.inviteEmailInput {
input {
width: 250px;
}
}
}
}

Expand Down Expand Up @@ -395,10 +401,15 @@
}

.addButtonContainer {
width: 110px;
display: flex;
justify-content: flex-start;
height: 30px;
margin-top: 20px;
margin-bottom: 20px;
gap: 8px;
> * {
width: 125px;
}
}

.addUserContentContainer {
Expand Down
Loading