-
Notifications
You must be signed in to change notification settings - Fork 20
New work app to replace work-manager, and v6 projects API usage in copilots app #1487
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
base: dev
Are you sure you want to change the base?
Changes from 54 commits
53a4912
3c3451d
6cfb37c
a6cc139
caa121c
468bc7e
57cf4c5
078871a
720400d
7bc3fc4
65a144d
5472ae2
dc87772
eb60a13
fe2435c
c9b1f97
94d681f
75ea1d2
5e9962c
3c1dc2a
938edc2
7ae2767
c9999b3
bb9429b
7d0de9d
ea9be07
2abcde2
606ebd8
714fa80
a3ecbab
ea67ae1
1e756b6
9f541c4
b4e6dba
d8f42fd
c237b12
eabc27b
6f6165c
fd72c19
2704143
1abec5b
b86e7bc
81914b0
a706a68
a07ac73
67a063b
ee9b1ce
b30f055
0adefe0
16de4f3
d7258bb
4fa864e
754a597
1fcb271
5b64344
f24f8ca
c91c5e5
0af1e4c
f8ae64a
f63c9ad
ad99bbf
5e8486d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| REACT_APP_GROUPS_API_URL=https://api.topcoder-dev.com/v6/groups | ||
| REACT_APP_TERMS_API_URL=https://api.topcoder-dev.com/v5/terms | ||
| REACT_APP_RESOURCES_API_URL=https://api.topcoder-dev.com/v6/resources | ||
| REACT_APP_MEMBER_API_URL=https://api.topcoder-dev.com/v6/members | ||
| REACT_APP_RESOURCE_ROLES_API_URL=https://api.topcoder-dev.com/v6/resource-roles |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| REACT_APP_GROUPS_API_URL=https://api.topcoder.com/v6/groups | ||
| REACT_APP_TERMS_API_URL=https://api.topcoder.com/v5/terms | ||
| REACT_APP_RESOURCES_API_URL=https://api.topcoder.com/v6/resources | ||
| REACT_APP_MEMBER_API_URL=https://api.topcoder.com/v6/members | ||
| REACT_APP_RESOURCE_ROLES_API_URL=https://api.topcoder.com/v6/resource-roles | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,8 @@ import { | |
| WearableIcon, | ||
| } from '~/apps/accounts/src/lib' | ||
|
|
||
| import { shouldUseUpdateTraitAction } from '../trait-action.utils' | ||
|
|
||
| import styles from './Devices.module.scss' | ||
|
|
||
| interface DevicesProps { | ||
|
|
@@ -315,7 +317,9 @@ const Devices: FC<DevicesProps> = (props: DevicesProps) => { | |
| }, | ||
| }] | ||
|
|
||
| const action = props.devicesTrait ? updateMemberTraitsAsync : createMemberTraitsAsync | ||
| const action = shouldUseUpdateTraitAction(props.devicesTrait, deviceTypesData) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [❗❗ |
||
| ? updateMemberTraitsAsync | ||
| : createMemberTraitsAsync | ||
|
|
||
| action( | ||
| props.profile.handle, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,8 @@ import { | |
| TelevisionServiceProviderIcon, | ||
| } from '~/apps/accounts/src/lib' | ||
|
|
||
| import { shouldUseUpdateTraitAction } from '../trait-action.utils' | ||
|
|
||
| import { serviceProviderTypes } from './service-provider-types.config' | ||
| import styles from './ServiceProvider.module.scss' | ||
|
|
||
|
|
@@ -216,7 +218,9 @@ const ServiceProvider: FC<ServiceProviderProps> = (props: ServiceProviderProps) | |
| }, | ||
| }] | ||
|
|
||
| const action = props.serviceProviderTrait ? updateMemberTraitsAsync : createMemberTraitsAsync | ||
| const action = shouldUseUpdateTraitAction(props.serviceProviderTrait, serviceProviderTypesData) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [❗❗ |
||
| ? updateMemberTraitsAsync | ||
| : createMemberTraitsAsync | ||
|
|
||
| action( | ||
| props.profile.handle, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,8 @@ import { createMemberTraitsAsync, updateMemberTraitsAsync, UserProfile, UserTrai | |
| import { Button, Collapsible, ConfirmModal, IconOutline, InputSelect, InputText } from '~/libs/ui' | ||
| import { SettingSection, SoftwareIcon } from '~/apps/accounts/src/lib' | ||
|
|
||
| import { shouldUseUpdateTraitAction } from '../trait-action.utils' | ||
|
|
||
| import { softwareTypes } from './software-types.config' | ||
| import styles from './Software.module.scss' | ||
|
|
||
|
|
@@ -170,7 +172,9 @@ const Software: FC<SoftwareProps> = (props: SoftwareProps) => { | |
| }, | ||
| }] | ||
|
|
||
| const action = props.softwareTrait ? updateMemberTraitsAsync : createMemberTraitsAsync | ||
| const action = shouldUseUpdateTraitAction(props.softwareTrait, softwareTypesData) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [❗❗ |
||
| ? updateMemberTraitsAsync | ||
| : createMemberTraitsAsync | ||
|
|
||
| action( | ||
| props.profile.handle, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,8 @@ import { createMemberTraitsAsync, updateMemberTraitsAsync, UserProfile, UserTrai | |
| import { Button, Collapsible, ConfirmModal, IconOutline, InputText } from '~/libs/ui' | ||
| import { SettingSection, SubscriptionsIcon } from '~/apps/accounts/src/lib' | ||
|
|
||
| import { shouldUseUpdateTraitAction } from '../trait-action.utils' | ||
|
|
||
| import styles from './Subscriptions.module.scss' | ||
|
|
||
| interface SubscriptionsProps { | ||
|
|
@@ -150,7 +152,9 @@ const Subscriptions: FC<SubscriptionsProps> = (props: SubscriptionsProps) => { | |
| setIsSaving(false) | ||
| }) | ||
| } else { | ||
| const action = props.subscriptionsTrait ? updateMemberTraitsAsync : createMemberTraitsAsync | ||
| const action = shouldUseUpdateTraitAction(props.subscriptionsTrait, subscriptionsTypesData) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| ? updateMemberTraitsAsync | ||
| : createMemberTraitsAsync | ||
| action( | ||
| props.profile.handle, | ||
| [{ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import { shouldUseUpdateTraitAction } from './trait-action.utils' | ||
|
|
||
| describe('shouldUseUpdateTraitAction', () => { | ||
| it('returns true when the initial trait exists', () => { | ||
| expect(shouldUseUpdateTraitAction({ traitId: 'software' }, undefined)) | ||
| .toBe(true) | ||
| }) | ||
|
|
||
| it('returns true when local traits exist even without the initial trait', () => { | ||
| expect(shouldUseUpdateTraitAction(undefined, [{ name: 'Chrome' }])) | ||
| .toBe(true) | ||
| }) | ||
|
|
||
| it('returns false when both initial and local traits are missing', () => { | ||
| expect(shouldUseUpdateTraitAction(undefined, undefined)) | ||
| .toBe(false) | ||
| }) | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { UserTrait } from '~/libs/core' | ||
|
|
||
| /** | ||
| * Determine whether tool traits should use update or create action. | ||
| * The initial trait prop can be stale while the user stays on the tab, | ||
| * so local list state is also considered to avoid duplicate create calls. | ||
| */ | ||
| export function shouldUseUpdateTraitAction( | ||
| initialTrait: UserTrait | undefined, | ||
| localTraitsData: UserTrait[] | undefined, | ||
| ): boolean { | ||
| return Boolean(initialTrait || localTraitsData?.length) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import { | ||
| canOpenReviewUi, | ||
| getReviewUiChallengeUrl, | ||
| } from './reviewUiLink' | ||
|
|
||
| describe('ChallengeList review UI helpers', () => { | ||
| describe('canOpenReviewUi', () => { | ||
| it('returns true when challenge has a uuid id', () => { | ||
| expect(canOpenReviewUi('challenge-uuid')) | ||
| .toBe(true) | ||
| }) | ||
|
|
||
| it('returns false when challenge id is empty', () => { | ||
| expect(canOpenReviewUi('')) | ||
| .toBe(false) | ||
| }) | ||
|
|
||
| it('returns false when challenge id is only whitespace', () => { | ||
| expect(canOpenReviewUi(' ')) | ||
| .toBe(false) | ||
| }) | ||
| }) | ||
|
|
||
| describe('getReviewUiChallengeUrl', () => { | ||
| it('builds review ui url using challenge id path', () => { | ||
| expect(getReviewUiChallengeUrl('https://review.topcoder-dev.com', 'challenge-uuid')) | ||
| .toBe('https://review.topcoder-dev.com/challenge-uuid') | ||
| }) | ||
| }) | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,10 @@ import { Paging } from '../../models/challenge-management/Pagination' | |
| import { checkIsMM } from '../../utils/challenge' | ||
|
|
||
| import { MobileListView } from './MobileListView' | ||
| import { | ||
| canOpenReviewUi, | ||
| getReviewUiChallengeUrl, | ||
| } from './reviewUiLink' | ||
| import styles from './ChallengeList.module.scss' | ||
|
|
||
| export interface ChallengeListProps { | ||
|
|
@@ -180,11 +184,12 @@ const Actions: FC<{ | |
| }, | ||
| ) | ||
|
|
||
| const hasChallengeDetailsAccess = canOpenReviewUi(props.challenge.id) | ||
| const hasProjectId | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| = 'projectId' in props.challenge | ||
| && props.challenge.projectId !== undefined | ||
| const hasLegacyId | ||
| = 'legacyId' in props.challenge && props.challenge.legacyId !== undefined | ||
| = typeof props.challenge.projectId === 'number' | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [💡 |
||
| && props.challenge.projectId > 0 | ||
| const hasWorkManagerAccess = hasProjectId && hasChallengeDetailsAccess | ||
| const hasReviewUiAccess = canOpenReviewUi(props.challenge.id) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [❗❗ |
||
|
|
||
| return ( | ||
| <div className={styles.rowActions}> | ||
|
|
@@ -234,17 +239,20 @@ const Actions: FC<{ | |
| classNames={{ menu: 'challenge-list-actions-dropdown-menu' }} | ||
| > | ||
| <ul> | ||
| <li> | ||
| <a | ||
| href={`${EnvironmentConfig.ADMIN.CHALLENGE_URL}/${props.challenge.id}`} | ||
| target='_blank' | ||
| rel='noreferrer' | ||
| > | ||
| Challenge Details | ||
| </a> | ||
| <li className={cn({ disabled: !hasChallengeDetailsAccess })}> | ||
| {hasChallengeDetailsAccess && ( | ||
| <a | ||
| href={`${EnvironmentConfig.ADMIN.CHALLENGE_URL}/${props.challenge.id}`} | ||
| target='_blank' | ||
| rel='noreferrer' | ||
| > | ||
| Challenge Details | ||
| </a> | ||
| )} | ||
| {!hasChallengeDetailsAccess && <span>Challenge Details</span>} | ||
| </li> | ||
| <li className={cn({ disabled: !hasProjectId })}> | ||
| {hasProjectId && ( | ||
| <li className={cn({ disabled: !hasWorkManagerAccess })}> | ||
| {hasWorkManagerAccess && ( | ||
| <a | ||
| href={ | ||
| `${EnvironmentConfig.ADMIN.WORK_MANAGER_URL}/projects/${props.challenge.projectId}/challenges/${props.challenge.id}/view` /* eslint-disable-line max-len */ | ||
|
|
@@ -255,21 +263,22 @@ const Actions: FC<{ | |
| Work Manager | ||
| </a> | ||
| )} | ||
| {!hasProjectId && <span>Work Manager</span>} | ||
| {!hasWorkManagerAccess && <span>Work Manager</span>} | ||
| </li> | ||
| <li className={cn({ disabled: !hasLegacyId })}> | ||
| {hasLegacyId && ( | ||
| <li className={cn({ disabled: !hasReviewUiAccess })}> | ||
| {hasReviewUiAccess && ( | ||
| <a | ||
| href={ | ||
| `${EnvironmentConfig.ADMIN.REVIEW_UI_URL}/=${props.challenge.id}` /* eslint-disable-line max-len */ | ||
| } | ||
| href={getReviewUiChallengeUrl( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| EnvironmentConfig.ADMIN.REVIEW_UI_URL, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| props.challenge.id, | ||
| )} | ||
| target='_blank' | ||
| rel='noreferrer' | ||
| > | ||
| Review UI | ||
| </a> | ||
| )} | ||
| {!hasLegacyId && <span>Review UI</span>} | ||
| {!hasReviewUiAccess && <span>Review UI</span>} | ||
| </li> | ||
| </ul> | ||
| </DropdownMenu> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| /** | ||
| * Returns whether the Review UI link can be opened for a challenge. | ||
| */ | ||
| export function canOpenReviewUi(challengeId?: string): boolean { | ||
| return Boolean(challengeId?.trim()) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [💡 |
||
| } | ||
|
|
||
| /** | ||
| * Builds the Review UI URL for a challenge id. | ||
| */ | ||
| export function getReviewUiChallengeUrl( | ||
| reviewUiBaseUrl: string, | ||
| challengeId: string, | ||
| ): string { | ||
| return `${reviewUiBaseUrl}/${challengeId}` | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| @import '@libs/ui/styles/includes'; | ||
|
|
||
| .modal { | ||
| width: 1240px !important; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| max-width: calc(100vw - 32px) !important; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| } | ||
|
|
||
| .container { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 20px; | ||
|
|
||
| th:first-child { | ||
| padding-left: 16px !important; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| } | ||
| } | ||
|
|
||
| .actionButtons { | ||
| display: flex; | ||
| justify-content: flex-end; | ||
| gap: 6px; | ||
| } | ||
|
|
||
| .tableCellNoWrap { | ||
| white-space: nowrap; | ||
| text-align: left !important; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| } | ||
|
|
||
| .statusCell { | ||
| text-align: center !important; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| width: 90px; | ||
| } | ||
|
|
||
| .emailStatus { | ||
| align-items: center; | ||
| display: inline-flex; | ||
| justify-content: center; | ||
| min-height: 24px; | ||
| min-width: 24px; | ||
|
|
||
| svg { | ||
| width: 20px; | ||
| height: 20px; | ||
| } | ||
| } | ||
|
|
||
| .emailStatusDelivered { | ||
| color: $green-120; | ||
| } | ||
|
|
||
| .emailStatusFailed { | ||
| color: $red-110; | ||
| } | ||
|
|
||
| .tableCell { | ||
| min-width: 220px; | ||
| white-space: break-spaces !important; | ||
| text-align: left !important; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| } | ||
|
|
||
| .loadingSpinnerContainer { | ||
| position: relative; | ||
| height: 100px; | ||
|
|
||
| .spinner { | ||
| background: none; | ||
| } | ||
| } | ||
|
|
||
| .noRecordFound { | ||
| padding: 16px 16px 32px; | ||
| text-align: center; | ||
| } | ||
|
|
||
| .desktopTable { | ||
| overflow-x: auto; | ||
| overflow-y: visible; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
|
|
||
| thead th { | ||
| position: sticky; | ||
| top: 0; | ||
| z-index: 2; | ||
| background: $tc-white; | ||
| } | ||
|
|
||
| td { | ||
| vertical-align: middle; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[❗❗
correctness]The API version for
REACT_APP_TERMS_API_URLis v5, while others are v6. Ensure this is intentional and that the correct API version is being used.