diff --git a/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/CheatInfo.tsx b/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/CheatInfo.tsx index 1dc0660dc..8f4c4d6a9 100644 --- a/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/CheatInfo.tsx +++ b/src/GZCTF/ClientApp/src/pages/games/[id]/monitor/CheatInfo.tsx @@ -5,12 +5,10 @@ import { Box, Center, Group, - Input, Paper, ScrollArea, Stack, Switch, - Table, Text, Title, useMantineTheme, @@ -30,7 +28,6 @@ import { SwitchLabel } from '@Components/admin/SwitchLabel' import { useLanguage } from '@Utils/I18n' import { showErrorMsg } from '@Utils/Shared' import { useParticipationStatusMap } from '@Utils/Shared' -import { useDisplayInputStyles } from '@Utils/ThemeOverride' import { OnceSWRConfig } from '@Hooks/useConfig' import { useUserRole } from '@Hooks/useUser' import api, { CheatInfoModel, ParticipationEditModel, ParticipationStatus, Role } from '@Api' @@ -42,6 +39,11 @@ enum CheatType { Owned = 'Owned', } +const CHEAT_INFO_MISSING_VALUE = '__missing__' +const CHEAT_SUBMISSION_SEPARATOR = '|' +const CHEAT_SUBMISSION_AT = '@' +const CHEAT_SUBMISSION_ARROW = '→' + const CheatTypeMap = new Map([ [ CheatType.Submit, @@ -64,7 +66,8 @@ interface CheatSubmissionInfo { answer?: string user?: string challenge?: string - relatedTeam?: string + submitTeam?: string + ownedTeam?: string cheatType: CheatType } @@ -114,12 +117,13 @@ const ToCheatTeamInfo = (cheatInfo: CheatInfoModel[]) => { } const cheatSubmissionInfo: CheatSubmissionInfo = { - time: time, + time, answer: submission.answer, user: submission.user, challenge: submission.challenge, + submitTeam: submitTeam.team?.name, + ownedTeam: ownedTeam.team?.name, cheatType: CheatType.Owned, - relatedTeam: submitTeam.team?.name, } ownedTeamInfo.submissionInfo.add(cheatSubmissionInfo) @@ -131,7 +135,6 @@ const ToCheatTeamInfo = (cheatInfo: CheatInfoModel[]) => { const cheatSubmissionSourceInfo: CheatSubmissionInfo = { ...cheatSubmissionInfo, cheatType: CheatType.Submit, - relatedTeam: ownedTeam.team?.name, } submitTeamInfo.submissionInfo.add(cheatSubmissionSourceInfo) @@ -139,40 +142,70 @@ const ToCheatTeamInfo = (cheatInfo: CheatInfoModel[]) => { return cheatTeamInfo } -interface CheatSubmissionInfoProps { +const ToCheatSubmissionInfo = (info: CheatInfoModel, cheatType: CheatType = CheatType.Submit): CheatSubmissionInfo => ({ + time: info.submission?.time ? dayjs(info.submission.time) : undefined, + answer: info.submission?.answer, + user: info.submission?.user, + challenge: info.submission?.challenge, + submitTeam: info.submitTeam?.team?.name, + ownedTeam: info.ownedTeam?.team?.name, + cheatType, +}) + +const GetCheatSubmissionKey = (submissionInfo: CheatSubmissionInfo) => + [ + submissionInfo.cheatType, + submissionInfo.time?.unix() ?? CHEAT_INFO_MISSING_VALUE, + submissionInfo.submitTeam ?? CHEAT_INFO_MISSING_VALUE, + submissionInfo.ownedTeam ?? CHEAT_INFO_MISSING_VALUE, + submissionInfo.user ?? CHEAT_INFO_MISSING_VALUE, + submissionInfo.challenge ?? CHEAT_INFO_MISSING_VALUE, + ].join(CHEAT_SUBMISSION_SEPARATOR) + +const FormatCheatTime = (time: dayjs.Dayjs | undefined, locale: string, format: string) => + time ? time.locale(locale).format(format) : '-' + +const FormatCheatSubmissionSummary = (submissionInfo: CheatSubmissionInfo, userLabel: string, teamLabel: string) => + `${submissionInfo.user ?? userLabel} ${CHEAT_SUBMISSION_AT} ${submissionInfo.submitTeam ?? teamLabel} ${CHEAT_SUBMISSION_ARROW} ${submissionInfo.ownedTeam ?? teamLabel}` + +interface CheatSubmissionCardProps { submissionInfo: CheatSubmissionInfo } -const CheatSubmissionInfo: FC = (props) => { +const CheatSubmissionCard: FC = (props) => { const { submissionInfo } = props - const theme = useMantineTheme() const type = CheatTypeMap.get(submissionInfo.cheatType)! - const { classes } = useDisplayInputStyles({ ff: 'monospace' }) + const { t } = useTranslation() const { locale } = useLanguage() return ( - - - - - - {dayjs(submissionInfo.time).locale(locale).format('SL HH:mm:ss')} + + + + + {FormatCheatSubmissionSummary(submissionInfo, t('common.label.user'), t('common.label.team'))} + + + }> + {submissionInfo.cheatType === CheatType.Submit + ? t('game.label.cheat_info.submit_team') + : t('game.label.cheat_info.owned_team')} + + + {FormatCheatTime(submissionInfo.time, locale, 'SL HH:mm:ss')} + + + + + + {submissionInfo.challenge ?? t('common.label.challenge')} - - {submissionInfo.relatedTeam} + + {submissionInfo.answer ?? '-'} - - {submissionInfo.user} - - - - - {submissionInfo.challenge} - - - + ) } @@ -205,6 +238,9 @@ const CheatInfoItem: FC = (props) => { {!cheatTeamInfo.name ? t('admin.placeholder.games.participation.team') : cheatTeamInfo.name} + + {cheatTeamInfo.submissionInfo.size} + {cheatTeamInfo?.division && ( {cheatTeamInfo.division} @@ -212,7 +248,7 @@ const CheatInfoItem: FC = (props) => { )} - {dayjs(cheatTeamInfo.lastSubmitTime).locale(locale).format('SL LTS')} + {FormatCheatTime(cheatTeamInfo.lastSubmitTime, locale, 'SL LTS')} @@ -242,7 +278,7 @@ const CheatInfoItem: FC = (props) => { {[...cheatTeamInfo.submissionInfo] .sort((a, b) => (b.time?.unix() ?? 0) - (a.time?.unix() ?? 0)) .map((submissionInfo) => ( - + ))} @@ -297,63 +333,17 @@ interface CheatInfoTableViewProps { } const CheatInfoTableView: FC = (props) => { - const { classes: inputClasses } = useDisplayInputStyles({ ff: 'monospace' }) - const { t } = useTranslation() - const { locale } = useLanguage() - const rows = props.cheatInfo .sort((a, b) => (dayjs(b.submission?.time).unix() ?? 0) - (dayjs(a.submission?.time).unix() ?? 0)) - .map((item, i) => ( - - - - {dayjs(item.submission?.time).locale(locale).format('SL HH:mm:ss')} - - - - - {item.ownedTeam?.team?.name ?? 'Team'} - - - - - {`>>>`} - - - - - {item.submitTeam?.team?.name ?? 'Team'} - - - - - {item.submission?.user ?? 'User'} - - - {item.submission?.challenge ?? 'Challenge'} - - - - - )) + .map((item) => { + const submissionInfo = ToCheatSubmissionInfo(item) + return + }) return ( - - - - {t('common.label.time')} - {t('game.label.cheat_info.owned_team')} - - {t('game.label.cheat_info.submit_team')} - {t('game.label.cheat_info.submit_user')} - {t('common.label.challenge')} - {t('common.label.flag')} - - - {rows} -
+ {rows}
)