Skip to content

Commit

Permalink
fix: use Api.ts to download sheets
Browse files Browse the repository at this point in the history
  • Loading branch information
chenjunyu19 committed Feb 22, 2024
1 parent 88ffd00 commit 39e517f
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 6 deletions.
22 changes: 20 additions & 2 deletions src/GZCTF/ClientApp/src/components/WithGameMonitor.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import { Button, Group, LoadingOverlay, Stack, Tabs, useMantineTheme } from '@mantine/core'
import { showNotification } from '@mantine/notifications'
import {
mdiClose,
mdiExclamationThick,
mdiFileTableOutline,
mdiFlag,
mdiLightningBolt,
mdiPackageVariant,
} from '@mdi/js'
import { Icon } from '@mdi/react'
import { AxiosError } from 'axios'
import React, { FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useLocation, useNavigate, useParams } from 'react-router-dom'
import WithGameTab from '@Components/WithGameTab'
import WithNavBar from '@Components/WithNavbar'
import WithRole from '@Components/WithRole'
import { Role } from '@Api'
import { handleAxiosBlobError, openAxiosBlobResponse } from '@Utils/blob'
import api, { Role } from '@Api'

interface WithGameMonitorProps extends React.PropsWithChildren {
isLoading?: boolean
Expand Down Expand Up @@ -49,6 +53,20 @@ const WithGameMonitor: FC<WithGameMonitorProps> = ({ children, isLoading }) => {
}
}, [location])

const onDownloadScoreboardSheet = () => {
api.game
.gameScoreboardSheet(numId, { format: 'blob' })
.then(openAxiosBlobResponse)
.catch(async (err: AxiosError) => {
showNotification({
color: 'red',
title: t('game.notification.fetch_failed.sheet'),
message: await handleAxiosBlobError(err),
icon: <Icon path={mdiClose} size={1} />,
})
})
}

return (
<WithNavBar width="90%">
<WithRole requiredRole={Role.Monitor}>
Expand All @@ -59,7 +77,7 @@ const WithGameMonitor: FC<WithGameMonitorProps> = ({ children, isLoading }) => {
w="9rem"
styles={{ inner: { justifyContent: 'space-between' } }}
leftIcon={<Icon path={mdiFileTableOutline} size={1} />}
onClick={() => window.open(`/api/game/${numId}/scoreboardsheet`, '_blank')}
onClick={onDownloadScoreboardSheet}
>
{t('game.button.download.scoreboard')}
</Button>
Expand Down
21 changes: 17 additions & 4 deletions src/GZCTF/ClientApp/src/pages/games/[id]/monitor/Submissions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ import {
} from '@mdi/js'
import { Icon } from '@mdi/react'
import * as signalR from '@microsoft/signalr'
import { AxiosError } from 'axios'
import dayjs from 'dayjs'
import { FC, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
import WithGameMonitorTab from '@Components/WithGameMonitor'
import { useTableStyles, useTooltipStyles } from '@Utils/ThemeOverride'
import { handleAxiosBlobError, openAxiosBlobResponse } from '@Utils/blob'
import { useGame } from '@Utils/useGame'
import api, { AnswerResult, Submission } from '@Api'

Expand Down Expand Up @@ -206,6 +208,20 @@ const Submissions: FC = () => {
)
)

const onDownloadSubmissionSheet = () => {
api.game
.gameSubmissionSheet(numId, { format: 'blob' })
.then(openAxiosBlobResponse)
.catch(async (err: AxiosError) => {
showNotification({
color: 'red',
title: t('game.notification.fetch_failed.sheet'),
message: await handleAxiosBlobError(err),
icon: <Icon path={mdiClose} size={1} />,
})
})
}

return (
<WithGameMonitorTab>
<Group position="apart" w="100%">
Expand Down Expand Up @@ -240,10 +256,7 @@ const Submissions: FC = () => {
position="left"
classNames={tooltipClasses}
>
<ActionIcon
size="lg"
onClick={() => window.open(`/api/game/${numId}/submissionsheet`, '_blank')}
>
<ActionIcon size="lg" onClick={onDownloadSubmissionSheet}>
<Icon path={mdiDownload} size={1} />
</ActionIcon>
</Tooltip>
Expand Down
35 changes: 35 additions & 0 deletions src/GZCTF/ClientApp/src/utils/blob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { AxiosError, AxiosResponse } from 'axios'
import { ContentType } from '@Api'

type WindowOpenParameters =
Parameters<typeof window.open> extends [any?, ...infer Rest] ? Rest : never

export const openBlob = (blob: Blob, ...rest: WindowOpenParameters) => {
let blobURL = window.URL.createObjectURL(blob)
window.open(blobURL, ...rest)
window.URL.revokeObjectURL(blobURL)
}

export const openAxiosBlobResponse = (res: AxiosResponse) => {
if (res.data instanceof Blob) {
openBlob(res.data, '_blank')
} else {
throw new Error('Response data is not a Blob')
}
}

export const handleAxiosBlobError = async (err: AxiosError) => {
if (err.response?.data instanceof Blob) {
const data = err.response.data
switch (data.type) {
case ContentType.Text:
return await data.text()
case ContentType.Json:
const res = JSON.parse(await data.text())
if (res.title) {
return res.title
}
}
}
return err.message
}

0 comments on commit 39e517f

Please sign in to comment.