Skip to content
Open
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
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,7 @@ e.g.:
The following summarizes the various [apps](#adding-a-new-platform-ui-application) in the Platform UI.

- [Platform App](#platform-app)
- [Arena Manager](#arena-manager)
- [Dev Center](#dev-center)
- [Earn](#earn)
- [Gamification Admin](#gamification-admin)
Expand All @@ -565,6 +566,12 @@ It also renders the [Universal Navigation](https://github.com/topcoder-platform/
[Platform README](./src/apps/platform/README.md)
[Platform Routes](./src/apps/platform/src/platform.routes.tsx)

## Arena Manager

Application that hosts AI Arena problem-library and tournament-management workflows.

[Arena Manager Routes](./src/apps/arena-manager/src/arena-manager.routes.tsx)

## Dev Center

A community-led project to document how to work with Topcoder internal applications.
Expand Down
13 changes: 13 additions & 0 deletions craco.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ module.exports = {
} },
],

devServer: {
proxy: {
'/arena-manager/api': {
target: 'http://localhost:8081',
changeOrigin: true,
},
Comment thread
jpeg22 marked this conversation as resolved.
'/v6': {
target: 'http://localhost:8081',
changeOrigin: true,
},
}
},

webpack: {
alias: {
// aliases used in JS/TS
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -249,5 +249,6 @@
"volta": {
"node": "22.13.0",
"yarn": "1.22.22"
}
},
"packageManager": "yarn@1.22.22"
}
1 change: 1 addition & 0 deletions src/apps/arena-manager/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './src'
32 changes: 32 additions & 0 deletions src/apps/arena-manager/src/ArenaManagerApp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { FC, useContext, useEffect, useMemo } from 'react'
import { Outlet, Routes } from 'react-router-dom'

import { routerContext, RouterContextData } from '~/libs/core'

import { toolTitle } from './arena-manager.routes'
import './lib/styles/index.scss'

/**
* Root component for the Arena Manager micro-app.
*/
const ArenaManagerApp: FC = () => {
const { getChildRoutes }: RouterContextData = useContext(routerContext)
// eslint-disable-next-line react-hooks/exhaustive-deps
const childRoutes = useMemo(() => getChildRoutes(toolTitle), [])

useEffect(() => {
document.body.classList.add('arena-manager-app')
return () => {
document.body.classList.remove('arena-manager-app')
}
}, [])

return (
<div>
<Outlet />
<Routes>{childRoutes}</Routes>
</div>
)
}

export default ArenaManagerApp
80 changes: 80 additions & 0 deletions src/apps/arena-manager/src/arena-manager.routes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { AppSubdomain, ToolTitle } from '~/config'
import {
lazyLoad,
PlatformRoute,
Rewrite,
} from '~/libs/core'

import {
aiHubTournamentRoute,
problemLibraryRouteId,
rootRoute,
tournamentLaunchRouteId,
tournamentsRouteId,
} from './config/routes.config'
import ActiveTournamentAiHubPage from './tournaments/ActiveTournamentAiHubPage'

const ArenaManagerApp = lazyLoad(
() => import('./ArenaManagerApp'),
)

const ProblemLibraryPage = lazyLoad(
() => import('./problem-library/ProblemLibraryPage'),
'ProblemLibraryPage',
)

const TournamentPage = lazyLoad(
() => import('./tournaments'),
'TournamentPage',
)

const TournamentLaunchPage = lazyLoad(
() => import('./tournaments/TournamentLaunchPage'),
'TournamentLaunchPage',
)

export const toolTitle: string = ToolTitle.arenaManager

export const arenaManagerRoutes: ReadonlyArray<PlatformRoute> = [
{
authRequired: false,
element: <ActiveTournamentAiHubPage />,
id: 'ai-hub-tournament',
route: aiHubTournamentRoute,
title: 'Active Tournament',
},
{
authRequired: true,
// TODO: Restrict viewing of Arena Manager pages by role when role policy is finalized.
// Example: rolesRequired: ['arena-admin']
children: [
{
element: <Rewrite to={problemLibraryRouteId} />,
route: '',
},
{
element: <ProblemLibraryPage />,
id: problemLibraryRouteId,
route: problemLibraryRouteId,
title: 'Problem Library',
},
{
element: <TournamentPage />,
id: tournamentsRouteId,
route: tournamentsRouteId,
title: 'Tournaments',
},
{
element: <TournamentLaunchPage />,
id: tournamentLaunchRouteId,
route: `${tournamentsRouteId}/:tourneyId/launch`,
title: 'Launch Tournament',
},
],
domain: AppSubdomain.arenaManager,
element: <ArenaManagerApp />,
id: toolTitle,
route: rootRoute,
title: toolTitle,
},
]
14 changes: 14 additions & 0 deletions src/apps/arena-manager/src/config/index.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Shared constants for the arena-manager app.
*/

export const MSG_NO_PROBLEMS_FOUND = 'No problems registered. Upload one to get started.'
export const MSG_NO_TOURNAMENTS_FOUND = 'No tournaments found.'

export const FALLBACK_PROBLEM_IDS = [
'P1-Sorting',
'P2-Maze',
'P3-Pathing',
'P4-Search',
'P5-Heuristic',
]
2 changes: 2 additions & 0 deletions src/apps/arena-manager/src/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './index.config'
export * from './routes.config'
22 changes: 22 additions & 0 deletions src/apps/arena-manager/src/config/routes.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Route IDs and root path for the arena-manager app.
*/
import { AppSubdomain, EnvironmentConfig } from '~/config'

export const rootRoute: string
= EnvironmentConfig.SUBDOMAIN === AppSubdomain.arenaManager
? ''
: `/${AppSubdomain.arenaManager}`

export const problemLibraryRouteId = 'problem-library'
export const tournamentsRouteId = 'tournaments'
export const tournamentLaunchRouteId = 'tournament-launch'
export const aiHubTournamentRoute = '/ai-hub/tournament'

export function getTournamentLaunchPath(tourneyId: string): string {
return `${rootRoute}/${tournamentsRouteId}/${tourneyId}/launch`
}

export function getActiveTournamentPath(): string {
return aiHubTournamentRoute
}
2 changes: 2 additions & 0 deletions src/apps/arena-manager/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { arenaManagerRoutes } from './arena-manager.routes'
export { rootRoute as arenaManagerRootRoute } from './config/routes.config'
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
@import '@libs/ui/styles/includes';

.modalOverlay {
align-items: center;
background: rgb(15 23 42 / 0.45);
display: flex;
inset: 0;
justify-content: center;
padding: $sp-4;
position: fixed;
z-index: 1200;
}

.modal {
background: $tc-white;
border-radius: 12px;
box-shadow: 0 10px 30px rgb(0 0 0 / 0.2);
max-width: 540px;
overflow: hidden;
width: 100%;
}

.modalHeader {
align-items: center;
border-bottom: 1px solid $black-20;
display: flex;
justify-content: space-between;
padding: $sp-4 $sp-5;
}

.modalTitle {
font-family: $font-barlow;
font-size: 22px;
font-weight: $font-weight-bold;
line-height: 30px;
margin: 0;
text-transform: none;
}

.modalClose {
background: transparent;
border: 0;
color: $black-60;
cursor: pointer;
font-size: 20px;
line-height: 1;
padding: 0;
}

.confirmBody {
padding: $sp-5;
}

.confirmText {
color: $black-80;
font-size: 16px;
line-height: 24px;
margin: 0;
}

.confirmActions {
display: flex;
gap: $sp-3;
justify-content: flex-end;
margin-top: $sp-5;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { FC, ReactNode } from 'react'

import { Button } from '~/libs/ui'

import styles from './DeleteConfirmationModal.module.scss'

interface DeleteConfirmationModalProps {
open: boolean
title: string
content: ReactNode
confirmLabel: string
cancelLabel?: string
confirmButtonClassName?: string
isProcessing?: boolean
onCancel: () => void
onConfirm: () => void
}

export const DeleteConfirmationModal: FC<DeleteConfirmationModalProps> = (
props: DeleteConfirmationModalProps,
) => {
if (!props.open) {
return null
}

return (
<div
className={styles.modalOverlay}
onClick={() => !props.isProcessing && props.onCancel()}
role='dialog'
aria-modal='true'
aria-label={props.title}
>
<div
className={styles.modal}
onClick={event => event.stopPropagation()}
>
<div className={styles.modalHeader}>
<h4 className={styles.modalTitle}>{props.title}</h4>
<button
className={styles.modalClose}
onClick={props.onCancel}
disabled={props.isProcessing}
aria-label='Close'
>
</button>
</div>
<div className={styles.confirmBody}>
<div className={styles.confirmText}>{props.content}</div>
<div className={styles.confirmActions}>
<Button
size='sm'
secondary
noCaps
onClick={props.onCancel}
disabled={props.isProcessing}
>
{props.cancelLabel || 'Cancel'}
</Button>
<Button
size='sm'
noCaps
onClick={props.onConfirm}
disabled={props.isProcessing}
className={props.confirmButtonClassName}
>
{props.confirmLabel}
</Button>
</div>
</div>
</div>
</div>
)
}

export default DeleteConfirmationModal
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as DeleteConfirmationModal } from './DeleteConfirmationModal'
1 change: 1 addition & 0 deletions src/apps/arena-manager/src/lib/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './DeleteConfirmationModal'
3 changes: 3 additions & 0 deletions src/apps/arena-manager/src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './components'
export * from './models'
export * from './services'
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Generic API response wrapper from the arena-manager api.
*/
export interface ResponseObject<T> {
data: T
success: boolean
message: string
}
13 changes: 13 additions & 0 deletions src/apps/arena-manager/src/lib/models/SourceProblem.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Represents a programming problem in the problem library.
*/
export interface SourceProblem {
problemId: string
problemName: string
/** Whether the problem has successfully passed its Docker test run. */
isTested: boolean
/** Whether the problem is flagged as ready for use in a contest. */
isContestReady: boolean
/** Human-readable test status: 'Pending Test' | 'Passed' | 'Failed' */
status?: string
}
Loading
Loading