-
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 10 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 |
|---|---|---|
|
|
@@ -62,7 +62,7 @@ const FieldHtmlEditor: FC<FieldHtmlEditorProps> = ( | |
| + '}', | ||
| height: 400, | ||
| menubar: false, | ||
| plugins: ['table', 'link', 'textcolor', 'contextmenu'], | ||
| plugins: ['table', 'link'], | ||
|
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. [ 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. [ |
||
| source_view: true, | ||
| statusbar: false, | ||
| toolbar: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -158,7 +158,9 @@ const CopilotRequestsPage: FC = () => { | |
| }: CopilotRequestsResponse = useCopilotRequests(sort) | ||
|
|
||
| const viewRequestDetails = useMemo(() => ( | ||
| routeParams.requestId && find(requests, { id: +routeParams.requestId }) as CopilotRequest | ||
| routeParams.requestId | ||
| ? find(requests, request => `${request.id}` === routeParams.requestId) as CopilotRequest | ||
|
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. [💡 |
||
| : undefined | ||
| ), [requests, routeParams.requestId]) | ||
|
|
||
| const hideRequestDetails = useCallback(() => { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,7 +9,7 @@ import { getPaginatedAsync, PaginatedResponse } from '~/libs/core/lib/xhr/xhr-fu | |
|
|
||
| import { CopilotRequest } from '../models/CopilotRequest' | ||
|
|
||
| const baseUrl = `${EnvironmentConfig.API.V5}/projects` | ||
| const baseUrl = `${EnvironmentConfig.API.V6}/projects` | ||
|
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. [❗❗ |
||
| const PAGE_SIZE = 20 | ||
|
|
||
| /** | ||
|
|
@@ -27,6 +27,7 @@ function copilotRequestFactory(data: any): CopilotRequest { | |
| createdAt: new Date(data.createdAt), | ||
| data: undefined, | ||
| opportunity: data.copilotOpportunity?.[0], | ||
| projectId: String(data?.projectId ?? data?.data?.projectId ?? ''), | ||
|
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. [ |
||
| startDate: new Date(data.data?.startDate), | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,11 +7,15 @@ import { EnvironmentConfig } from '~/config' | |
|
|
||
| import { Project } from '../models/Project' | ||
|
|
||
| const baseUrl = `${EnvironmentConfig.API.V5}/projects` | ||
| const baseUrl = `${EnvironmentConfig.API.V6}/projects` | ||
|
|
||
| export type ProjectsResponse = SWRResponse<Project[], Project[]> | ||
|
|
||
| const sleep = (ms: number): Promise<()=> void> => new Promise(resolve => { setTimeout(resolve, ms) }) | ||
|
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. [ |
||
| const normalizeProject = (project: Project): Project => ({ | ||
| ...project, | ||
| id: String(project.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. [ |
||
| }) | ||
|
|
||
| /** | ||
| * Custom hook to fetch and manage projects data. | ||
|
|
@@ -38,7 +42,7 @@ export const useProjects = (search?: string, config?: {isPaused?: () => boolean, | |
| const response = await xhrGetAsync<Project[]>( | ||
| buildUrl(baseUrl, { ...params, id: chunkIds }), | ||
| ) | ||
| allResults.push(...response) | ||
| allResults.push(...response.map(normalizeProject)) | ||
|
|
||
| // Rate limit: delay 200ms between calls | ||
| // eslint-disable-next-line no-await-in-loop | ||
|
|
@@ -49,6 +53,7 @@ export const useProjects = (search?: string, config?: {isPaused?: () => boolean, | |
| } | ||
|
|
||
| return xhrGetAsync<Project[]>(url) | ||
| .then(response => response.map(normalizeProject)) | ||
| } | ||
|
|
||
| return useSWR(url, fetcher, { | ||
|
|
@@ -61,10 +66,12 @@ export const useProjects = (search?: string, config?: {isPaused?: () => boolean, | |
| export const getProject = (projectId: string): Promise<Project> => { | ||
| const url = `${baseUrl}/${projectId}` | ||
| return xhrGetAsync<Project>(url) | ||
| .then(normalizeProject) | ||
| } | ||
|
|
||
| export const getProjects = (search?: string, config?: {filter: any}): Promise<Project[]> => { | ||
| const params = { name: search, ...config?.filter } | ||
| const url = buildUrl(baseUrl, params) | ||
| return xhrGetAsync<Project[]>(url) | ||
| .then(response => response.map(normalizeProject)) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,13 +20,16 @@ interface Props { | |
| backUrl?: string | ||
| backAction?: () => void | ||
| titleUrl?: string | 'emptyLink' | ||
| titleAction?: ReactNode | ||
| rightHeader?: ReactNode, | ||
| breadCrumb: BreadCrumbData[] | ||
| } | ||
|
|
||
| export const PageWrapper: FC<PropsWithChildren<Props>> = props => ( | ||
| <div className={classNames(styles.container, props.className)}> | ||
| <BreadCrumb list={props.breadCrumb} /> | ||
| {props.breadCrumb.length > 0 && ( | ||
|
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. [ |
||
| <BreadCrumb list={props.breadCrumb} /> | ||
| )} | ||
| <PageTitle>{props.pageTitle}</PageTitle> | ||
| <div className={styles.blockHeader}> | ||
| <div className={styles.blockHeaderRight}> | ||
|
|
@@ -46,6 +49,13 @@ export const PageWrapper: FC<PropsWithChildren<Props>> = props => ( | |
| {props.pageTitle} | ||
| </h3> | ||
| </PageHeader> | ||
| {props.titleAction | ||
|
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. [💡 |
||
| ? ( | ||
| <div className={styles.blockTitleAction}> | ||
| {props.titleAction} | ||
| </div> | ||
| ) | ||
| : undefined} | ||
| {props.titleUrl && props.titleUrl !== 'emptyLink' && ( | ||
| <a | ||
| className={styles.blockExternalLink} | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| # Work App | ||
|
|
||
| The Work app provides work management capabilities for: | ||
| - challenges | ||
| - projects | ||
| - TaaS engagements | ||
| - users | ||
| - groups | ||
|
|
||
| ## Routing | ||
|
|
||
| `work-app.routes.tsx` defines the app root and child routes: | ||
| - `challenges` | ||
| - `projects` | ||
| - `taas` | ||
| - `users` | ||
| - `groups` | ||
|
|
||
| `config/routes.config.ts` contains route ids and the `rootRoute` resolver based on the active subdomain. | ||
|
|
||
| ## Providers | ||
|
|
||
| `WorkApp.tsx` composes these providers: | ||
| - `WorkAppContextProvider`: authentication token and derived role/access flags | ||
| - `SWRConfigProvider`: shared SWR fetch configuration for the app | ||
|
|
||
| ## Extending The App | ||
|
|
||
| 1. Add feature routes under `work-app.routes.tsx` children. | ||
| 2. Implement pages/components inside `src/lib` or feature folders. | ||
| 3. Reuse `WorkAppContext` and `SWRConfigProvider` for shared state/data access. | ||
|
|
||
| ## Legacy Reference | ||
|
|
||
| Original implementation reference: | ||
| - `work-manager/` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export * from './src' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import { FC, useContext, useEffect, useMemo } from 'react' | ||
| import { Outlet, Routes } from 'react-router-dom' | ||
|
|
||
| import { routerContext, RouterContextData } from '~/libs/core' | ||
|
|
||
| import { Layout, SWRConfigProvider, WorkAppContextProvider, WORK_APP_BODY_CLASS } from './lib' | ||
| import { toolTitle } from './work-app.routes' | ||
| import './lib/styles/index.scss' | ||
|
|
||
| const WorkApp: FC = () => { | ||
| const { getChildRoutes }: RouterContextData = useContext(routerContext) | ||
| const childRoutes = useMemo(() => getChildRoutes(toolTitle), [getChildRoutes]) | ||
|
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. [💡 |
||
|
|
||
| useEffect(() => { | ||
| document.body.classList.add(WORK_APP_BODY_CLASS) | ||
|
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 () => { | ||
| document.body.classList.remove(WORK_APP_BODY_CLASS) | ||
| } | ||
| }, []) | ||
|
|
||
| return ( | ||
| <WorkAppContextProvider> | ||
| <SWRConfigProvider> | ||
| <Layout> | ||
| <Outlet /> | ||
| <Routes>{childRoutes}</Routes> | ||
| </Layout> | ||
| </SWRConfigProvider> | ||
| </WorkAppContextProvider> | ||
| ) | ||
| } | ||
|
|
||
| export default WorkApp | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| export const CHALLENGE_TRACKS = { | ||
| COMPETITIVE_PROGRAMMING: 'COMPETITIVE_PROGRAMMING', | ||
| DATA_SCIENCE: 'DATA_SCIENCE', | ||
| DESIGN: 'DESIGN', | ||
| DEVELOP: 'DEVELOP', | ||
| QA: 'QA', | ||
| } as const | ||
|
|
||
| export const CHALLENGE_TYPES = { | ||
| CHALLENGE: 'Challenge', | ||
| FIRST_2_FINISH: 'First2Finish', | ||
| MARATHON_MATCH: 'Marathon Match', | ||
| TASK: 'Task', | ||
| } as const | ||
|
|
||
| export const CHALLENGE_STATUS = { | ||
| ACTIVE: 'ACTIVE', | ||
| APPROVED: 'APPROVED', | ||
| CANCELLED: 'CANCELLED', | ||
| CANCELLED_CLIENT_REQUEST: 'CANCELLED_CLIENT_REQUEST', | ||
| CANCELLED_FAILED_REVIEW: 'CANCELLED_FAILED_REVIEW', | ||
| CANCELLED_FAILED_SCREENING: 'CANCELLED_FAILED_SCREENING', | ||
| CANCELLED_REQUIREMENTS_INFEASIBLE: 'CANCELLED_REQUIREMENTS_INFEASIBLE', | ||
| CANCELLED_WINNER_UNRESPONSIVE: 'CANCELLED_WINNER_UNRESPONSIVE', | ||
| CANCELLED_ZERO_REGISTRATIONS: 'CANCELLED_ZERO_REGISTRATIONS', | ||
| CANCELLED_ZERO_SUBMISSIONS: 'CANCELLED_ZERO_SUBMISSIONS', | ||
| COMPLETED: 'COMPLETED', | ||
| DRAFT: 'DRAFT', | ||
| NEW: 'NEW', | ||
| } as const | ||
|
|
||
| export const READ_ONLY = 'topcoder user' | ||
| export const ADMIN = 'administrator' | ||
| export const CONNECT_ADMIN = 'connect admin' | ||
| export const COPILOT = 'copilot' | ||
| export const MANAGER = 'manager' | ||
| export const PROJECT_MANAGER = 'project manager' | ||
| export const TOPCODER_PROJECT_MANAGER = 'topcoder project manager' | ||
| export const TALENT_MANAGER = 'talent manager' | ||
| export const TOPCODER_TALENT_MANAGER = 'topcoder talent manager' | ||
| export const TASK_MANAGER = 'task manager' | ||
| export const TOPCODER_TASK_MANAGER = 'topcoder task manager' | ||
|
|
||
| export const READ_ONLY_ROLES = [READ_ONLY] | ||
| export const ADMIN_ROLES = [ADMIN, CONNECT_ADMIN] | ||
| export const COPILOT_ROLES = [COPILOT] | ||
| export const TALENT_MANAGER_ROLES = [ | ||
| TALENT_MANAGER, | ||
| TOPCODER_TALENT_MANAGER, | ||
| ] | ||
| export const MANAGER_ROLES = [ | ||
| PROJECT_MANAGER, | ||
| TOPCODER_PROJECT_MANAGER, | ||
| TALENT_MANAGER, | ||
| TOPCODER_TALENT_MANAGER, | ||
| ] | ||
| export const TASK_MANAGER_ROLES = [ | ||
| TASK_MANAGER, | ||
| TOPCODER_TASK_MANAGER, | ||
| TALENT_MANAGER, | ||
| TOPCODER_TALENT_MANAGER, | ||
| ] | ||
|
|
||
| export const DEFAULT_PAGE_SIZE = 10 | ||
| export const PROJECTS_PAGE_SIZE = 20 | ||
| export const ENGAGEMENTS_PAGE_SIZE = 100 | ||
| export const TABLE_DATE_FORMAT = 'MMM DD YYYY, HH:mm A' | ||
|
|
||
| export const PAGINATION_PER_PAGE_OPTIONS = [ | ||
| { label: '5', value: '5' }, | ||
|
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. [ |
||
| { label: '10', value: '10' }, | ||
| { label: '25', value: '25' }, | ||
| { label: '50', value: '50' }, | ||
| ] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import { AppSubdomain, EnvironmentConfig } from '~/config' | ||
|
|
||
| export const rootRoute: string | ||
|
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.SUBDOMAIN === AppSubdomain.work | ||
| ? '' | ||
| : `/${AppSubdomain.work}` | ||
|
|
||
| export const challengesRouteId = 'challenges' | ||
| export const challengeCreateRouteId = 'challenge-create' | ||
| export const challengeEditRouteId = 'challenge-edit' | ||
| export const projectsRouteId = 'projects' | ||
| export const projectCreateRouteId = 'project-create' | ||
| export const projectEditRouteId = 'project-edit' | ||
| export const taasRouteId = 'taas' | ||
| export const taasCreateRouteId = 'taas-create' | ||
| export const taasEditRouteId = 'taas-edit' | ||
| export const engagementsRouteId = 'engagements' | ||
| export const engagementCreateRouteId = 'engagement-create' | ||
| export const engagementEditRouteId = 'engagement-edit' | ||
| export const engagementApplicationsRouteId = 'engagement-applications' | ||
| export const engagementAssignmentsRouteId = 'engagement-assignments' | ||
| export const engagementFeedbackRouteId = 'engagement-feedback' | ||
| export const engagementExperienceRouteId = 'engagement-experience' | ||
| export const projectAssetsRouteId = 'project-assets' | ||
| export const usersRouteId = 'users' | ||
| export const projectInvitationsRouteId = 'project-invitations' | ||
| export const groupsRouteId = 'groups' | ||
| export const groupsEditRouteId = 'group-edit' | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| export { workRoutes } from './work-app.routes' | ||
| export { rootRoute as workRootRoute } from './config/routes.config' |
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.